diff --git a/CLAUDE.md b/CLAUDE.md index c1587cd..3885dc0 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -103,4 +103,6 @@ The event schema is the most important artifact in the repo. Rules: ## Current Working Context -See `docs/CURRENT_SLICE.md` for what we're actively building right now. +The Week 1–2 Foundation slice is **complete** (all 8 deliverables on `main`, 2026-05-18). Active work is now **Vertical Slice 0 — Auth + Task Capture Spine**. + +See `docs/CURRENT_SLICE.md` for what we're actively building right now, and `docs/handoffs/week-1-2.md` for the foundation outcome + remaining operational steps. diff --git a/docs/CURRENT_SLICE.md b/docs/CURRENT_SLICE.md index d90440a..40ec3bb 100644 --- a/docs/CURRENT_SLICE.md +++ b/docs/CURRENT_SLICE.md @@ -1,10 +1,10 @@ # Current Slice — Vertical Slice 0: Auth + Task Capture Spine -> **⚠️ Foundation status (2026-05-11):** The Week 1–2 Foundation slice is **partially shipped**. Monorepo wiring, event schema v1 (9 types, TS↔Python round-trip green), `@lockin/ui` base components, GitHub Actions PR pipeline, and GCP Terraform modules are done. Auth (NextAuth + Google OAuth + passkeys), full observability (Sentry + OTel + Grafana), Storybook deploy, secrets-pull CLI, and the TimescaleDB hypertable migration are **not yet shipped**. Read [`docs/handoffs/week-1-2.md`](handoffs/week-1-2.md) before starting this slice — Slice 0 depends on auth being in place, so Tasks 9 + 10 of the foundation plan should land first. +> **✅ Foundation status (2026-05-18):** The Week 1–2 Foundation slice is **complete** — all 8 deliverables merged to `main` across PRs #1–#5. Monorepo + Turborepo, event schema v1 (9 types, TS↔Python round-trip), `@lockin/ui` + Storybook, GitHub Actions (PR + staging + prod pipelines), GCP Terraform modules, observability (OTel + Sentry + Grafana), secret management, and the auth foundation (NextAuth v5 + Google OAuth + WebAuthn passkeys) are all on `main`. Remaining items are **operational, not code** — see [`docs/handoffs/week-1-2.md`](handoffs/week-1-2.md) for the ops checklist before this slice ships to a real environment. -**Status:** Blocked on Foundation Tasks 9 + 10 (auth + passkeys) +**Status:** Ready to start — foundation unblocked **Owner:** [assigned engineer] -**Est. duration:** 3–5 days (after auth lands) +**Est. duration:** 3–5 days ## The Goal diff --git a/docs/handoffs/week-1-2.md b/docs/handoffs/week-1-2.md index 14262f9..3cbbf20 100644 --- a/docs/handoffs/week-1-2.md +++ b/docs/handoffs/week-1-2.md @@ -1,63 +1,65 @@ # Week 1–2 Foundation — Handoff to Week 3 -**Date:** 2026-05-11 -**Branch:** `feat/week-1-2-foundation` +**Slice status:** ✅ **COMPLETE** — all 8 deliverables merged to `main` (2026-05-18) **Plan:** [`docs/superpowers/plans/2026-05-11-week-1-2-foundation.md`](../superpowers/plans/2026-05-11-week-1-2-foundation.md) +**Shipped via:** PRs #1–#5 -This slice is partially landed. The foundation-unblocking subset that Week 3 depends on is shipped; auth, observability, and Storybook are sequenced for follow-up sessions. +## Delivery map -## Shipped this session +| PR | Branch | Deliverables | +| --- | --- | --- | +| #1 | `feat/week-1-2-foundation` | 1 Monorepo · 2 CI (PR pipeline) · 3 Terraform · 7 design system · 8 event schema | +| #2 | `feat/auth-google-oauth` | 6 Auth foundation · TimescaleDB hypertable migration | +| #3 | `feat/observability-baseline` | 4 Observability (OTel + Sentry + Grafana) | +| #4 | `feat/deploy-and-secrets` | 2 CI (staging/prod CD) · 5 Secret management | +| #5 | `feat/storybook-preview` | 7 Storybook deploy | -- [x] **Deliverable 1 — Monorepo.** Turborepo + pnpm workspace at root. `pnpm install && pnpm typecheck` green on a clean clone. 4 workspaces: `@lockin/web`, `@lockin/events`, `@lockin/ui`, `@lockin/shared-types`. uv workspace covers `apps/api`, `apps/mcp`, `packages/events/python`. -- [x] **Deliverable 2 — CI/CD (PR pipeline).** `.github/workflows/pr.yml` with `dorny/paths-filter` for changed-package detection. Separate jobs: js (lint/typecheck/test/build), python-api (ruff/mypy/pytest), python-mcp, events-roundtrip (TS + Python parity), terraform-plan (fmt-check + validate staging + prod). One `gate` job aggregates results so branch protection has a single required check. -- [x] **Deliverable 3 — Terraform (modules + envs).** Six GCP modules (`vpc`, `postgres`, `redis`, `kubernetes`, `secrets`, `dns`) wired into `envs/staging` and `envs/prod`. GCS remote state, env-prefixed paths. README documents state-bucket bootstrap, TimescaleDB `CREATE EXTENSION` step, and the Workload Identity Federation chicken-and-egg. -- [x] **Deliverable 7 — Design system (`@lockin/ui`).** Six base components (`Button`, `Input`, `Card`, `Stack`, `Text`, `Icon`) + Tailwind v4 `@theme` token block with brand, semantic surfaces, type scale, spacing, motion, radius, dark-mode variants. 18 component tests via Vitest + Testing Library. `apps/web` consumes `@lockin/ui` and the page renders `Button/Stack/Text` — design-system smoke test green. -- [x] **Deliverable 8 — Event schema v1.** Zod source-of-truth at `packages/events/src/schema.ts`. 9 event types (`task.created`, `task.scheduled`, `task.accepted`, `task.rejected`, `task.modified`, `task.completed`, `mood.logged`, `energy.logged`, `schedule.explained`). Versioned envelope (`event_version: 1`) with `source` enum, `tenant_id`, `client_idempotency_key`. JSON Schema emitted; pydantic models generated via `datamodel-code-generator`. 19 TS round-trip tests + 10 Python round-trip tests — both green. `apps/api/app/events/schemas.py` rewritten to thin re-export from the `lockin_events` package. +## Acceptance vs current state -## Punted to follow-up sessions +| # | Deliverable | Acceptance check | State | +| --- | --- | --- | --- | +| 1 | Monorepo | `pnpm install` + `pnpm dev` boots web; `make api`/`make mcp` boot the Python apps | ✅ shipped | +| 2 | CI/CD | PR pipeline (paths-filtered) + `staging.yml` + `prod.yml` | ✅ shipped — live deploys gated on repo secrets | +| 3 | Terraform | GCP modules (vpc/postgres/redis/gke/secrets/dns) + staging/prod envs | ✅ shipped — `apply` pending one-time GCP bootstrap | +| 4 | Observability | OTel + Sentry on api/mcp/web; Grafana dashboards; forced-500 route | ✅ shipped — Grafana UI authoring + Slack contact point pending | +| 5 | Secrets | Zero secrets in repo; `pnpm secrets:pull` helper | ✅ shipped | +| 6 | Auth foundation | NextAuth v5 + Google OAuth + JWT middleware + `/api/me`; WebAuthn passkey endpoints | ✅ shipped | +| 7 | Design system | `@lockin/ui` 6 base components + tokens; `apps/web` consumes them; Storybook | ✅ shipped — Lighthouse ≥95 verify pending live deploy | +| 8 | Event schema v1 | 9 event types, TS↔Python round-trip; TimescaleDB migration ready (unapplied) | ✅ shipped | -- [ ] **Deliverable 2 — staging + prod pipelines.** `.github/workflows/staging.yml` and `prod.yml` are speced in the plan (Task 6) but not committed. Manual reviewer approval on the `prod` GitHub Environment is a repo-setting and is **not** enforced by the workflow file alone. -- [ ] **Deliverable 4 — Observability.** OpenTelemetry SDK wiring (Task 11), Sentry SDK on web/api/mcp (Task 12), Grafana Cloud dashboards + Slack alert + forced-500 verification (Task 13). Today's `apps/api/app/core/logging.py` is OTel-compatible structured logging only — no exporter yet. -- [ ] **Deliverable 5 — Secret management.** `scripts/secrets-pull.mjs` and `.env.example` expansion (Task 8). Today there are no real secrets in the repo (✓) but no automated rotation pull either. -- [ ] **Deliverable 6 — Auth foundation.** NextAuth v5 + Google OAuth + JWT middleware + `/api/me` (Task 9), WebAuthn passkey endpoints (Task 10). -- [ ] **Deliverable 7 — Storybook deploy** (Task 4). Components exist; Storybook config + Vercel preview workflow do not. -- [ ] **Deliverable 8 — TimescaleDB hypertable migration** (Task 14). Alembic migration not yet committed; the plan has the code. +## Test posture on `main` -## Open infra debt (must do once, manually, before staging is real) +- `pnpm typecheck` — 5/5 turbo tasks · `pnpm lint` — 3/3 · `pnpm test` — 18 ui + 19 events +- `pytest apps/api` — 15 · `pytest apps/mcp` — 2 · `pytest packages/events` — 10 +- `mypy apps/api` clean (40 files) · `mypy apps/mcp` clean (12 files) -- Create GCS state bucket: `gcloud storage buckets create gs://lockin-tfstate-$LOCKIN_GCP_PROJECT ...` (see [`infra/terraform/README.md`](../../infra/terraform/README.md)). -- Configure GitHub Actions OIDC → GCP Workload Identity Pool. The pool/provider isn't in Terraform — it would have to authenticate as itself to create itself. -- After Terraform applies Cloud SQL: connect once and run `CREATE EXTENSION IF NOT EXISTS timescaledb CASCADE;`. -- Configure repo Settings → Environments → `prod` with required-reviewers; the workflow file does not enforce this on its own. +## Open operational debt — must be done before staging is real -## What Week 3 (Auth + Task Capture Spine) starts with +These are **not code** — they are one-time provisioning steps, owned by DevOps: -- `pnpm install && pnpm dev` boots `@lockin/web` on `http://localhost:3000`. -- `@lockin/web` already imports `Button`, `Stack`, `Text` from `@lockin/ui`. Adding `Input` for the task-input field is one import. -- `@lockin/events` exports `TaskCreatedEvent`, `LockInEvent`, and 7 more event types. `apps/api` imports the same types via `from lockin_events import TaskCreated`. -- The `events:tasks` Redis stream constant is canonical in both languages. `EVENT_TYPE_TO_STREAM["task.created"] === "events:tasks"`. -- `apps/api` test suite still passes after the `schemas.py` rewrite — 1 health test green. -- `docker compose -f infra/docker/docker-compose.dev.yml up -d` brings up local Postgres + Redis (this slice did not touch local-dev infra). +- **GCS state bucket** — `gcloud storage buckets create gs://lockin-tfstate-$LOCKIN_GCP_PROJECT …` (see [`infra/terraform/README.md`](../../infra/terraform/README.md)). +- **GitHub Actions OIDC → GCP** — create the Workload Identity Federation pool/provider; bind the `lockin-deploy` service account. Cannot be Terraformed (chicken-and-egg). +- **Repo secrets** — provision `VERCEL_TOKEN`, `VERCEL_ORG_ID`, `VERCEL_WEB_PROJECT_ID`, `VERCEL_STORYBOOK_PROJECT_ID`, `GCP_WORKLOAD_IDENTITY_PROVIDER`, `GCP_DEPLOY_SA`, `GCP_PROJECT_ID`, `SENTRY_DSN_*`, `SENTRY_ORG/PROJECT/AUTH_TOKEN`, `GRAFANA_CLOUD_OTLP_*`. +- **`prod` GitHub Environment** — configure Required reviewers in repo Settings → Environments. The `prod.yml` workflow references the environment but does not enforce the gate by itself. +- **TimescaleDB** — after the first `terraform apply` provisions Cloud SQL, run `CREATE EXTENSION IF NOT EXISTS timescaledb CASCADE;` once, then apply Alembic migration `0001`. +- **K8s manifests** — `staging.yml`/`prod.yml` assume `Deployment/api` and `Deployment/mcp` already exist in the `lockin` namespace. Authoring those manifests is the first infra task of whichever slice ships the backend to GKE. +- **Grafana** — import the three dashboards from [`infra/grafana/dashboards/`](../../infra/grafana/dashboards), create the `#lockin-test-alerts` Slack contact point + the `api 5xx > 0` rule, then run the forced-500 acceptance test (`curl …/v1/__debug__/force_500`). -## What Week 3 should **not** do +## Known code follow-up -- Touch root Turborepo wiring, event schema TS/Python codegen pipeline, or `@lockin/ui` base components. Add new components/events only if needed. -- Add another OAuth provider — that's the Week 5 polish window per the cloud + OAuth decision record ([`docs/decisions/2026-05-11-cloud-and-oauth.md`](../decisions/2026-05-11-cloud-and-oauth.md)). -- Start native mobile, gamification, or analytics dashboard work — those are P3 / out-of-scope per `CLAUDE.md`. +- **`app` package-name collision** — both `apps/api` and `apps/mcp` install themselves as the top-level `app` Python module. The `apps/mcp` smoke test works around it with `importlib` path-loading. Proper fix: rename one package (`refactor/mcp-namespace`). Not foundation scope. -## Acceptance vs current state +## What Week 3 (Auth + Task Capture Spine) starts with -| # | Deliverable | Acceptance check | State | -| --- | ---------------------------------------- | ----------------------------------------------------------- | ----------------------------------------- | -| 1 | Monorepo | `pnpm install && pnpm dev` boots all 3 apps from clean clone | ✓ shipped | -| 2 | CI/CD | PR pipeline runs only changed-package tests; main→staging <8m; tag→prod with approval | PR pipeline ✓ shipped; staging/prod ↺ punted | -| 3 | Terraform | `apply` from zero produces working staging; `destroy` clean | ✓ shipped (validation pending real `apply`) | -| 4 | Observability | Forced 500 → Sentry + Grafana + Slack alert within 60s | ↺ punted | -| 5 | Secrets | No secrets in repo; rotation without redeploy | Half: repo is clean (✓), no rotation tool yet | -| 6 | Auth foundation | OAuth signin → `/api/me` returns user; passkey verify works | ↺ punted | -| 7 | Design system | `@lockin/web` uses `@lockin/ui`; Lighthouse ≥95 | Components ✓ shipped; Storybook deploy ↺ punted | -| 8 | Event schema v1 | TS↔Python round-trip green; hypertable migration ready | Round-trip ✓ shipped; migration ↺ punted | +- A user can sign in with Google; `/api/me` returns `{ user_id, email, providers }`. +- The api validates a shared-secret HS256 bearer (`get_current_user` dependency) and can write to Postgres. +- The event schema imports cleanly from `apps/web` (`@lockin/events`) and `apps/api` (`lockin_events`). +- `@lockin/ui` exports `Input`, `Button`, `Stack`, `Text` — everything the task-input UI needs. +- Sentry catches errors; OTel traces flow once `GRAFANA_CLOUD_OTLP_*` is set; the forced-500 route proves the chain. +- `docker compose -f infra/docker/docker-compose.dev.yml up -d` brings up local Postgres + Redis. -## Pointer for the next session +## What Week 3 should NOT do -Read [`docs/superpowers/plans/2026-05-11-week-1-2-foundation.md`](../superpowers/plans/2026-05-11-week-1-2-foundation.md) — Tasks **4, 6, 8, 9, 10, 11, 12, 13, 14** are concretely spec'd and unexecuted. Each has full code/config; no placeholders. +- Re-touch monorepo wiring, the event-schema codegen pipeline, or `@lockin/ui` base components — extend only. +- Add another OAuth provider — Apple + Microsoft are the Week 5 polish window ([`docs/decisions/2026-05-11-cloud-and-oauth.md`](../decisions/2026-05-11-cloud-and-oauth.md)). +- Start gamification, native mobile, or an analytics dashboard — out of P1 scope per `CLAUDE.md`. diff --git a/docs/superpowers/plans/2026-05-11-week-1-2-foundation.md b/docs/superpowers/plans/2026-05-11-week-1-2-foundation.md index 9eab271..16133d8 100644 --- a/docs/superpowers/plans/2026-05-11-week-1-2-foundation.md +++ b/docs/superpowers/plans/2026-05-11-week-1-2-foundation.md @@ -1,5 +1,12 @@ # Week 1–2 Foundation Slice — Implementation Plan +> **✅ STATUS: COMPLETE (2026-05-18).** All 15 tasks shipped to `main` via PRs #1–#5. +> The unchecked `- [ ]` boxes below are left as the historical plan record — do not +> re-execute. Current state and remaining operational steps live in +> [`docs/handoffs/week-1-2.md`](../../handoffs/week-1-2.md). +> Mapping: Tasks 1,2,3,7(components),8 → PR #1 · Tasks 9,10,14 → PR #2 · +> Tasks 11,12,13 → PR #3 · Tasks 6,8(secrets CLI) → PR #4 · Task 4 → PR #5. + > **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. **Goal:** Ship the eight Week 1–2 Foundation Handoff deliverables — monorepo wiring, CI/CD, GCP Terraform, observability, secret management, auth foundation, design system, and event schema v1 — so the Week 3 Auth+Task-Capture vertical slice can start clean on Day 1.