リポジトリ

フォルダ構成・gitignore・tasks/・インフラ。

リポ構成・tasks/・gitignore の置き場を揃える。

やること

  1. ディレクトリ を確認
  2. tasks/ を置く

完了: チームでパスが合意されている

リポジトリ構成・.gitignore・ローカル開発・AWS 想定インフラの参考。11.1–11.2 を先に読み、詳細は折りたたみ内。

内容リンク
11.1ディレクトリ構成
11.2.gitignore
11.3ローカル開発 (Docker)詳細
11.4S3 / MinIO詳細
11.5CI/CD (AWS想定)詳細
11.6docs/ と z_docs/詳細
11.7ADR詳細
11.8RAG詳細
11.9OpenAI API 組み込み詳細
11.10Prompt Cache Pre-warming詳細

ディレクトリ構成 (実業務向け)

project/
├── AGENTS.md
├── CLAUDE.md
├── README.md
├── .gitignore
├── .editorconfig
├── .claude/
│   ├── skills/
│   │   └── phase4-domain-tdd/
│   │       └── SKILL.md
│   ├── agents/                     # 任意: 複雑調査を定型化する場合
│   └── settings.json               # 任意: Hooks を使う場合
├── .cursor/
│   └── rules/
│       ├── 00-project.mdc
│       ├── 10-domain-rules.mdc
│       ├── 20-coding-style.mdc
│       ├── 30-testing.mdc
│       ├── 40-logging.mdc
│       ├── 50-documentation.mdc
│       ├── 60-ai-workflow.mdc
│       ├── 61-tdd-loop.mdc
│       └── 70-local-env.mdc       # Docker前提の運用ルール
├── docs/                          # チーム公式ドキュメント (詳細: 11.6)
│   ├── README.md                  # ドキュメント索引
│   ├── architecture.md            # 全体アーキテクチャ (常時更新)
│   ├── glossary.md                # 用語集
│   ├── setup.md                   # セットアップ手順
│   ├── adr/                       # ADR (詳細: 11.7)
│   │   ├── README.md              # ADR索引
│   │   ├── template.md            # ADR雛形
│   │   ├── 0001-use-postgres.md
│   │   ├── 0002-adopt-fastapi.md
│   │   └── ...
│   ├── operations/                # 運用手順・ランブック
│   │   ├── deployment.md
│   │   └── incident-response.md
│   └── <feature-A>/               # 機能単位の公式ドキュメント
│       ├── README.md              # 機能ドキュメント索引
│       ├── 01_requirements.md
│       ├── 02_design.md
│       ├── 03_db_schema.md
│       ├── 04_tech_decisions.md
│       ├── 05_test_plan.md
│       ├── 06_logging.md
│       └── 07_deployment.md
├── tasks/                         # Plan・振り返り(詳細: 11.6 / flow-18)
│   ├── todo.md                    # チェック可能な Plan・進捗・結果
│   └── lessons.md                 # 指摘・修正パターンの蓄積
├── z_docs/                        # 任意: 個人メモを置く場合のみ (詳細: 11.6)
│   ├── <feature-A>/
│   │   ├── 00_plan.md             # 任意: 個人用のタスク分解メモ
│   │   └── history/
│   │       └── yymmdd-hhMM-summary.md  # 任意: 個人用の作業ログ
│   ├── scratch/                   # 試行錯誤・調査メモ
│   └── notes/                     # 個人メモ
├── src/
│   ├── domain/
│   ├── application/
│   ├── infrastructure/
│   └── interface/
├── tests/
│   ├── unit/
│   ├── integration/
│   └── e2e/
├── migrations/
├── docker/
│   ├── app/
│   │   ├── Dockerfile         # 本番用 (マルチステージ)
│   │   └── Dockerfile.dev     # 開発用 (hot-reload等)
│   └── db/
│       └── init.sql           # DB初期化スクリプト
├── docker-compose.yml           # 開発環境定義 (app + db + redis + minio)
├── docker-compose.override.yml.example  # 個人カスタマイズ雛形
├── Makefile                     # コマンド集約
├── .aws/
│   └── task-definition.json   # ECS Task Definition (デプロイで使用)
├── .github/
│   └── workflows/
│       ├── ci.yml             # PR/push時のテスト・lint
│       └── deploy.yml         # mainマージ時のECSデプロイ
├── .env.example
└── pyproject.toml (or go.mod / package.json)

.gitignore

方針

  • コミットすべき: .cursor/rules/ / AGENTS.md / CLAUDE.md / 共有 .claude/skills/ / .agents/skills/ / .codex/config.toml* / .env.example / Docker 関連 / Makefile
  • コミットしない: .env 実体 / シークレット / キャッシュ / ビルド成果物 / 個人 IDE 設定
  • テンプレは github/gitignore を組み合わせる

.gitignore として

# === OS ===
.DS_Store
Thumbs.db
*.swp
*~

