72 lines
3.9 KiB
Markdown
72 lines
3.9 KiB
Markdown
# Implementation plan
|
||
|
||
Step-by-step build order for Phase 0 (prototype) and the seams that make Phases 1–5 cheap.
|
||
|
||
The principle: **build the contracts first, stub the internals.** Every service should exist with a `/health` endpoint and a minimal real implementation of its interface before any service is "finished". This gives us an end-to-end walking skeleton from week one.
|
||
|
||
---
|
||
|
||
## Stage 0 — Foundations (days 1–3)
|
||
|
||
1. **Monorepo tooling.** pnpm workspaces for JS/TS; uv or poetry for Python; turbo or nx for build graph; pre-commit (lint, typecheck, format).
|
||
2. **Docker Compose dev env.** Postgres, NATS, MinIO (S3), Mailhog, all services wired with hot-reload.
|
||
3. **CI skeleton** (Gitea Actions): lint → typecheck → unit test → build → publish images.
|
||
4. **Secrets convention.** `.env.example` per service; prod secrets injected by orchestrator.
|
||
5. **Shared types package.** OpenAPI source → generated TS + Python clients.
|
||
|
||
Deliverable: `docker compose up` brings a green dashboard of `/health` endpoints.
|
||
|
||
## Stage 1 — Identity & session (days 4–7)
|
||
|
||
1. `services/auth`: Google OAuth2 (PKCE), session cookies, short-lived JWTs, refresh rotation. Library-backed (Auth.js or Ory Kratos + Hydra) — we do not roll our own.
|
||
2. `services/profile`: minimal `User` record; created on first sign-in.
|
||
3. `apps/web` sign-in page; gateway verifies JWT.
|
||
|
||
Exit check: a user can sign in and fetch their own profile.
|
||
|
||
## Stage 2 — Integrations framework (days 8–12)
|
||
|
||
1. `services/integrations` with a **Connector** interface:
|
||
- `begin_oauth(user) → redirect_url`
|
||
- `finish_oauth(code, state) → StoredCredential`
|
||
- `fetch_signals(user, since) → Event[]`
|
||
2. **Token vault**: column-level encryption (libsodium), key from env or KMS.
|
||
3. **Todoist connector** as the first concrete implementation.
|
||
4. Web "Connect" page: list of connectors, button per connector, callback handling.
|
||
|
||
Exit check: a user taps "Connect Todoist", completes the OAuth dance, and the integrations service can fetch their tasks on demand.
|
||
|
||
## Stage 3 — Recommender contract (days 13–16)
|
||
|
||
1. `services/recommender` exposes `POST /recommend {user_id, context} → {tip}`.
|
||
2. Policy interface (`Policy.pick(user, candidates, context) → tip`).
|
||
3. **`RandomPolicy` v0** — fetches candidates from `integrations` (Todoist tasks), returns one uniformly at random.
|
||
4. Tip shape is provider-agnostic: `{id, kind: "todo"|"advice", title, body, source, deep_link, meta}`.
|
||
5. `apps/web` tip page: full black, one tip centered, tap = mark done → callback fires to integrations (complete Todoist task) + emits a feedback event.
|
||
|
||
Exit check: three-page prototype works end-to-end for one user.
|
||
|
||
## Stage 4 — Hardening the prototype (days 17–20)
|
||
|
||
1. Error surfaces (Sentry), structured logs (pino / structlog), trace IDs across services.
|
||
2. Rate limits + retries on outbound API calls.
|
||
3. Integration tests: Playwright for the web flow, pact-style contract tests between services.
|
||
4. Deploy to a single VM via docker-compose + Caddy.
|
||
|
||
Exit check: Phase 0 milestone closed.
|
||
|
||
---
|
||
|
||
## Seams prepared for later phases (do not implement yet, but do not foreclose)
|
||
|
||
- **Event bus.** From day one, `integrations` and `recommender` speak through an async fn that today is an in-process call but will be NATS tomorrow. Keep the signature `(event: NormalizedEvent) → void`.
|
||
- **Feature store.** The recommender accepts a `context` blob; later, a feature service fills it. Do not inline feature lookups inside the policy.
|
||
- **Policy registry.** `PolicyFactory.get(name)` so A/B and bandit policies slot in without code changes to the gateway.
|
||
- **Python boundary.** Recommender is TS today, but its scoring function is isolated — moving to FastAPI in Phase 1 is a file move, not a refactor.
|
||
|
||
---
|
||
|
||
## Staffing assumption
|
||
|
||
Work is parallelizable across ~3 streams: **infra/platform**, **backend services**, **web app**. Each Gitea issue notes which stream and which phase (milestone) it belongs to.
|