|
46 | 46 |
|
47 | 47 | --- |
48 | 48 |
|
| 49 | +## Milestone: v2.1 — Email Auth |
| 50 | + |
| 51 | +**Shipped:** 2026-03-02 |
| 52 | +**Phases:** 5 | **Plans:** 10 | **Sessions:** ~5 |
| 53 | + |
| 54 | +### What Was Built |
| 55 | +- Email/password signup with 6-digit OTP verification via branded Lumio email templates |
| 56 | +- Email login with progressive disclosure UX (Google OAuth on top, email below separator) |
| 57 | +- Password reset with two-phase OTP-then-password screen and global session invalidation |
| 58 | +- Bidirectional account linking (Google ↔ email) with single-identity unlink protection |
| 59 | +- Provider-aware database trigger for email signups (display_name from email prefix) |
| 60 | +- 71 auth i18n keys in IT/EN with DeepStringify compile-time validation |
| 61 | + |
| 62 | +### What Worked |
| 63 | +- OTP over deep link was the right choice for Android — no deep link infrastructure needed, more reliable |
| 64 | +- Progressive disclosure pattern reduces cognitive load on login screen |
| 65 | +- Recovery state machine with AsyncStorage survives app restarts elegantly |
| 66 | +- addPasswordModeRef pattern cleanly separates "add password" from "forgot password" OTP flows |
| 67 | + |
| 68 | +### What Was Inefficient |
| 69 | +- Dead else branch in ForgotPasswordScreen.tsx error handling — both paths set same error message (minor tech debt) |
| 70 | +- Multiple quick tasks (5, 6, 8, 9) needed post-milestone for production issues — could benefit from more thorough UAT before shipping |
| 71 | + |
| 72 | +### Patterns Established |
| 73 | +- Provider-aware trigger using `raw_app_meta_data->>'provider'` with COALESCE default |
| 74 | +- Guard pattern: `hasPreviousSignIn()` before `GoogleSignin.signOut()` for mixed-auth users |
| 75 | +- Two-phase screen pattern: single component handles both OTP entry and action (password set, verification) |
| 76 | +- Ref-based flow suppression (`addPasswordModeRef`) to prevent auth event handler interference |
| 77 | + |
| 78 | +### Key Lessons |
| 79 | +1. OTP is more reliable than deep links on Android — less infrastructure, fewer failure modes |
| 80 | +2. Auth flows need extensive real-device testing — several quick fixes were needed post-ship |
| 81 | +3. Provider-aware triggers with explicit detection are cleaner than implicit auth.users field checks |
| 82 | +4. Global session invalidation on password change is a security best practice worth the UX cost |
| 83 | + |
| 84 | +### Cost Observations |
| 85 | +- Model mix: 80% opus, 20% sonnet (quality profile) |
| 86 | +- Sessions: ~5 (4 days of development) |
| 87 | +- Notable: 5 phases, 10 plans, 16 requirements — largest milestone since v1.1, all satisfied |
| 88 | + |
| 89 | +--- |
| 90 | + |
| 91 | +## Milestone: v2.2 — Session Limits |
| 92 | + |
| 93 | +**Shipped:** 2026-03-05 |
| 94 | +**Phases:** 2 | **Plans:** 2 | **Sessions:** ~2 |
| 95 | + |
| 96 | +### What Was Built |
| 97 | +- RPC `get_study_cards_for_session` enforces total card cap with overdue-first priority (IF/ELSE plpgsql for NULL vs capped p_limit) |
| 98 | +- RPC `get_due_card_count` returns session-aware count via LEAST(total, p_limit) for dashboard |
| 99 | +- Dashboard counter reflects session-limited card count reactively via useStudySettings |
| 100 | +- CardsPerSession type renamed from 'all' to 'auto' with backward-compatible AsyncStorage migration |
| 101 | +- Settings selector shows "Auto" with sparkles icon |
| 102 | + |
| 103 | +### What Worked |
| 104 | +- Minimal milestone scope (2 phases, 5 requirements) — shipped in 2 days with zero deviations |
| 105 | +- Nullable RPC parameter pattern (p_limit DEFAULT NULL) from Phase 32 reused immediately in Phase 33 |
| 106 | +- LEAST(total, p_limit) was simpler than duplicating query logic for the count RPC |
| 107 | +- Audit passed cleanly: 5/5 requirements, 8/8 integration checks, 3/3 E2E flows |
| 108 | + |
| 109 | +### What Was Inefficient |
| 110 | +- Nothing notable — clean execution from start to finish |
| 111 | + |
| 112 | +### Patterns Established |
| 113 | +- Nullable RPC parameters: pass null from TS, PostgreSQL uses DEFAULT NULL for unlimited behavior |
| 114 | +- AsyncStorage backward-compat migration: read old value, return new enum value silently |
| 115 | +- LEAST-based capping for scalar count RPCs (simpler than IF/ELSE when only capping a result) |
| 116 | + |
| 117 | +### Key Lessons |
| 118 | +1. Small, focused milestones (2 phases) execute cleanly with near-zero overhead |
| 119 | +2. Reusing RPC patterns across phases in the same milestone accelerates development |
| 120 | +3. "Auto" as universal label (no translation needed) simplifies i18n |
| 121 | + |
| 122 | +### Cost Observations |
| 123 | +- Model mix: 80% opus, 20% sonnet (quality profile) |
| 124 | +- Sessions: ~2 (2 days) |
| 125 | +- Notable: Smallest milestone since v1.5 — 2 phases, 2 plans, 4 tasks, ~6 minutes total execution |
| 126 | + |
| 127 | +--- |
| 128 | + |
49 | 129 | ## Cross-Milestone Trends |
50 | 130 |
|
51 | 131 | ### Process Evolution |
52 | 132 |
|
53 | 133 | | Milestone | Sessions | Phases | Key Change | |
54 | 134 | |-----------|----------|--------|------------| |
55 | 135 | | v2.0 | ~4 | 4 | First milestone with audit-before-complete workflow; gap closure pattern | |
| 136 | +| v2.1 | ~5 | 5 | Largest since v1.1; post-ship quick fixes revealed UAT gaps | |
| 137 | +| v2.2 | ~2 | 2 | Cleanest milestone — zero deviations, zero issues | |
56 | 138 |
|
57 | 139 | ### Cumulative Quality |
58 | 140 |
|
59 | 141 | | Milestone | Tests | Coverage | Zero-Dep Additions | |
60 | 142 | |-----------|-------|----------|-------------------| |
61 | 143 | | v2.0 | 10 (SM-2 unit) | SRS module only | supermemo@2.0.23, vitest@4.0.18 | |
| 144 | +| v2.1 | — | Auth flows (manual) | — | |
| 145 | +| v2.2 | — | Session limit (manual) | — | |
62 | 146 |
|
63 | 147 | ### Top Lessons (Verified Across Milestones) |
64 | 148 |
|
65 | 149 | 1. Research-first planning pays off — prevents mid-milestone pivots (validated v1.1 through v2.0) |
66 | | -2. Server-side computation for stateful operations avoids race conditions and simplifies client code (v2.0) |
| 150 | +2. Server-side computation for stateful operations avoids race conditions and simplifies client code (v2.0, v2.2) |
67 | 151 | 3. Small gap closure plans are more efficient than trying to get everything right in the first pass (v2.0) |
| 152 | +4. Small, focused milestones execute cleanly with near-zero overhead (v2.2) |
| 153 | +5. Reusing patterns across phases in the same milestone accelerates development (v2.2) |
0 commit comments