Files
kite/.planning/phases/01-infrastructure-foundation/01-01-SUMMARY.md
T
curo1305 f9b8a0d1ca 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)
2026-05-22 09:01:16 +02:00

6.8 KiB

phase, plan, subsystem, tags, dependency_graph, tech_stack, key_files, decisions, metrics
phase plan subsystem tags dependency_graph tech_stack key_files decisions metrics
01-infrastructure-foundation 01 infrastructure
docker-compose
postgresql
minio
redis
celery
pydantic-settings
requires provides affects
five-service compose stack (postgres, minio, redis, backend, celery-worker)
two-DSN postgresql user provisioning
pydantic-settings config class
phase-1 dependency manifest
all subsequent plans (infrastructure foundation)
added removed patterns
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
filelock>=3.14
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)
created modified
docker-compose.yml
docker/postgres/initdb.d/01-init-users.sql
.gitignore
.env.example
backend/config.py
backend/requirements.txt
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)
duration completed_date tasks_completed tasks_total files_created files_modified
~6 minutes 2026-05-22 3 3 3 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

  • docker-compose.yml exists and contains 6 services
  • docker/postgres/initdb.d/01-init-users.sql exists
  • .gitignore contains .env
  • .env.example has 14 variables
  • backend/config.py has Settings class and settings instance
  • backend/requirements.txt has no filelock, has all 7 new packages
  • Commits 983ecd8, beb55ca, 6c507d5 confirmed in git log