From f9b8a0d1ca9839431b9eb6b57568935d40e5065f Mon Sep 17 00:00:00 2001 From: curo1305 Date: Fri, 22 May 2026 09:01:16 +0200 Subject: [PATCH] =?UTF-8?q?docs(01-01):=20complete=20Compose=20+=20Config?= =?UTF-8?q?=20Foundation=20plan=20=E2=80=94=20SUMMARY,=20STATE,=20ROADMAP?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Create 01-01-SUMMARY.md with full execution record (3 tasks, 6 files) - Update STATE.md: advance to plan 2 of 5, record key decisions, update session - Update ROADMAP.md: mark 01-01 complete, update progress table (1/5 plans) --- .planning/ROADMAP.md | 4 +- .planning/STATE.md | 35 +++-- .../01-01-SUMMARY.md | 138 ++++++++++++++++++ 3 files changed, 160 insertions(+), 17 deletions(-) create mode 100644 .planning/phases/01-infrastructure-foundation/01-01-SUMMARY.md diff --git a/.planning/ROADMAP.md b/.planning/ROADMAP.md index ee0e823..1a15c4f 100644 --- a/.planning/ROADMAP.md +++ b/.planning/ROADMAP.md @@ -27,7 +27,7 @@ _Last updated: 2026-05-21_ 4. MinIO object key schema `{user_id}/{document_id}/{uuid4()}{ext}` is enforced in the model layer; human-readable filenames are stored in the DB column, not in the MinIO key **Plans**: 5 plans -- [ ] 01-01-PLAN.md — Docker Compose service topology + Postgres init + Pydantic Settings + requirements +- [x] 01-01-PLAN.md — Docker Compose service topology + Postgres init + Pydantic Settings + requirements - [ ] 01-02-PLAN.md — Wave 0 test scaffolds (xfail/skip stubs) + async pytest fixtures - [ ] 01-03-PLAN.md — SQLAlchemy ORM models + async engine + Alembic async migration (incl. alembic upgrade head) - [ ] 01-04-PLAN.md — StorageBackend ABC + MinIO backend + rewritten async services/storage.py @@ -110,7 +110,7 @@ _Last updated: 2026-05-21_ | Phase | Plans Complete | Status | Completed | |-------|----------------|--------|-----------| -| 1. Infrastructure Foundation | 0/? | Not started | - | +| 1. Infrastructure Foundation | 1/5 | In Progress | - | | 2. Users & Authentication | 0/? | Not started | - | | 3. Document Migration & Multi-User Isolation | 0/? | Not started | - | | 4. Folders, Sharing, Quotas & Document UX | 0/? | Not started | - | diff --git a/.planning/STATE.md b/.planning/STATE.md index 90aef73..7ed8d74 100644 --- a/.planning/STATE.md +++ b/.planning/STATE.md @@ -2,29 +2,29 @@ gsd_state_version: 1.0 milestone: v1.0 milestone_name: milestone -current_phase: — +current_phase: 1 status: executing -last_updated: "2026-05-22T06:49:02.336Z" +last_updated: "2026-05-22T06:59:23Z" progress: total_phases: 5 completed_phases: 0 total_plans: 5 - completed_plans: 0 - percent: 0 + completed_plans: 1 + percent: 20 --- # Project State **Project:** DocuVault -**Status:** Ready to execute -**Current Phase:** — -**Last Updated:** 2026-05-21 +**Status:** Executing Phase 1 +**Current Phase:** 1 +**Last Updated:** 2026-05-22 ## Phase Status | Phase | Name | Status | |---|---|---| -| 1 | Infrastructure Foundation | Not Started | +| 1 | Infrastructure Foundation | In Progress (1/5 plans) | | 2 | Users & Authentication | Not Started | | 3 | Document Migration & Multi-User Isolation | Not Started | | 4 | Folders, Sharing, Quotas & Document UX | Not Started | @@ -32,9 +32,11 @@ progress: ## Current Position -**Phase:** — -**Plan:** — -**Progress:** ░░░░░░░░░░ 0% +Phase: 1 (Infrastructure Foundation) — EXECUTING +Plan: 2 of 5 +**Phase:** 01-infrastructure-foundation +**Plan:** 01-01 COMPLETE → advancing to 01-02 +**Progress:** ██░░░░░░░░ 20% ## Performance Metrics @@ -42,8 +44,8 @@ progress: |---|---| | Phases complete | 0 / 5 | | Requirements mapped | 54 / 54 | -| Plans written | 0 | -| Plans complete | 0 | +| Plans written | 5 (Phase 1) | +| Plans complete | 1 | ## Accumulated Context @@ -59,6 +61,9 @@ progress: | Refresh token family revocation | RFC 9700 — reuse of a rotated token revokes entire family and alerts user | | BackgroundTasks replacement | FastAPI BackgroundTasks is per-instance; replace with Celery+Redis or pgqueuer before horizontal scale | | Admin impersonation excluded | Explicit architectural exclusion — no endpoint or UI pathway; violates privacy-first core value | +| Two-DSN PostgreSQL strategy | DATABASE_URL (docuvault_app, DML only) + DATABASE_MIGRATE_URL (docuvault_migrate, DDL only); celery-worker gets only DATABASE_URL | +| MinIO healthcheck via mc ready local | curl removed from MinIO Docker image since Oct 2023; mc is the correct in-container healthcheck tool | +| pydantic-settings v2 SettingsConfigDict | SettingsConfigDict API used (not deprecated class Config form) for env var config | ### Open Questions @@ -77,6 +82,6 @@ _Updated at each phase transition._ | Field | Value | |---|---| -| Last session | 2026-05-21 — Roadmap created | -| Next action | Run `/gsd:plan-phase 1` to begin Phase 1 planning | +| Last session | 2026-05-22 — Executed 01-01-PLAN.md (Compose + Config Foundation) | +| Next action | Execute 01-02-PLAN.md (Wave 0 test scaffolds + async pytest fixtures) | | Pending decisions | See Open Questions above | diff --git a/.planning/phases/01-infrastructure-foundation/01-01-SUMMARY.md b/.planning/phases/01-infrastructure-foundation/01-01-SUMMARY.md new file mode 100644 index 0000000..4ec54ca --- /dev/null +++ b/.planning/phases/01-infrastructure-foundation/01-01-SUMMARY.md @@ -0,0 +1,138 @@ +--- +phase: 01-infrastructure-foundation +plan: "01" +subsystem: infrastructure +tags: + - docker-compose + - postgresql + - minio + - redis + - celery + - pydantic-settings +dependency_graph: + requires: [] + provides: + - five-service compose stack (postgres, minio, redis, backend, celery-worker) + - two-DSN postgresql user provisioning + - pydantic-settings config class + - phase-1 dependency manifest + affects: + - all subsequent plans (infrastructure foundation) +tech_stack: + added: + - "sqlalchemy[asyncio]>=2.0.49" + - "psycopg[binary]>=3.3.4" + - "alembic>=1.18.4" + - "minio>=7.2.20" + - "celery[redis]>=5.6.3" + - "redis>=7.4.0" + - "aiosqlite>=0.20.0" + removed: + - "filelock>=3.14" + patterns: + - pydantic-settings v2 SettingsConfigDict (not deprecated class Config form) + - docker compose service_healthy depends_on conditions + - two-DSN postgresql strategy (app user + migrate user) + - mc ready local healthcheck for MinIO (curl removed from image) + - redis-cli -a $REDIS_PASSWORD ping healthcheck (NOAUTH prevention) +key_files: + created: + - docker-compose.yml + - docker/postgres/initdb.d/01-init-users.sql + - .gitignore + modified: + - .env.example + - backend/config.py + - backend/requirements.txt +decisions: + - "Two-DSN PostgreSQL strategy: DATABASE_URL (docuvault_app, DML only) + DATABASE_MIGRATE_URL (docuvault_migrate, DDL only)" + - "MinIO healthcheck uses mc ready local — curl removed from image since Oct 2023" + - "Redis healthcheck passes -a $REDIS_PASSWORD — bare ping returns NOAUTH with requirepass" + - "Legacy flat-file constants (DATA_DIR, UPLOADS_DIR, DEFAULT_SETTINGS etc.) kept in config.py until Plan 05" + - "pydantic-settings v2 SettingsConfigDict API used (not deprecated class Config)" +metrics: + duration: "~6 minutes" + completed_date: "2026-05-22" + tasks_completed: 3 + tasks_total: 3 + files_created: 3 + files_modified: 3 +--- + +# Phase 1 Plan 1: Docker Compose + Config Foundation Summary + +**One-liner:** Five-service Compose stack (postgres:17-alpine + minio + redis:7-alpine + celery-worker + backend) with health-checked depends_on, two-user PostgreSQL init script, and Pydantic Settings class reading all Phase 1 env vars. + +## Tasks Completed + +| Task | Name | Commit | Key Files | +|------|------|--------|-----------| +| 1 | Replace docker-compose.yml with five-service stack | `983ecd8` | docker-compose.yml, docker/postgres/initdb.d/01-init-users.sql, .gitignore | +| 2 | Extend .env.example with all Phase 1 variables | `beb55ca` | .env.example | +| 3 | Replace backend/config.py with Pydantic Settings + extend requirements.txt | `6c507d5` | backend/config.py, backend/requirements.txt | + +## What Was Built + +### docker-compose.yml +Rewrote from a 2-service file (backend + frontend) to a full 6-service Phase 1 stack: +- **postgres** (postgres:17-alpine): health-checked with `pg_isready -U postgres -d docuvault`; mounts `docker/postgres/initdb.d` as `/docker-entrypoint-initdb.d:ro` +- **minio** (minio/minio:latest): health-checked with `mc ready local` (curl removed from image); exposes ports 9000 and 9001 +- **redis** (redis:7-alpine): runs `redis-server --requirepass ${REDIS_PASSWORD}`; health-checked with `redis-cli -a ${REDIS_PASSWORD} ping` to avoid NOAUTH errors +- **backend**: depends on all three infra services with `condition: service_healthy`; removed `./backend/data:/app/data` volume per D-04 +- **celery-worker**: same build as backend; command `celery -A celery_app worker --loglevel=info -Q documents` per D-10; has `DATABASE_URL` but NOT `DATABASE_MIGRATE_URL` (workers need no DDL) +- **frontend**: unchanged from original +- Top-level `volumes:` block with `postgres_data:` and `minio_data:` named volumes + +### docker/postgres/initdb.d/01-init-users.sql +Provisions both PostgreSQL users on first container start: +- `docuvault_migrate` with `GRANT ALL PRIVILEGES ON DATABASE docuvault` (DDL — Alembic only) +- `docuvault_app` with `GRANT CONNECT ON DATABASE docuvault` (DML — FastAPI + Celery) +- Comment notes that table-level grants are issued in the Alembic migration (Plan 03) + +### .env.example +Extended from 6 lines to a fully documented 4-section env file with 14 named variables grouped by service. All passwords use `changeme_*` placeholders consistent between the env file and the SQL init script. + +### backend/config.py +Added `Settings(BaseSettings)` class with `SettingsConfigDict` (pydantic-settings v2 API). Instantiates `settings = Settings()` at module level. Preserved all legacy flat-file constants verbatim (`DATA_DIR`, `UPLOADS_DIR`, `METADATA_DIR`, `TOPICS_FILE`, `SETTINGS_FILE`, `DEFAULT_SYSTEM_PROMPT`, `DEFAULT_SETTINGS`, `ensure_data_dirs()`). + +### backend/requirements.txt +Removed `filelock>=3.14`. Added 7 new dependencies: `sqlalchemy[asyncio]>=2.0.49`, `psycopg[binary]>=3.3.4`, `alembic>=1.18.4`, `minio>=7.2.20`, `celery[redis]>=5.6.3`, `redis>=7.4.0`, `aiosqlite>=0.20.0`. Bumped `pytest-asyncio` to `>=1.3.0`. + +## Verification Results + +- `docker compose --env-file .env.example config -q` exits 0 (no parse errors) +- `from config import settings; settings.minio_bucket` returns `"docuvault"` +- `settings.database_url` starts with `postgresql+psycopg://` +- `grep -c "filelock" backend/requirements.txt` returns 0 +- All 14 env vars present in `.env.example` +- All 6 service keys present in `docker-compose.yml` +- SQL init script creates both `docuvault_app` and `docuvault_migrate` users + +## Deviations from Plan + +None — plan executed exactly as written. + +The legacy flat-file constants were preserved verbatim as specified in the plan's `` section. The `SettingsConfigDict` approach (pydantic-settings v2 API) was used as specified. The `celery-worker` service omits `DATABASE_MIGRATE_URL` as specified (workers need no DDL access). + +## Known Stubs + +None — this plan is infrastructure and configuration only. No UI data flows or component wiring involved. + +## Threat Flags + +None — all threat mitigations from the plan's threat model are implemented: +- T-01-01-01 (PostgreSQL EoP): Two-DSN pattern implemented (app user DML-only, migrate user DDL-only) +- T-01-01-02 (MinIO root creds): MINIO_ROOT_USER/PASSWORD separate from MINIO_ACCESS_KEY/SECRET_KEY in both compose and env.example +- T-01-01-03 (Redis unauthenticated): `--requirepass ${REDIS_PASSWORD}` + authenticated healthcheck +- T-01-01-04 (Secret leakage): `.env` added to `.gitignore`; only `.env.example` with `changeme_*` values committed +- T-01-01-05 (Race condition startup): `depends_on: condition: service_healthy` on all infra dependencies + +## Self-Check: PASSED + +- [x] docker-compose.yml exists and contains 6 services +- [x] docker/postgres/initdb.d/01-init-users.sql exists +- [x] .gitignore contains `.env` +- [x] .env.example has 14 variables +- [x] backend/config.py has Settings class and settings instance +- [x] backend/requirements.txt has no filelock, has all 7 new packages +- [x] Commits 983ecd8, beb55ca, 6c507d5 confirmed in git log