docs(01-01): complete Compose + Config Foundation plan — SUMMARY, STATE, ROADMAP
- 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)
This commit is contained in:
@@ -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
|
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
|
**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-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-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
|
- [ ] 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 |
|
| Phase | Plans Complete | Status | Completed |
|
||||||
|-------|----------------|--------|-----------|
|
|-------|----------------|--------|-----------|
|
||||||
| 1. Infrastructure Foundation | 0/? | Not started | - |
|
| 1. Infrastructure Foundation | 1/5 | In Progress | - |
|
||||||
| 2. Users & Authentication | 0/? | Not started | - |
|
| 2. Users & Authentication | 0/? | Not started | - |
|
||||||
| 3. Document Migration & Multi-User Isolation | 0/? | Not started | - |
|
| 3. Document Migration & Multi-User Isolation | 0/? | Not started | - |
|
||||||
| 4. Folders, Sharing, Quotas & Document UX | 0/? | Not started | - |
|
| 4. Folders, Sharing, Quotas & Document UX | 0/? | Not started | - |
|
||||||
|
|||||||
+20
-15
@@ -2,29 +2,29 @@
|
|||||||
gsd_state_version: 1.0
|
gsd_state_version: 1.0
|
||||||
milestone: v1.0
|
milestone: v1.0
|
||||||
milestone_name: milestone
|
milestone_name: milestone
|
||||||
current_phase: —
|
current_phase: 1
|
||||||
status: executing
|
status: executing
|
||||||
last_updated: "2026-05-22T06:49:02.336Z"
|
last_updated: "2026-05-22T06:59:23Z"
|
||||||
progress:
|
progress:
|
||||||
total_phases: 5
|
total_phases: 5
|
||||||
completed_phases: 0
|
completed_phases: 0
|
||||||
total_plans: 5
|
total_plans: 5
|
||||||
completed_plans: 0
|
completed_plans: 1
|
||||||
percent: 0
|
percent: 20
|
||||||
---
|
---
|
||||||
|
|
||||||
# Project State
|
# Project State
|
||||||
|
|
||||||
**Project:** DocuVault
|
**Project:** DocuVault
|
||||||
**Status:** Ready to execute
|
**Status:** Executing Phase 1
|
||||||
**Current Phase:** —
|
**Current Phase:** 1
|
||||||
**Last Updated:** 2026-05-21
|
**Last Updated:** 2026-05-22
|
||||||
|
|
||||||
## Phase Status
|
## Phase Status
|
||||||
|
|
||||||
| Phase | Name | Status |
|
| Phase | Name | Status |
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
| 1 | Infrastructure Foundation | Not Started |
|
| 1 | Infrastructure Foundation | In Progress (1/5 plans) |
|
||||||
| 2 | Users & Authentication | Not Started |
|
| 2 | Users & Authentication | Not Started |
|
||||||
| 3 | Document Migration & Multi-User Isolation | Not Started |
|
| 3 | Document Migration & Multi-User Isolation | Not Started |
|
||||||
| 4 | Folders, Sharing, Quotas & Document UX | Not Started |
|
| 4 | Folders, Sharing, Quotas & Document UX | Not Started |
|
||||||
@@ -32,9 +32,11 @@ progress:
|
|||||||
|
|
||||||
## Current Position
|
## Current Position
|
||||||
|
|
||||||
**Phase:** —
|
Phase: 1 (Infrastructure Foundation) — EXECUTING
|
||||||
**Plan:** —
|
Plan: 2 of 5
|
||||||
**Progress:** ░░░░░░░░░░ 0%
|
**Phase:** 01-infrastructure-foundation
|
||||||
|
**Plan:** 01-01 COMPLETE → advancing to 01-02
|
||||||
|
**Progress:** ██░░░░░░░░ 20%
|
||||||
|
|
||||||
## Performance Metrics
|
## Performance Metrics
|
||||||
|
|
||||||
@@ -42,8 +44,8 @@ progress:
|
|||||||
|---|---|
|
|---|---|
|
||||||
| Phases complete | 0 / 5 |
|
| Phases complete | 0 / 5 |
|
||||||
| Requirements mapped | 54 / 54 |
|
| Requirements mapped | 54 / 54 |
|
||||||
| Plans written | 0 |
|
| Plans written | 5 (Phase 1) |
|
||||||
| Plans complete | 0 |
|
| Plans complete | 1 |
|
||||||
|
|
||||||
## Accumulated Context
|
## Accumulated Context
|
||||||
|
|
||||||
@@ -59,6 +61,9 @@ progress:
|
|||||||
| Refresh token family revocation | RFC 9700 — reuse of a rotated token revokes entire family and alerts user |
|
| 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 |
|
| 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 |
|
| 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
|
### Open Questions
|
||||||
|
|
||||||
@@ -77,6 +82,6 @@ _Updated at each phase transition._
|
|||||||
|
|
||||||
| Field | Value |
|
| Field | Value |
|
||||||
|---|---|
|
|---|---|
|
||||||
| Last session | 2026-05-21 — Roadmap created |
|
| Last session | 2026-05-22 — Executed 01-01-PLAN.md (Compose + Config Foundation) |
|
||||||
| Next action | Run `/gsd:plan-phase 1` to begin Phase 1 planning |
|
| Next action | Execute 01-02-PLAN.md (Wave 0 test scaffolds + async pytest fixtures) |
|
||||||
| Pending decisions | See Open Questions above |
|
| Pending decisions | See Open Questions above |
|
||||||
|
|||||||
@@ -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 `<interfaces>` 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
|
||||||
Reference in New Issue
Block a user