Feature 0002 — Auth & Design System
Establish a custom Flutter design system (built on Material 3) and ship the first auth slice (Supabase email + password) for the Treeper mobile app.
Decisions
Section titled “Decisions”- State management: flutter_bloc (app-wide
AuthBloc, page-scoped Cubits) - Routing: go_router with
refreshListenabledriven byAuthBloc.stream - Backend: supabase_flutter (built-in secure session persistence)
- Display font: Sora (Google Fonts)
- Body font: Inter (Google Fonts)
- Auth flows in scope: sign-up, sign-in, forgot-password, sign-out, session restore
- Out of scope: magic link, OAuth, profile, onboarding, RLS
Design tokens (extracted from reference screenshots)
Section titled “Design tokens (extracted from reference screenshots)”- Surfaces: sage
#DCE8D2, cream#F3EEE2, card#FFFFFF - Primary: forest
#13251A(dark CTAs, nav) - Accent: lime
#C5E04A(highlight CTAs, calendar selected, ticket band) - Text: primary
#0F1A12, muted#6B7A6F, onDark#FFFFFF - Border subtle:
#E6E1D4 - Spacing: 4 / 8 / 12 / 16 / 20 / 24 / 32 / 40
- Radii: sm 8, md 16, lg 24, xl 32, pill 999
- Motion: fast 120ms, base 220ms, slow 360ms, easeOutCubic
Components (build order)
Section titled “Components (build order)”AppSurface(sage / cream)AppPillButton(primary / accent / ghost)AppTextField(rounded pill input + password toggle)AppCircleIconButton(white / dark / accent)AppChip(active / inactive with leading icon)AppInfoPill(icon + label)AppSegmented(One way / Round trip style)AppCard(image card with scrim)AppAvatarStackAppBottomNavAppLoadingPillAppWeatherChipAppCountryLabel
Architecture
Section titled “Architecture”lib/ app/ # bootstrap, MaterialApp.router, root BlocProvider core/ router/ # GoRouter, AuthRefreshListenable, route names error/ # AppFailure design_system/ tokens/ theme/ components/ showcase/ features/ auth/ data/ # AuthRepository, SupabaseAuthRepository domain/ # AuthUser, AuthFailure bloc/ # AuthBloc, SignInCubit, SignUpCubit, ForgotPasswordCubit view/ # splash, sign_in, sign_up, forgot_password home/ # auth-gated stubAuth state machine
Section titled “Auth state machine”AuthState.unknown(initial) → splashAuthState.authenticated(user)→ homeAuthState.unauthenticated→ sign-in Driven bySupabase.instance.client.auth.onAuthStateChange.
Routing
Section titled “Routing”/splash(initial),/sign-in,/sign-up,/forgot-password,/home/dev/showcaseexposed in debug builds onlyredirectrule:unknown→/splashunauthenticated+ protected →/sign-inauthenticated+ auth route →/home
Config & secrets
Section titled “Config & secrets”--dart-define=SUPABASE_URL=… --dart-define=SUPABASE_ANON_KEY=…apps/mobile/.env.examplelists required keys- No secrets committed; anon key only in build args
Increments
Section titled “Increments”- Tokens + theme + AppSurface + AppPillButton + AppTextField + showcase route ← Phase 1
- AppCircleIconButton, AppChip, AppInfoPill, AppSegmented added to showcase
- Supabase bootstrap (env, init, connectivity test)
- AuthRepository + SupabaseAuthRepository + tests
- AuthBloc + tests
- GoRouter + redirect + splash + home stub
- Sign-in page + SignInCubit
- Sign-up + forgot-password pages
- Polish: error snackbars, loading states, golden test for AppPillButton
Verification per increment
Section titled “Verification per increment”- 1–2: visual via showcase route on simulator
- 3: connectivity smoke test on simulator
- 4–5: unit tests with mocktail / bloc_test
- 6–9: widget tests + manual smoke (sign-up → home, sign-out → sign-in, kill app → session restored)
Open follow-ups
Section titled “Open follow-ups”- Password-reset deep link (URL scheme
io.supabase.treeper://reset) — wire when forgot-password page lands - Email confirmation flow toggle (dev: off, prod: on)
- RLS policies — deferred until first user-owned table arrives