FAS 1b: Progressive onboarding (3-layer flow)

- Add PROGRESSIVE_ONBOARDING feature flag to KNOWN_FLAGS
- Add onboarding_step column to users table (a/b/c)
- New backend endpoints:
  - GET /v1/onboarding/status – check current step + feature flag
  - POST /v1/onboarding/quick-start – complete Step A (goal + precision)
  - POST /v1/onboarding/complete-b – complete Step B (diet, allergens, household)
  - POST /v1/onboarding/complete-c – complete Step C (health profile)
  - POST /v1/onboarding/skip – GDPR-friendly skip
- Refactor mobile onboarding screen into 3 progressive layers
- Update auth store with onboardingStep state
- Update tab layout to only block on Step A
- Update registration to set onboardingStep='a'
- Add i18n keys for Step B/C titles across all 12 locales
- Add Zod validation schemas (quickStartInputSchema, onboardingStatusSchema)
- Add tests for validation and feature flag
- Preserve existing /v1/me/onboarding for backward compatibility
- Migration: 0004_progressive_onboarding.sql
This commit is contained in:
Sven (AAMOS AI)
2026-08-06 00:39:44 +07:00
parent b2b6601f54
commit 2f3cdf8016
24 changed files with 4338 additions and 3837 deletions
+4
View File
@@ -30,6 +30,7 @@ interface AuthState {
accessToken: string | null;
user: AuthUser | null;
onboardingCompleted: boolean;
onboardingStep: "a" | "b" | "c";
hydrate: () => Promise<void>;
setSession: (
tokens: { accessToken: string; refreshToken: string },
@@ -37,6 +38,7 @@ interface AuthState {
) => Promise<void>;
setAccessToken: (token: string) => void;
setOnboardingCompleted: (done: boolean) => void;
setOnboardingStep: (step: "a" | "b" | "c") => void;
getRefreshToken: () => Promise<string | null>;
logout: () => Promise<void>;
}
@@ -46,6 +48,7 @@ export const useAuth = create<AuthState>((set) => ({
accessToken: null,
user: null,
onboardingCompleted: true,
onboardingStep: "a",
hydrate: async () => {
try {
@@ -77,6 +80,7 @@ export const useAuth = create<AuthState>((set) => ({
},
setOnboardingCompleted: (done) => set({ onboardingCompleted: done }),
setOnboardingStep: (step) => set({ onboardingStep: step }),
getRefreshToken: () => SecureStore.getItemAsync(REFRESH_KEY),