The card consumed the API directly via useVerifyMfa() (TanStack Query mutation). Per Decision F's intent (store owns business logic, the component consumes typed results), the card now calls useAuthStore.verifyMfa() and pattern-matches on the MfaVerifyResult discriminated union. Changes: - MfaChallengeCard: drop useVerifyMfa import; call authStore.verifyMfa with camelCase args (sessionToken, trustDevice, deviceFingerprint, deviceName); local isVerifying ref replaces verifyMutation.isPending. On result.kind === 'authenticated' emit `verified` (no payload — the store has already refreshed user state); on 'failed' surface result.reason with a generic fallback. - emit signature: `verified: [data: unknown]` → `verified: []`. - login.vue: onMfaVerified no longer calls authStore.refreshUser — authStore.verifyMfa() refreshes internally. Page just routes to resolvePostLoginTarget(). Adds 4 vitest specs in components/auth/__tests__/MfaChallengeCard.spec.ts covering: success path emits `verified` with camelCase args, failure path shows reason and suppresses emit, trustDevice toggle honours fingerprint + device name, fallback message when reason is empty. Test count 209 → 213. Lint + typecheck clean. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Crewli — Organizer SPA
Main product UI for organisation and event staff (Vue 3 + Vuexy + Vuetify). Lives in this repo; only re-copy from Vuexy when upgrading the template.
Setup
- Install dependencies:
pnpm install
- Create
.env.local:
VITE_API_URL=http://localhost:8000/api/v1
VITE_APP_NAME="Crewli Organizer"
- Dev server uses port 5174 (see
vite.config.tsor run from repo root:make app).
pnpm dev --port 5174
Port
Runs on http://localhost:5174
Production: e.g. VITE_API_URL=https://api.crewli.app/api/v1 and host the SPA at https://crewli.app (see api/.env.example for FRONTEND_APP_URL and SANCTUM_STATEFUL_DOMAINS).