リポジトリ
フォルダ構成・gitignore・tasks/・インフラ。
リポ構成・tasks/・gitignore の置き場を揃える。
やること
- ディレクトリ を確認
- tasks/ を置く
完了: チームでパスが合意されている
リポジトリ構成・.gitignore・ローカル開発・AWS 想定インフラの参考。11.1–11.2 を先に読み、詳細は折りたたみ内。
| 節 | 内容 | リンク |
|---|---|---|
| 11.1 | ディレクトリ構成 | ↓ |
| 11.2 | .gitignore | ↓ |
| 11.3 | ローカル開発 (Docker) | 詳細 |
| 11.4 | S3 / MinIO | 詳細 |
| 11.5 | CI/CD (AWS想定) | 詳細 |
| 11.6 | docs/ と z_docs/ | 詳細 |
| 11.7 | ADR | 詳細 |
| 11.8 | RAG | 詳細 |
| 11.9 | OpenAI API 組み込み | 詳細 |
| 11.10 | Prompt 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 clone→make 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 testをdocker 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 コンテナ: ホストで gh・vercel・aws・docker compose・supabase。アプリ実行・テストは 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)
- インストールと確認
brew install gh gh --version - ログイン — ブラウザまたはトークン。
gh auth login後にgh auth statusでLogged inを確認する。 - リポジトリ紐付け — 作業ディレクトリで
gh repo set-default(またはgh repo viewで remote 確認)。 - エージェントの初手 — PR 調査:
gh pr checks→ 失敗 run:gh run view RUN_ID --log-failed。 - つまずき — SSO 組織は
gh auth login --hostname github.com --webを再実行。トークン scope 不足はrepo/read:orgを付与。
Vercel CLI
- インストールと確認
npm install -g vercel vercel --version - ログイン —
vercel login(ブラウザ)→vercel whoami。 - プロジェクト紐付け — 初回
vercel link。環境変数はvercel env pull .env.local(.env.localは gitignore)。 - エージェントの初手 — preview:
vercel(対話)または CI 経由。ローカル確認前にvercel env pullで不足キーを潰す。 - つまずき — 複数 team/scope があるときは
vercel switch。本番 deploy は要確認(上記「危険操作」)。
AWS CLI
- インストールと確認
brew install awscli aws --version - 認証(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)を正本とする。 - プロファイル確認 —
aws configure list-profiles。複数アカウントではAWS_PROFILEを rules に明記する。 - エージェントの初手 — ログ:
aws logs tail /ecs/myapp --follow。イメージ:aws ecr describe-repositories。 - つまずき — SSO セッションは数時間で切れる。
aws sso loginを再実行。region 未設定はAWS_DEFAULT_REGION=ap-northeast-1等を profile に固定。
Supabase CLI(短文)
brew install supabase/tap/supabase→supabase login→supabase projects list- ローカル:
supabase init→supabase 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想定 (仮)
全体像
サービス選定 (仮想定)
| 役割 | サービス | 備考 |
|---|---|---|
| ソース管理 | 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 でその場限りの認証情報を発行する。
セットアップ手順:
- AWS IAM で OIDC Identity Provider を追加 (
token.actions.githubusercontent.com) - GitHubリポジトリ・ブランチ限定の IAM Role を作成
- Role の信頼ポリシーで Repository / Branch を絞る (他リポジトリから乗っ取られないため)
- 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>/ # 任意: 機能別の検討メモ
└── (直下のインデックス・長期メモはプロジェクトの慣習に従う)
判断フロー
運用のコツ
- 履歴の正本は 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.mdcとCLAUDE.mdにも「出典を添える」「根拠が取れないときは推測で埋めない」を入れておくとブレにくい。
向いているケース / 向いていないケース
向いているケース:
- 社内ドキュメント、運用マニュアル、ADR、仕様書、サポートナレッジのように 文書が正式な記録 の知識を引かせたいとき
- 回答のたびに 出典を添えたい とき
- モデル再学習ではなく、文書更新で知識を更新したい とき
向いていない、または注意が必要なケース:
- 元文書の品質が低い、重複が多い、古い版が混ざるなど、検索前の情報整理ができていない状態
- 更新タイミング、再インデックス条件、失効ルールなどの 鮮度管理 が決まっていない状態
- 出典を返さずに使う運用。誤答時に根拠追跡ができず、利用者も検証しづらい
- 本来は DB クエリや外部 API 呼び出しで確定値を返すべき処理。RAG は検索付き要約であり、システム of record の代替ではない
小さく導入する手順
- 対象知識を絞る: まずは1領域だけに限定する。例: オンボーディング資料、運用FAQ、1機能分の仕様群
- source of truth を整理する:
docs/、docs/adr/、用語集のどれを正式な記録にするかを決め、重複や古い版を潰す - 更新フローを決める: 誰が更新し、いつ再インデックスし、古い文書をどう失効させるかを決める
- 検索粒度とメタデータを決める: chunk の大きさ、見出し単位、文書ID、版、更新日時、章名を揃える
- 評価基準を先に決める: 取得精度、引用の正確さ、根拠なし時に回答を控える率、レイテンシを最低限測る
- ログとフィードバックを残す: 質問、取得文書、回答、ユーザーフィードバックを保存して改善材料にする
- 小さく公開してから広げる: まずは限定ユーザー・限定ユースケースで運用し、定着したら対象文書を増やす。全体方針になるなら 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機能・内部ユーザー限定で開始し、オフライン評価と実運用ログを見ながら公開範囲を広げる。
timeout、malformed output、rate limitの失敗系テストを先に足す - docs / ADR / testing との接続: 機能単位では
docs/<feature>/04_tech_decisions.mdにユースケース、モデル、同期/非同期、出力形式、コスト上限を書く。全体方針になるなら ADR 化し、05_test_plan.mdと06_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 は []