Files
2026-06-18 22:03:56 -04:00

57 lines
8.4 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Milestones
## v1.1 Operability & Polish (Shipped: 2026-06-18)
**Scope:** 14 phases (720), 57 plans, ~110 tasks. Continues v1.0 numbering; merged to `main` across a series of phase PRs (latest #27).
**Delivered:** Turned the v1.0 MVP into a configurable, administrable, and maintainable app — guided first-run setup, in-app role-gated admin, per-event reminders, near-instant write-back, local-auth (no-OIDC) mode, auto timezone — backed by a full self-hosted Gitea CI/CD pipeline (mobile + desktop e2e, security scanning, image hygiene, Docker publish) and a real lint gate. No more hand-editing env files or the database.
**Key accomplishments:**
- **Phase 7 — Mobile Test Harness:** Playwright harness (`@playwright/test`) with an iPhone/WebKit + Pixel/Chromium device matrix, SW-block, env-driven baseURL, deterministic dev-DB seed, and `DEV_AUTH_BYPASS` auth; layout/calendar/lists specs assert tap-targets, overflow, and populated/empty/error states. TEST-01/02. (Consumed by Phase 8 CI.)
- **Phase 8 — Gitea CI:** Self-hosted Gitea Actions pipeline — parallel `fast-checks` (lint/typecheck/PWA unit) + `api` (MariaDB 11 service container + migrate + DB-backed tests) + `harness` (dev-stack bring-up + Phase 7 specs on both profiles) gating every PR to `main`, plus a publish job pushing the API production image (`:latest` + `:v1.1-<sha>`, `--password-stdin`). CI-01/02.
- **Phase 9 — Faster Write-Back:** Event-driven outbox drain via a zero-dependency in-process EventEmitter (`outboxTrigger.ts`) — committed enqueues fire `signalOutboxDrain()` so edits land in ~12s instead of ~15s, preserving optimistic-202, create-before-delete, per-uid exactly-once, and the 15s fallback sweep. CAL-15.
- **Phase 10 — Admin Role & Settings:** v1.1 DB foundation (`users.is_admin`, `member_credentials.provider_type`, `calendar_events.reminder_lead_minutes`, `app_config`); DB-backed `requireAdmin` gating all `/api/admin/*`; one shared `validateEncryptAndStoreCredential` (CalDAV PROPFIND + AES-256-GCM) for admin rotation + member self-service; gated `/admin` PWA route. ADMIN-01/02/03.
- **Phase 11 — Per-Event Reminders:** Per-event reminder picker (None / 5m … 2d, all-day → 9 AM local) serialized as a VALARM, with a variable-lead scheduler (`uid:dtstartMs` dedup, dropped the hardcoded 15-min/shared-only restriction) that honors each event's lead, fires nothing without an alarm, and preserves VALARMs set in other clients. CAL-13/14, NOTIF-04/05/06.
- **Phase 12 — Initial Setup Wizard:** Pre-auth `/api/setup/*` first-run wizard validating DB / VAPID / OIDC / app-password before completion, generating env secrets (never persisted to DB), promoting the completing user to admin, and locking with a 423 guard on every invocation. SETUP-01/02/03/04.
- **Phase 13 — Real Lint Gate (ESLint):** ESLint flat config (typescript-eslint + React) across both apps + a Prettier `format:check` gate, turning the hollow `--if-present` no-op into a CI lint gate that actually fails; full first-run baseline cleanup to green.
- **Phase 14 — Desktop E2E Coverage:** Added a `desktop` (Desktop Chrome, no-touch) Playwright project and made the mobile-authored specs desktop-safe, so the CI regression gate validates desktop as well as iphone/pixel.
- **Phase 15 — Doc-Only CI Skip + Markdown Lint:** `dorny/paths-filter` classifies each PR so doc-only changes skip the slow `api`/`harness` jobs, with an always-running `gate` aggregate (avoids the required-check deadlock) and markdownlint-cli2 added to `fast-checks`.
- **Phase 16 — CI Dependency Audit, Security & Image Hygiene:** Boot-time refuse-to-boot guard + baked `NODE_ENV=production` confining `DEV_AUTH_BYPASS` to dev; `pnpm audit` gate with GHSA waiver allowlist + tiered outdated report; eslint-plugin-security; gitleaks (clean 613-commit baseline) + `.dockerignore`; publish-time image-hygiene assertions. SEC/DEP/IMG/CI-03.
- **Phase 17 — UI Optimization & Polish:** Fixed the long-standing phone BottomTabBar/FAB overlap (with a CI regression guard), shipped the real FamilySync logo + full favicon/PWA-icon set + brand accent, restructured `tokens.css` into a themeable semantic-token layer (light-only groundwork), and added a logout control + desktop-centered sheets + admin toasts.
- **Phase 18 — Auto Timezone Detection:** Made the household timezone an explicit, stored, browser-auto-detected, admin-changeable setting (`getHouseholdTimezone(db)` + IANA validation), routing the all-day "9 AM local" reminder computation through it instead of the implicit `process.env.TZ`.
- **Phase 19 — Local Auth (No-OIDC Mode):** Full local username/password account model (scrypt + stateless `local-session` JWT cookie, `local_credentials` table, rate-limit/lockout, login/logout, admin create/reset, self-change, OIDC-link, break-glass CLI) coexisting with the Authelia OIDC path — removing the hard dependency on a deployed Authelia.
- **Phase 20 — Admin Member Editor & Form Declutter:** Replaced per-row Rotate/Reset buttons with a single tappable member-editor sheet (display name + local password + app password) over a new `PATCH /api/admin/members/:id` with a last-admin guard, and collapsed the Add-member form — retiring the confusing "Rotate" copy.
**Requirements:** 17/17 v1.1 requirements complete (TEST, CI, CAL, ADMIN, NOTIF, SETUP). Phases 1320 were driven by decision contracts (D-IDs / AUTH-LOCAL-*) rather than REQ-IDs. Deferred to backlog: self-service onboarding (999.5), provider abstraction (999.1), multiple reminders per event (v1.2), dark mode / theming (999.20), modern styling refresh (999.21).
**Known deferred items at close:** none carried — all phase verifications (incl. Phase 11 & 17 human-needed checks) confirmed by the operator at close.
---
## v1.0 MVP (Shipped: 2026-06-10)
**Scope:** 6 phases, 42 plans, 68 tasks. Shipped via Gitea PR #1 (`gsd/v1.0-milestone``main`, 375 commits).
**Delivered:** A self-hosted, Dockerized family-organization PWA on the household's existing Fastmail account — unified color-coded calendar (shared + personal) with full event CRUD written back via CalDAV, installable PWA, shared collaborative lists with real-time co-edit sync, and Web Push notifications — usable cross-ecosystem with no app store.
**Key accomplishments:**
- **Phase 1 — Foundation + Broker Spike:** Authelia OIDC sessions with stable per-member identity (iss+sub) + auto-assigned color, AES-256-GCM credential encryption, and a tsdav CalDAV broker reading Fastmail calendars. CAL-08 resolved **GO** (per-member app-password model — no cross-account ACL).
- **Phase 2 — Calendar Display:** Unified color-coded calendar across day/week/month/agenda with server-side occurrence expansion (VTIMEZONE/DST, all-day, EXDATE), each member's events in their assigned color.
- **Phase 3 — Event Write-Back + PWA Install:** Full event CRUD written back to Fastmail (enqueue-only outbox, 202 optimistic-accept), installable PWA with auth-safe service worker and guided iOS install. Taken live over real Authelia/Pangolin and verified end-to-end on desktop and iOS.
- **Phase 4 — Shared Lists + Live Sync:** Named collaborative lists with item CRUD, fractional-rank drag-reorder, and real-time SSE co-edit sync — member-scoped with no cross-tenant leak proven at the route layer.
- **Phase 5 — Web Push Notifications:** VAPID push for event reminders, event-change alerts, and coalesced list-change notifications; resilient `setInterval` broker workers (poller/outbox/reminder) with catch-up + per-uid exactly-once dedup.
- **Phase 6 — UX Polish:** All-day visual distinction, duration-preserving event end-tracking, RRULE UNTIL/COUNT bounding + whole-series edit prompt, pre-auth AuthSplash gating, session-expiry interstitial, and persistent nav chrome.
**Requirements:** 20/20 v1 requirements complete (AUTH, CAL, PWA, LIST, NOTIF). Deferred out of scope: CAL-09…CAL-12 (v1.x), DISP-01/DISP-02 (v2).
**Known deferred items at close** (acknowledged, device-only / live-infra — not regressions):
- Phase 01 Gate-2 live checks (Authelia OIDC over Pangolin, iOS standalone install/redirect, session persistence) — carried under D-14; spot-check at go-live.
- Phase 06 iOS device-only residuals: standalone cold-load + OIDC redirect (D-10/D-11), PushPermissionPrompt spinner (CP-04.3).
- Android event-change push: server-side FCM delivery proven (201); on-device confirmation + operator channel-importance bump pending (05-UAT Test 4).
- Stale `kickoff-new-project` todo (superseded; archived during 2026-06-10 backlog review).
---