R-Same Wave 0 Scaffold Complete

Decision

Wave 0 of Layer 4 backend plan shipped in commit a4a786e (2026-04-17). Monorepo live at github.com/ARJ-TECH/r-same (private). Structure: apps/api (FastAPI 0.115 + Pydantic 2.9 + structlog + slowapi + typed errors RSAME-MOD-CODE + RFC 7807 + /health + /readyz + pytest smoke) · apps/worker (RQ 2.0 + rq-scheduler + heartbeat + signal handlers) · apps/web (React 19 + Vite 6 + Tailwind v4 @theme + TanStack Router/Query + Geist fonts + indigo-700/500 accent + dark mode + prefers-reduced-motion + TS strict + ESLint flat + Vitest) · packages/db (SQLAlchemy 2.0 typed Base + Postgres naming convention + UUID/timestamp mixins + Alembic with RSAME_DATABASE_URL env override) · packages/contracts (openapi.yaml + schema.sql + auth-model.md seeded from ADR-0003 + rls-catalog.yaml with contract-test binding) · packages/query-runner/VENDOR.md · .github/workflows/ci.yml (Python ruff+mypy+pytest + Frontend ESLint+tsc+Vitest+build + contracts drift placeholder). Docker Compose dev stack: Postgres 17-alpine + Redis 7.4-alpine (password-protected) + Cube.js latest (dev mode, Postgres-backed until Wave 2 M4). All Python files parse-clean; docker-compose.yml validates. ADR-0007 records the scaffold. STATE.md updated to “Wave 1 M1 Identity next”.

Rationale

Wave 0 scaffold is the gate to module work — everything downstream (M1-M12) builds on this foundation. Shipping a complete backbone in one commit (vs incremental drips) gives developers a working dev loop immediately: make install → make up → make dev-{api,worker,web} → make health. Latest-stable pins applied across the board per Law 6. Security defaults baked in from day 1 (ruff S rules, TS strict, exactOptionalPropertyTypes, noUncheckedSideEffectImports, mypy strict, argon2-cffi + pyotp pre-pulled, RFC 7807 errors never leaking detail, secrets env-only, rate-limiter wired). Design tokens seeded per L3 freeze so module work doesn’t introduce ad-hoc colors. Contract artifacts exist as placeholders so they can’t be forgotten later. ADR-0007 captures the scaffold rationale; STATE.md captures the next action. 55 files in commit a4a786e, 53 new + 2 updates (STATE.md, ADR README index).

Alternatives Rejected

Defer Cube.js to Wave 2 (when actually used for M4) — rejected: L4 plan Wave 0 gate includes Cube health check; stubbed Cube against Postgres works + validates the dev-stack pattern.

Tailwind 3 for stability — rejected: latest-and-greatest directive; v4 CSS-first is the right greenfield choice; React 18 + Tailwind 3 fallback-branch plan is sufficient mitigation.

Poetry instead of uv — rejected: uv is 10-100× faster and the 2025 Python standard; no reason to start on legacy tooling.

Jest instead of Vitest — rejected: Vitest is Vite-native; shared config; no transformer mismatch.

tailwind.config.js instead of @theme — rejected: v4 is CSS-first; no migration cost at greenfield; tokens-as-CSS-variables works better with Radix/shadcn.

Separate alembic configs per module — rejected: single Alembic instance for the whole schema; module boundaries enforced at Python package level.

Include Storybook / Playwright in Wave 0 — deferred: Storybook needs real components (Wave 3+); Playwright is L6 Quality.

CodeMirror 6 editor stub — deferred to Wave 1 M3: real editor integration happens with query engine.

Include ADR-0007 in same commit as L1-L3 docs — rejected: L1-L3 docs were frozen in a prior commit; ADR-0007 records the scaffold decision separately for traceability.

Hardcode DB URL in alembic.ini for dev convenience — rejected (caught by secret-scanner hook): alembic env.py reads RSAME_DATABASE_URL; .ini has placeholder driver://user:pass@host/db only. Cleaner pattern anyway.

Outcome

Pending