# === エディタ / IDE ===
.vscode/*
!.vscode/settings.json      # チーム共有設定だけはコミット (任意)
!.vscode/extensions.json
.idea/
*.iml
.fleet/
.zed/

# === Cursor / Claude Code / Codex ===
# .cursor/rules/ / AGENTS.md / CLAUDE.md / 共有する .claude/* / .agents/skills/ はコミット対象
.cursor/*
!.cursor/rules/
# Claude Code の共有設定だけ復活
.claude/*
!.claude/skills/
!.claude/agents/
!.claude/settings.json
# Codex: プロジェクト設定と共有 Skill(.codex/ は trusted 時のみ読込)
.codex/*
!.codex/config.toml
!.agents/
!.agents/skills/
# AI 関連の他ツールのローカル
.specstory/
.aider*

# === 環境変数 / シークレット (絶対コミットしない) ===
.env
.env.local
.env.*.local
.env.development
.env.production
# テンプレート類はコミット
!.env.example
!.env.sample
# クラウド credentials
*.pem
*.key
*.p12
*.pfx
credentials.json
service-account*.json
.aws/
.gcloud/

# === ログ・実行成果物 ===
*.log
logs/
tmp/
*.pid
*.seed

# === カバレッジ・キャッシュ ===
.coverage
.coverage.*
htmlcov/
coverage.xml
coverage/
.nyc_output/
.pytest_cache/
.mypy_cache/
.ruff_cache/
.tox/
.cache/

# === Docker (ローカルマウント先) ===
.docker-data/
postgres-data/
mysql-data/
redis-data/
# 個人カスタマイズ用 override は gitignore (雛形は .example で配布)
docker-compose.override.yml

# === 一時 / 個人作業 ===
.scratch/
.notes/
*.bak

言語別追加分

Python

__pycache__/
*.py[cod]
*$py.class
*.egg-info/
.eggs/
build/
dist/
.venv/
venv/
.python-version
.ipynb_checkpoints/

Node.js / Next.js

node_modules/
.next/
out/
.turbo/
.nuxt/
dist/
build/
.parcel-cache/
.pnpm-store/
.yarn/cache
.yarn/install-state.gz
*.tsbuildinfo

Go

# vendor/ をコミットするかは方針次第 (CI のオフライン化を重視するなら commit)
# vendor/
bin/
*.exe
*.test
*.out
coverage.out

NOTE: !(再含有)は親ディレクトリ自体が無視されていない場合のみ有効。.cursor/* + !.cursor/rules/ は機能する。.cursor/.claude/ をディレクトリごと無視すると ! が効かない。

11.3〜11.10 インフラ・docs・ADR・RAG 詳細(クリックで展開)

ローカル開発環境 (Docker前提)

主旨

  • 全開発者で環境を揃える: 「自分のPCでは動く」を排除
  • ホストOSを汚さない: 言語ランタイム・DBをホストにインストールしない
  • オンボーディング高速化: git clonemake up → 動く、を目標に
  • AIエージェントへの指示統一: 実行コマンドは常に docker compose exec 経由で提示させる

ファイル構成と役割

ファイル 役割 コミット
docker/app/Dockerfile 本番用イメージ (マルチステージ、最小化) する
docker/app/Dockerfile.dev 開発用イメージ (hot-reload、デバッガ、ツール込み) する
docker-compose.yml 開発環境のサービス構成 (app + db + redis 等) する
docker-compose.override.yml.example 個人カスタマイズの雛形 する
docker-compose.override.yml 個人カスタマイズ実体 (ポート変更等) しない
Makefile コマンド集約 (up/down/test/lint/migrate) する
.env.example 環境変数テンプレート する
.env 環境変数実体 しない

docker-compose.yml 雛形 (Python/FastAPI例)

services:
  app:
    build:
      context: .
      dockerfile: docker/app/Dockerfile.dev
    volumes:
      - .:/workspace:cached
      - python-cache:/root/.cache
    working_dir: /workspace
    env_file: .env
    ports:
      - "8000:8000"
    depends_on:
      db:
        condition: service_healthy
    command: uvicorn src.interface.main:app --reload --host 0.0.0.0

  db:
    image: postgres:16-alpine
    environment:
      POSTGRES_DB: app_dev
      POSTGRES_USER: app
      POSTGRES_PASSWORD: app
    volumes:
      - postgres-data:/var/lib/postgresql/data
      - ./docker/db/init.sql:/docker-entrypoint-initdb.d/init.sql:ro
    ports:
      - "5432:5432"
    healthcheck:
      test: ["CMD", "pg_isready", "-U", "app"]
      interval: 5s
      timeout: 5s
      retries: 5

  redis:
    image: redis:7-alpine
    ports:
      - "6379:6379"
    healthcheck:
      test: ["CMD", "redis-cli", "ping"]
      interval: 5s

volumes:
  postgres-data:
  python-cache:

Makefile 雛形

.PHONY: help up down restart logs sh test lint fmt migrate migrate-rollback shell-db clean

help:
    @grep -E '^[a-zA-Z_-]+:.*?## ' $(MAKEFILE_LIST) | awk 'BEGIN {FS=":.*?## "}; {printf "  %-20s %s
", $$1, $$2}'

up:           ## 開発環境起動
    docker compose up -d

down:         ## 開発環境停止
    docker compose down

restart:      ## 再起動
    docker compose restart app

logs:         ## アプリログ追尾
    docker compose logs -f app

sh:           ## アプリコンテナに入る
    docker compose exec app bash

test:         ## テスト実行
    docker compose exec app pytest -v --cov=src

lint:         ## Lint
    docker compose exec app ruff check . && docker compose exec app mypy src

fmt:          ## Format
    docker compose exec app ruff format .

migrate:      ## DBマイグレーション (forward)
    docker compose exec app alembic upgrade head

migrate-rollback: ## DBマイグレーション (rollback 1段)
    docker compose exec app alembic downgrade -1

shell-db:     ## DBに接続
    docker compose exec db psql -U app -d app_dev

clean:        ## ボリュームごと削除 (注意)
    docker compose down -v

言語が Go なら make testdocker compose exec app go test ./... に、Next.js なら docker compose exec app pnpm test に置換する。

.cursor/rules/70-local-env.mdc (Docker前提を強制)

---
description: ローカル開発環境はDocker前提。コマンド提示時はコンテナ経由を必須とする。
alwaysApply: true
---

# ローカル開発環境ルール

## 原則
- ホストOSに言語ランタイム・DB・キャッシュを直接インストールしない
- 全ての開発コマンドはコンテナ内で実行する
- 接頭辞: `docker compose exec <service> <command>`
- 例外: `git` `docker` `make` 自体はホスト側で実行

## AIエージェントへの指示
実行系コマンドを提案する際は、必ず以下の形式で提示すること:

- 悪い例: `pip install httpx`
- 良い例: `docker compose exec app pip install httpx` (一時的) または
  Dockerfile.dev / pyproject.toml に追加し `docker compose build app` (恒久)

- 悪い例: `pytest tests/`
- 良い例: `make test` または `docker compose exec app pytest tests/`

- 悪い例: `psql -U app app_dev`
- 良い例: `make shell-db` または `docker compose exec db psql -U app -d app_dev`

## 新規依存追加時のフロー
1. パッケージマネージャ定義ファイル (pyproject.toml / package.json / go.mod) に追記
2. `docker compose build app` でイメージ再ビルド
3. `docker compose up -d` で再起動
4. 既存コンテナで一時的に試したい場合のみ `docker compose exec app <install>`

## 環境変数
- `.env.example` を雛形として配布
- 各開発者は `.env` を作成 (gitignore対象)
- 新規環境変数を追加した場合は `.env.example` も同時更新 + PR本文で言及

## IDE統合
- IDE実行 (Cursor/VS Code) は Dev Containers 経由を推奨
- ホスト側のフォーマッタ/lintはCIで担保される前提なら使用可
- ただしテスト・ビルド・マイグレーションは必ずコンテナ内で実行

README.md に書くべき起動手順 (3行ルール)

## 起動方法

```bash
cp .env.example .env       # 必要なら値を編集
make up                     # アプリ + DB + Redis を起動
make migrate                # 初回のみ
```

API: http://localhost:8000 (健康確認: /healthz)

詳細は make help を参照。

NOTE: 「3行で動く」を維持するため、初期化処理 (シードデータ等) は make up 後に1コマンドで完結させる。複雑になるなら make seed を別途用意する。

ホスト CLI — エージェントと自分の時短定番

エージェントはシェル経由で PR 作成・デプロイ・ログ確認を試みる。CLI 未インストール / 未ログインだと認証プロンプトで止まり、人間の手戻りが増える。利用中のクラウドサービス CLI はホストに入れ、認証済みの状態を Day1 目標にする。

ホスト vs コンテナ: ホストで ghvercelawsdocker composesupabase。アプリ実行・テストは 11.3 Docker どおり docker compose exec 経由(例: MinIO の mc はコンテナ内)。

早見表

CLI 主用途 インストール(macOS 例) 認証・動作確認 エージェントがよく使う例
gh PR / Issue / CI 状況 brew install gh gh auth status gh pr checks · gh run view
vercel preview deploy · env pull npm i -g vercel vercel whoami vercel link · vercel env pull .env.local
aws ECS / ECR / S3 / ログ brew install awscli aws sts get-caller-identity aws logs tail · aws ecr describe-repositories
supabase ローカル DB · migration brew install supabase/tap/supabase supabase projects list supabase start · supabase db push
docker compose 起動 Docker Desktop docker compose version docker compose up -d · docker compose exec app …

危険操作の扱い

vercel deploy --prod や本番 aws 変更は、エージェントが勝手に実行しないよう 強制確認ルール完了前の検証 を rules に書く。

GitHub CLI (gh)

  1. インストールと確認
    brew install gh
    gh --version
  2. ログイン — ブラウザまたはトークン。gh auth login 後に gh auth statusLogged in を確認する。
  3. リポジトリ紐付け — 作業ディレクトリで gh repo set-default(または gh repo view で remote 確認)。
  4. エージェントの初手 — PR 調査: gh pr checks → 失敗 run: gh run view RUN_ID --log-failed
  5. つまずき — SSO 組織は gh auth login --hostname github.com --web を再実行。トークン scope 不足は repo / read:org を付与。

Vercel CLI

  1. インストールと確認
    npm install -g vercel
    vercel --version
  2. ログインvercel login(ブラウザ)→ vercel whoami
  3. プロジェクト紐付け — 初回 vercel link。環境変数は vercel env pull .env.local.env.local は gitignore)。
  4. エージェントの初手 — preview: vercel(対話)または CI 経由。ローカル確認前に vercel env pull で不足キーを潰す。
  5. つまずき — 複数 team/scope があるときは vercel switch。本番 deploy は要確認(上記「危険操作」)。

AWS CLI

  1. インストールと確認
    brew install awscli
    aws --version
  2. 認証(SSO 推奨)
    aws configure sso --profile myapp-dev
    aws sso login --profile myapp-dev
    export AWS_PROFILE=myapp-dev
    aws sts get-caller-identity

    開発のみ IAM ユーザーの場合は aws configure --profile myapp-dev。本番 CI は OIDC(11.5 CI/CD)を正本とする。

  3. プロファイル確認aws configure list-profiles。複数アカウントでは AWS_PROFILE を rules に明記する。
  4. エージェントの初手 — ログ: aws logs tail /ecs/myapp --follow。イメージ: aws ecr describe-repositories
  5. つまずき — SSO セッションは数時間で切れる。aws sso login を再実行。region 未設定は AWS_DEFAULT_REGION=ap-northeast-1 等を profile に固定。

Supabase CLI(短文)

  • brew install supabase/tap/supabasesupabase loginsupabase projects list
  • ローカル: supabase initsupabase start(Docker 必須。詳細は 11.3
  • マイグレーション: supabase db push / supabase migration new

Docker / Compose(短文)

  • ホストに Docker Desktop(または Linux engine)を入れ、docker compose version が通る状態にする
  • アプリ・DB・テストは 11.3 ローカル開発make up / docker compose exec を正本とする
  • エージェントへの指示は「ホストで compose 起動、実行は exec 経由」と rules で固定する

ストレージ: 本番 S3 / ローカル MinIO (AWS想定)

方針

  • 本番: Amazon S3 (高可用性・低コスト・IAMで権限管理)
  • ローカル: MinIO (S3互換APIをDockerコンテナで提供。オフライン可能・無料)
  • コード側: 環境変数で接続先だけ切り替える。AWS SDK (boto3 / aws-sdk-go / @aws-sdk/client-s3) は両方で同じものを使う

docker-compose.yml への追加

services:
  # ... 既存の app / db / redis ...

  minio:
    image: minio/minio:latest
    ports:
      - "9000:9000"   # S3 API
      - "9001:9001"   # Web Console
    environment:
      MINIO_ROOT_USER: minioadmin
      MINIO_ROOT_PASSWORD: minioadmin
    volumes:
      - minio-data:/data
    command: server /data --console-address ":9001"
    healthcheck:
      test: ["CMD", "mc", "ready", "local"]
      interval: 10s
      timeout: 5s
      retries: 3

  # 初期バケット作成 (起動時に1回だけ実行)
  minio-setup:
    image: minio/mc:latest
    depends_on:
      minio:
        condition: service_healthy
    entrypoint: >
      /bin/sh -c "
      mc alias set local http://minio:9000 minioadmin minioadmin &&
      mc mb -p local/app-uploads &&
      mc mb -p local/app-backups
      "

volumes:
  minio-data:

.env.example

# === AWS共通 ===
AWS_REGION=ap-northeast-1

# === S3 バケット名 (本番/ローカル共通でコード側から参照) ===
S3_BUCKET_UPLOADS=app-uploads
S3_BUCKET_BACKUPS=app-backups

# === ローカル (MinIO) 用 ===
# 本番では未設定にする (IAMロール認証に切り替わる)
AWS_ENDPOINT_URL=http://minio:9000
AWS_ACCESS_KEY_ID=minioadmin
AWS_SECRET_ACCESS_KEY=minioadmin
AWS_S3_USE_PATH_STYLE=true

コード側の切り替え例 (Python / boto3)

import os
import boto3
from botocore.config import Config


def make_s3_client():
    kwargs: dict = {"region_name": os.environ["AWS_REGION"]}

    if endpoint := os.environ.get("AWS_ENDPOINT_URL"):
        # ローカル開発 (MinIO): エンドポイントとアクセスキーを明示
        kwargs["endpoint_url"] = endpoint
        kwargs["aws_access_key_id"] = os.environ["AWS_ACCESS_KEY_ID"]
        kwargs["aws_secret_access_key"] = os.environ["AWS_SECRET_ACCESS_KEY"]
        kwargs["config"] = Config(s3={"addressing_style": "path"})
    # 本番: 何も指定しないと IAM Role (Task Role / IRSA) で自動認証

    return boto3.client("s3", **kwargs)

NOTE: 本番で AWS_ACCESS_KEY_ID / SECRET_ACCESS_KEY を環境変数で渡すのはアンチパターン。ECS Task Role / EKS IRSA を使えば SDK が自動で credential を取得する。長期credentialを発行しないことがセキュリティの基本。

MinIO の運用メモ

  • コンソール: http://localhost:9001 (admin: minioadmin / minioadmin)
  • バケット操作・オブジェクト閲覧・IAMユーザ管理がGUIで可能
  • mc (MinIO Client) でCLI操作: docker compose exec minio-setup mc ls local/app-uploads
  • ARM Mac でも linux/arm64 イメージが公式提供されている

CI/CD: AWS想定 (仮)

全体像

flowchart LR Dev[Developer] -->|push| GH[GitHub] GH -->|trigger| GHA[GitHub Actions] GHA -->|OIDC AssumeRole| IAM[AWS IAM Role] GHA -->|build push| ECR[Amazon ECR] GHA -->|update service| ECS[ECS Fargate] ECS -->|read| SM[Secrets Manager] ECS -->|read write| S3[Amazon S3] ECS -->|stdout| CWL[CloudWatch Logs] ECS -->|connect| RDS[Amazon RDS] ECS -->|connect| EC[ElastiCache Redis]

サービス選定 (仮想定)

役割 サービス 備考
ソース管理 GitHub AWS CodeCommitは実務でほぼ使わない
CI (テスト/lint) GitHub Actions 無料枠あり、エコシステム豊富
CD (ビルド/デプロイ) GitHub Actions + AWS CLI CodePipeline/CodeBuildは選定しない
イメージレジストリ Amazon ECR プライベートで安全
実行環境 Amazon ECS (Fargate) サーバレス、運用負荷低
シークレット管理 AWS Secrets Manager / SSM Parameter Store 機密度で使い分け
ログ集約 CloudWatch Logs Datadog連携も可
監視・アラート CloudWatch Alarms (+ Datadog 任意)
ストレージ Amazon S3 (本番) / MinIO (ローカル) (11.4)
RDB Amazon RDS (PostgreSQL/MySQL) / Aurora
キャッシュ ElastiCache (Redis)
ロードバランサ ALB HTTPSはACMで証明書管理
CDN CloudFront 静的アセット高速化
Infra as Code Terraform / AWS CDK Terraformが事実上の標準

.github/workflows/ci.yml (テスト/Lint、PR・push時)

name: CI

on:
  pull_request:
    branches: [main, develop]
  push:
    branches: [main, develop]

permissions:
  contents: read
  id-token: write   # OIDC用

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v3

      - name: Build dev image
        run: docker compose build app

      - name: Lint
        run: docker compose run --rm app ruff check .

      - name: Type check
        run: docker compose run --rm app mypy src

      - name: Test
        run: docker compose run --rm app pytest -v --cov=src --cov-report=xml

      - name: Upload coverage
        if: always()
        uses: actions/upload-artifact@v4
        with:
          name: coverage
          path: coverage.xml

CI もローカルと同じ Docker環境で実行する。「ローカルで通ったらCIでも通る」を担保する基本戦術。

.github/workflows/deploy.yml (main マージ時)

name: Deploy to ECS

on:
  push:
    branches: [main]

permissions:
  contents: read
  id-token: write

env:
  AWS_REGION: ap-northeast-1
  ECR_REPOSITORY: app
  ECS_CLUSTER: app-cluster
  ECS_SERVICE: app-service
  CONTAINER_NAME: app

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Configure AWS credentials (OIDC)
        uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: arn:aws:iam::123456789012:role/GitHubActionsDeployRole
          aws-region: ${{ env.AWS_REGION }}

      - name: Login to ECR
        id: ecr
        uses: aws-actions/amazon-ecr-login@v2

      - name: Build and push image
        run: |
          IMAGE="${{ steps.ecr.outputs.registry }}/${{ env.ECR_REPOSITORY }}:${{ github.sha }}"
          docker build -f docker/app/Dockerfile -t $IMAGE .
          docker push $IMAGE
          echo "IMAGE=$IMAGE" >> $GITHUB_ENV

      - name: Render new task definition
        id: taskdef
        uses: aws-actions/amazon-ecs-render-task-definition@v1
        with:
          task-definition: .aws/task-definition.json
          container-name: ${{ env.CONTAINER_NAME }}
          image: ${{ env.IMAGE }}

      - name: Deploy to ECS
        uses: aws-actions/amazon-ecs-deploy-task-definition@v1
        with:
          task-definition: ${{ steps.taskdef.outputs.task-definition }}
          service: ${{ env.ECS_SERVICE }}
          cluster: ${{ env.ECS_CLUSTER }}
          wait-for-service-stability: true

OIDC認証 (重要)

長期アクセスキーをGitHub Secretsに保存しない。代わりに OIDC でその場限りの認証情報を発行する。

セットアップ手順:

  1. AWS IAM で OIDC Identity Provider を追加 (token.actions.githubusercontent.com)
  2. GitHubリポジトリ・ブランチ限定の IAM Role を作成
  3. Role の信頼ポリシーで Repository / Branch を絞る (他リポジトリから乗っ取られないため)
  4. GitHub Actions 側で aws-actions/configure-aws-credentials@v4 でRole Assume

信頼ポリシー例 (mainブランチのみ許可):

{
  "Version": "2012-10-17",
  "Statement": [{
    "Effect": "Allow",
    "Principal": {
      "Federated": "arn:aws:iam::123456789012:oidc-provider/token.actions.githubusercontent.com"
    },
    "Action": "sts:AssumeRoleWithWebIdentity",
    "Condition": {
      "StringEquals": {
        "token.actions.githubusercontent.com:aud": "sts.amazonaws.com"
      },
      "StringLike": {
        "token.actions.githubusercontent.com:sub": "repo:my-org/my-repo:ref:refs/heads/main"
      }
    }
  }]
}

ECS Task Definition の要点 (.aws/task-definition.json 抜粋)

{
  "family": "app",
  "executionRoleArn": "arn:aws:iam::123456789012:role/ecsTaskExecutionRole",
  "taskRoleArn": "arn:aws:iam::123456789012:role/AppTaskRole",
  "networkMode": "awsvpc",
  "requiresCompatibilities": ["FARGATE"],
  "cpu": "512",
  "memory": "1024",
  "containerDefinitions": [
    {
      "name": "app",
      "image": "PLACEHOLDER",
      "essential": true,
      "portMappings": [{"containerPort": 8000, "protocol": "tcp"}],
      "environment": [
        {"name": "AWS_REGION", "value": "ap-northeast-1"},
        {"name": "S3_BUCKET_UPLOADS", "value": "app-prod-uploads"}
      ],
      "secrets": [
        {
          "name": "DATABASE_URL",
          "valueFrom": "arn:aws:secretsmanager:ap-northeast-1:123456789012:secret:app/db-url"
        }
      ],
      "logConfiguration": {
        "logDriver": "awslogs",
        "options": {
          "awslogs-group": "/ecs/app",
          "awslogs-region": "ap-northeast-1",
          "awslogs-stream-prefix": "app",
          "awslogs-create-group": "true"
        }
      },
      "healthCheck": {
        "command": ["CMD-SHELL", "curl -f http://localhost:8000/healthz || exit 1"],
        "interval": 30,
        "timeout": 5,
        "retries": 3,
        "startPeriod": 10
      }
    }
  ]
}

IAM Role 最小権限例 (アプリ用 = taskRoleArn)

S3アクセスのみ必要なケース:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": ["s3:GetObject", "s3:PutObject", "s3:DeleteObject"],
      "Resource": [
        "arn:aws:s3:::app-prod-uploads/*",
        "arn:aws:s3:::app-prod-backups/*"
      ]
    },
    {
      "Effect": "Allow",
      "Action": ["s3:ListBucket"],
      "Resource": [
        "arn:aws:s3:::app-prod-uploads",
        "arn:aws:s3:::app-prod-backups"
      ]
    }
  ]
}

Resource: "*" 禁止。バケット単位で絞る。

環境ごとの構成

環境 用途 ストレージ デプロイ条件
local 開発者ローカル MinIO (Docker) 手動 (make up)
dev 共通開発環境 (AWS) S3 (dev用バケット) develop push 時 自動
staging 本番相当の検証 S3 (staging用) リリースタグ作成時
production 本番 S3 (prod用) 手動承認後の deploy ワークフロー

デプロイ戦略

  • Rolling Update (デフォルト): ECS の Deployment 機能を使う
  • Blue/Green: CodeDeploy統合 (大規模変更時)
  • Canary: 機能フラグ (Feature Flag) と組み合わせる
  • Rollback: aws ecs update-service で前バージョンのtask definitionに戻す
  • 緊急停止: Desired Count を 0 にする / 機能フラグでOFF

ローカル ⇔ CI ⇔ 本番の認証差分まとめ

環境 認証方式 設定場所
ローカル (MinIO) 固定アクセスキー .env (gitignore)
CI (GitHub Actions) OIDC → IAM Role Assume ワークフローYAML
本番 (ECS Fargate) Task Role (IRSA相当) Task Definition

コスト・運用の注意点

  • ECR: lifecycle policy で古いイメージを自動削除 (デフォルトのままだと無限に溜まる)
  • CloudWatch Logs: 保持期間を明示 (デフォルトは無期限でコスト高)
  • S3: ライフサイクルで Glacier 移行 / 古いオブジェクト自動削除
  • Secrets Manager: $0.40/secret/月 (記憶ベース、要最新確認)。機密度低いものは Parameter Store (無料枠あり) で代替
  • NAT Gateway: 意外と高い。VPC設計で privatelink / VPC endpoint も検討

.cursor/rules/ への追補

70-local-env.mdc に AWS 周りを追補:

## ストレージ
- ローカル: MinIO コンテナ経由 (環境変数 AWS_ENDPOINT_URL で切替)
- 本番: S3 + IAM Task Role
- アプリコードで AWS_ACCESS_KEY_ID を本番にハードコードしない
- S3 アクセスは boto3 / aws-sdk のデフォルト credential chain に任せる

## CI/CD
- GitHub Actions の認証は OIDC のみ。長期アクセスキー禁止
- IAM Role 信頼ポリシーは リポジトリ・ブランチで絞る
- 新規 AWS リソースは Terraform / CDK でコード化、手動作成禁止

NOTE: AWS のサービス名・料金・API仕様は時々変わる。実プロジェクトで採用する際は AWS公式ドキュメント・料金ページで最新を確認すること。本セクションは2026年初頭時点の一般的なパターンに基づいた仮想定。

docs/z_docs/(作業履歴)

作業履歴の正本: Obsidian Vault 03_Operations/history/YYYY-MM/yymmdd-hhMM.md(MCP 連携可)。

リポ内 z_docs/history/: ローカル退避・任意(Vault 未接続時)。新規書き込みは Vault を優先。

docs/: チーム公式。新規追加はユーザー明示時のみ(documentation-z-docs.mdc 参照)。

立ち位置の違い

観点 docs/ z_docs/
位置づけチーム公式(既存)作業履歴・個人メモ
新規追加原則禁止(ユーザー明示時のみ)セッションごとに自由
主な読者チーム・新メンバー主に自分
品質バーレビュー必須再現できれば OK
PR 対象はい(既存更新時)原則いいえ
代表的内容要件・設計・ADR・運用作業ログ・調査・下書き

tasks/(Plan・振り返り)

ファイル 書くこと 更新タイミング
tasks/todo.mdチェックリスト、Plan メモ、レビュー・結果タスク着手時・Plan 確定時・完了時(Phase 2
tasks/lessons.mdユーザー指摘・修正パターン・再発防止指摘を受けた直後、セッション開始前に読む(エージェント運用

配置ルール

docs/                              # チーム公式(新規追加はユーザー明示時のみ)
├── README.md                      # docs/ 全体の索引
├── architecture.md                # システム全体アーキ
├── glossary.md                    # 用語集
├── setup.md                       # 開発環境セットアップ
├── adr/                           # ADR(詳細: 11.7)
├── operations/                    # 運用手順
└── <feature>/                     # 機能単位(既存)

tasks/                             # Plan・振り返り(リポジトリ直下・テンプレ同梱)
├── todo.md
└── lessons.md

z_docs/
├── history/                       # 作業履歴(必須)
│   ├── yymmdd-hhMM.md             # セッション単位
│   └── yymmdd-hhMM-{概要}.md      # 概要を明示したい場合
├── <feature>/                     # 任意: 機能別の検討メモ
└── (直下のインデックス・長期メモはプロジェクトの慣習に従う)

判断フロー

flowchart TD A[書こうとしている文書] --> B{セッションの作業ログか} B -->|はい| H[z_docs/history/yymmdd-hhMM.md] B -->|いいえ| C{チームの公式成果物か} C -->|いいえ| Z[z_docs/ の任意の場所] C -->|はい| D{ユーザーから docs 明示の指示があるか} D -->|いいえ| W[まずユーザーに確認] D -->|はい| E{意思決定の根拠か} E -->|はい| F[docs/adr/] E -->|いいえ| G[docs/<feature>/]

運用のコツ

  • 履歴の正本は Obsidian 03_Operations/history/YYYY-MM/。ファイル名 yymmdd-hhMM.md(概要付きは yymmdd-hhMM-{概要}.md)。リポ内 z_docs/history/ は任意のローカル退避
  • docs/ への新規追加はユーザー明示時のみ: 既存 docs/ の修正・更新は通常のフローでよい。削除や移行はユーザー依頼時のみ
  • 個人グローバルルール(~/.cursor/rules/documentation-z-docs.mdc)が常時適用される前提
  • MCP(Obsidian): Vault 内 03_Operations/history/ を参照・追記。ボルトとリポ z_docs/ の二重化は任意(正本は Vault)
  • 長期メモ・索引: z_docs/ 直下に置くかはプロジェクトの慣習またはユーザーの明示に従う

.gitignore での扱い(11.2 への追補)

  • docs/ はコミット対象(チーム共有の正式な記録)
  • z_docs/ はプロジェクトの慣習に従う: ローカル限定にするなら .gitignore へ。チームで履歴を共有するならコミット対象でもよい
# 例: 個人メモをローカル限定にする場合
z_docs/
# 例: 履歴だけ共有したい場合
# z_docs/*
# !z_docs/history/

ADR (Architecture Decision Records)

ADR とは

Michael Nygard 提唱のフォーマットが事実上の標準。

用語集の ADR / Architecture Decision Records も参照。

なぜ書くか

  • 「なぜそうしたか」が忘れられない: 3ヶ月後の自分や新メンバーが「なぜRedisじゃなくてDynamoDB?」を追える
  • 同じ議論の再発を防ぐ: 「過去に同じ検討をしてこういう理由で却下した」と参照できる
  • 設計変更時の影響範囲が分かる: 関連ADRを辿ることで決定の連鎖が見える
  • オンボーディングが楽: 新メンバーが ADR を読めば過去の判断が分かる

いつ書くか (判断基準)

書く対象 (例):

  • 新規ライブラリ・フレームワーク採用
  • DB選定・スキーマ設計の大きな変更
  • 認証方式・認可モデルの選定
  • 通信プロトコル選定 (REST / GraphQL / gRPC)
  • アーキテクチャパターン選定 (モノリス / マイクロサービス)
  • インフラ・クラウドサービス選定
  • 重要なライブラリの破壊的アップグレード

書かない対象 (例):

  • 細かい命名規則 (.cursor/rules/20-coding-style.mdc で十分)
  • 個別関数の実装方針 (コードコメントで十分)
  • 一時的な調査 (必要なら z_docs/scratch/ の個人メモで十分)

迷ったら書く。あとから「ADRにすべきだった」より「ADRがあって良かった」のほうが多い。

配置・命名

  • ディレクトリ: docs/adr/
  • ファイル名: NNNN-<slug>.md (NNNN は連番、4桁ゼロ埋め)
  • 例: 0001-use-postgres.md / 0002-adopt-fastapi.md / 0003-replace-celery-with-sqs.md
  • 索引: docs/adr/README.md に一覧 (ステータス・タイトル・リンク)

ADR ステータス

  • Proposed: 提案中、レビュー待ち
  • Accepted: 採用決定、現在の方針
  • Deprecated: 非推奨だが特に置き換えなし
  • Superseded by ADR-NNNN: 別のADRに置き換えられた (古いほうも残す)

重要: ADR は 追記方式。既存ADRを書き換えるのではなく、新しいADRで上書き (Superseded) する。

docs/adr/template.md

# ADR-NNNN: <タイトル>

- Date: YYYY-MM-DD
- Status: Proposed | Accepted | Deprecated | Superseded by ADR-MMMM
- Deciders: [氏名 / チーム]
- Related: [関連ADR, Issue, PR]

## Context (背景)

なぜこの決定が必要なのか。
- 解決したい問題
- 制約 (技術的・組織的・予算的)
- 関係するステークホルダー

## Decision (決定)

何を決めたか。具体的に。
- 採用した選択肢
- 採用した理由 (Context との対応)

## Consequences (結果・影響)

### Positive (良い結果)
- 期待される効果
- 解決される問題

### Negative (悪い結果・トレードオフ)
- 受け入れるコスト
- 新たに発生する課題

### Neutral (中立、副次的な影響)
- 注意点
- 周辺への影響

## Alternatives Considered (検討した他案)

### Option A: <別案>
- 概要
- メリット
- デメリット
- 採用しなかった理由

### Option B: <別案>
- ...

## References (参考資料)

- [公式ドキュメント](URL)
- [比較記事](URL)
- 関連Issue: #123

ADRの書き出しプロンプト

まずドラフトを素早く起こしたいときは ADR生成ツール で Markdown 叩き台を作ってから、この章のテンプレートと照らして調整すると早い。

新規ADRを起票します。

【テーマ】
[例: Redis を使うべきか、別の選択肢があるか]

【現状】
[なぜ検討が必要になったか、関連するコンテキスト]

【作業】
docs/adr/ に新規ADRファイルを作成してください。
- 連番 NNNN は既存ADRの最大値+1
- ファイル名: NNNN-<slug>.md (slug は英小文字+ハイフン)
- フォーマットは docs/adr/template.md に従う
- Status は Proposed として作成 (レビュー後に Accepted に変更する想定)

検討した代替案を最低3つ挙げ、それぞれのメリット・デメリット・採用しなかった理由を書いてください。
私が後で判断するための材料として、推測ではなく検証可能な事実に基づいて書いてください。

ADRに昇格すべきかの判断

docs/<feature>/04_tech_decisions.md に書いた内容のうち、

  • 機能を超えてプロジェクト全体に影響する
  • 後から変更が困難 (DB変更、認証方式変更等)
  • ステークホルダー間の議論があった

ものは ADRに昇格 (新規ADR起票 + 04_tech_decisions.md から docs/adr/NNNN-*.md へリンク)。

docs/adr/README.md の例

# Architecture Decision Records

| ADR | Title | Status | Date |
|---|---|---|---|
| [0001](./0001-use-postgres.md) | Use PostgreSQL as primary DB | Accepted | 2026-04-01 |
| [0002](./0002-adopt-fastapi.md) | Adopt FastAPI for backend | Accepted | 2026-04-05 |
| [0003](./0003-replace-celery-with-sqs.md) | Replace Celery with AWS SQS | Proposed | 2026-05-10 |
| [0004](./0004-tdd-as-team-standard.md) | TDD as team standard | Accepted | 2026-05-12 |

新規ADR起票時はこの表に追記すること。

RAG (Retrieval-Augmented Generation) の導入

RAG とは

  • 基本構成: ソース文書 → chunking → embeddings / index → retrieval → prompt composition → 回答 + 引用
  • 一次情報は docs/docs/adr/、用語集、仕様書を優先する
  • z_docs/history/ などの個人メモを検索対象に入れるなら、「草稿・履歴を含む」ことを明示する

NOTE: RAG を正式運用するなら、.cursor/rules/60-ai-workflow.mdcCLAUDE.md にも「出典を添える」「根拠が取れないときは推測で埋めない」を入れておくとブレにくい。

向いているケース / 向いていないケース

向いているケース:

  • 社内ドキュメント、運用マニュアル、ADR、仕様書、サポートナレッジのように 文書が正式な記録 の知識を引かせたいとき
  • 回答のたびに 出典を添えたい とき
  • モデル再学習ではなく、文書更新で知識を更新したい とき

向いていない、または注意が必要なケース:

  • 元文書の品質が低い、重複が多い、古い版が混ざるなど、検索前の情報整理ができていない状態
  • 更新タイミング、再インデックス条件、失効ルールなどの 鮮度管理 が決まっていない状態
  • 出典を返さずに使う運用。誤答時に根拠追跡ができず、利用者も検証しづらい
  • 本来は DB クエリや外部 API 呼び出しで確定値を返すべき処理。RAG は検索付き要約であり、システム of record の代替ではない

小さく導入する手順

  1. 対象知識を絞る: まずは1領域だけに限定する。例: オンボーディング資料、運用FAQ、1機能分の仕様群
  2. source of truth を整理する: docs/docs/adr/、用語集のどれを正式な記録にするかを決め、重複や古い版を潰す
  3. 更新フローを決める: 誰が更新し、いつ再インデックスし、古い文書をどう失効させるかを決める
  4. 検索粒度とメタデータを決める: chunk の大きさ、見出し単位、文書ID、版、更新日時、章名を揃える
  5. 評価基準を先に決める: 取得精度、引用の正確さ、根拠なし時に回答を控える率、レイテンシを最低限測る
  6. ログとフィードバックを残す: 質問、取得文書、回答、ユーザーフィードバックを保存して改善材料にする
  7. 小さく公開してから広げる: まずは限定ユーザー・限定ユースケースで運用し、定着したら対象文書を増やす。全体方針になるなら ADR 化も検討する

RAG は 検索基盤の話である前に、文書運用の話。このドキュメントの流れに合わせるなら、docs/ / docs/adr/ / 用語集を整えたうえで、AIワークフローに「出典必須」を組み込む順が安全。Naive RAG で足りない場合(多段推論・検索判断・自己修正)は RAG 参考 — Agentic RAG を参照。

生成AI機能 (OpenAI API) の組み込み

先に決めること

  • ユースケース: 要約、抽出、分類、チャット支援、下書き生成など、何をAIに任せるかを先に固定する。確定値を返す処理は通常のDB/APIで解く
  • レイテンシ / コスト / モデル: 対話UIなら応答目標時間、バッチなら件数と上限単価を決め、まずは小さめのモデルから評価する
  • 同期 / 非同期: 画面で待てるなら同期、時間が読みにくい・再実行が必要・件数が多いならジョブ化する
  • 出力形式: 人間向け文章か、JSONなどの機械可読形式かを決める。後者は backend で型・schema を検証する前提で設計する

最小安全構成

典型的な流れは client -> backend -> OpenAI API -> backend -> client。通常は 信頼できないフロントエンドから OpenAI API を直接呼ばない。APIキー露出の問題だけでなく、レート制限、監査ログ、prompt差し替え、レスポンス検証、リトライ/タイムアウト制御をサーバ側に集約できなくなるため。

# .env.example
OPENAI_API_KEY=your-openai-api-key
OPENAI_MODEL=your-openai-model
OPENAI_TIMEOUT_MS=15000
OPENAI_MAX_RETRIES=2
  • 秘密情報: OPENAI_API_KEY はサーバ側だけで読む。ローカルは .env、本番は Secret Manager / CI Secret を使い、.env.example にはダミー値だけ置く
  • 入力境界: client から受ける値は backend で認可・バリデーションし、必要なら個人情報や機密文字列をマスクしてから OpenAI に渡す
  • 出力境界: 返却前に JSON schema / 型 / 禁止語 / 参照ID などを検証し、想定外の出力は fallback か再試行に倒す

運用と段階導入

  • Prompt / version 管理: system prompt、few-shot、出力schema、使用モデルを識別可能にし、変更時はバージョンを上げて追跡できるようにする
  • ログ / redaction: 入出力全文を無制限保存しない。trace_id、model、token使用量、遅延、成功/失敗理由を残し、本文は必要最小限 + redaction 前提にする
  • 保護: レート制限、タイムアウト、指数バックオフ付きリトライを先に入れる。障害時の一時停止条件も決めておく
  • 段階導入: まずは1機能・内部ユーザー限定で開始し、オフライン評価と実運用ログを見ながら公開範囲を広げる。timeoutmalformed outputrate limit の失敗系テストを先に足す
  • docs / ADR / testing との接続: 機能単位では docs/<feature>/04_tech_decisions.md にユースケース、モデル、同期/非同期、出力形式、コスト上限を書く。全体方針になるなら ADR 化し、05_test_plan.md06_logging.md に評価観点と運用ルールを残す

NOTE: 既存プロジェクトでは、まず「LLMを使わない実装」で足りない理由を明文化してから小さく入れる。導入理由、失敗時のfallback、人手確認が必要な境界が曖昧なら先に設計を固める。

プロンプトキャッシュのプリウォーム(Claude API Pre-warming)

公式: Prompt caching — Pre-warming the cache。共有 system / ツール定義を事前キャッシュし、初回対話のキャッシュミス遅延を避ける。

仕組み(max_tokens: 0

  • max_tokens: 0 のリクエストではプレフィルまで実行され、cache_control のブレークポイントでキャッシュが書き込まれたうえで出力は生成されずに即返る。レスポンスは content: []stop_reason: "max_tokens"usage は通常どおり。
  • cache_control は、本番リクエストと共有される末尾ブロック(多くの場合は system やツール定義)に置く。プレースホルダ用の user メッセージ(例: "warmup")にブレークポイントを置くと、キャッシュキーがズレて本番がヒットしない。プリウォームでは明示的な cache breakpoint を使う(自動キャッシュは最終ブロックにブレークポイントが付くため、プレースホルダが最後だと不適切)。プレースホルダの本文は空白以外なら任意で、prefill では読まれるが回答はされない。
  • プレフィックスが未キャッシュなら通常と同様のキャッシュ書き込み課金。確認は usage.cache_creation_input_tokens 等。出力トークンは 0 で課金されない。

運用パターンと TTL

  • アプリ起動時や定期ジョブでプリウォームし、完了後に本番の messages.create を送る。
  • デフォルトの 5 分 TTL では、温め続けるなら少なくとも 5 分ごとにプリウォームを送り直す。ユーザー間隔が長い場合は公式の 1 時間キャッシュ(同一ドキュメント内の別節)を検討。

max_tokens: 0 が拒否される条件(公式どおり)

  • stream: true、Extended thinking(thinking.type: "enabled")、Structured outputs(output_config.format)、tool_choice{"type":"tool",...} または {"type":"any"}
  • Message Batches 内のリクエストでは max_tokens: 0 は拒否される(バッチは TTFT 対象外で、書き込んだキャッシュも追随リクエストまでに失効しやすい、という旨が公式に記載)。

過去の max_tokens: 1 によるウォームアップは、出力が発生しない max_tokens: 0 が推奨とされている(意図が明確で出力トークン課金もない)。

// 共有 system を先にキャッシュ(本番リクエストと同一の system ブロック構成に合わせる)
const prewarm = await client.messages.create({
  model: "claude-opus-4-7",
  max_tokens: 0,
  system: [
    { type: "text", text: SYSTEM_PROMPT_TEXT, cache_control: { type: "ephemeral" } },
  ],
  messages: [{ role: "user", content: "warmup" }],
});
// prewarm.stop_reason === "max_tokens" / prewarm.content は []