Commit Graph

5 Commits

Author SHA1 Message Date
473b22ac9e feat(router): context-aware guards with meta-driven role/context resolution
Rewrites plugins/1.router/guards.ts per ARCH-CONSOLIDATION §4.3. The
B1 portal-context carve-out is removed; portal/organizer routing is
now declarative via meta.context, role gates via meta.requiresRole.

Guard pipeline:
1. Initialize auth store on first navigation
2. Public routes pass through (authenticated user on guest-only path
   is bounced to resolveLandingRoute)
3. Auth required → /login?to=<path>
4. MFA setup gate → /account-settings?tab=security
5. requiresRole declarative check (replaces hardcoded /platform path
   prefix + isSuperAdmin)
6. Context routing — portal returns early, organizer falls through
   and sets lastContext
7. Org-selection check (organizer routes only)

Page meta updates (mechanical, idempotent):
- 4 portal pages: removed `requiresAuth: true` (auth is implicit)
- 4 pages: replaced `requiresAuth: false` with `meta.public: true`
  (registreren, wachtwoord-instellen, advance/[token],
  invitations/[token])
- 22 organizer pages: added `context: 'organizer'`
  (account-settings, events/**, organisation/form-failures/**,
  select-organisation, dashboard, events/index, members,
  organisation/{index,companies,settings})
- 8 platform pages: added `context: 'organizer'` +
  `requiresRole: 'super_admin'`
- 6 organizer pages had no definePage block — one was added with
  `context: 'organizer'`

Adds plugins/1.router/__tests__/guards.spec.ts (11 tests) covering
public passthrough, unauthenticated redirect, portal/organizer
context branching, declarative requiresRole, org-selection
redirect, MFA gate.

Test count 178 → 189 (11 new). Lint + typecheck clean.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-05 21:32:54 +02:00
47bd533179 style(app): apply eslint --fix to Tier 1 (Vue templates)
WS-3 session 1b-i Tier 1.

Scope: src/components/**, src/pages/**, src/layouts/**, src/views/**
restricted to *.vue files. Mechanical formatting only — predominantly
vue/html-indent (506 fixes in CrowdListDetailPanel.vue alone),
padding-line-between-statements, antfu/if-newline.

Excludes (per session prompt):
- apps/app/vite.config.ts (Tier 3)
- apps/app/themeConfig.ts (Tier 3)
- apps/app/vitest.config.ts (Tier 3)
- All TypeScript-only files in src/composables, src/lib, src/stores,
  src/plugins, src/types (Tier 2 — separate commit)

Includes session 1a layouts (PortalLayout.vue, PublicLayout.vue) where
2 'lines-around-comment' errors were flagged in the previous 1b-i
pre-flight inspection.

Tests + typecheck verified green post-fix:
- apps/app vitest: 49 passed (unchanged)
- apps/app vue-tsc: clean (unchanged)
- apps/portal vitest: 113 passed (unchanged — not touched)
- backend pest: 1486 passed (unchanged — not touched)

Lint baseline progression:
- Pre-Tier-1: 1451 problems
- Post-Tier-1: 422 problems

Visual smoke status:
- NOT YET SMOKED — Bert to verify before merge. This Claude Code
  session has no UI access; cannot run pnpm dev and click through
  affected routes. The high-traffic candidates are
  CrowdListDetailPanel (506 fixes), AssignPersonDialog (44),
  ShiftDetailPanel (36), and the events / form-failures pages.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-29 11:04:46 +02:00
cd2c775692 fix: eliminate all TypeScript any usage across Vue components
Replace 24 `err: any` error handler types with proper `AxiosError<ApiErrorResponse>`
typing. Fix additional `as any` casts and `Record<string, any>` patterns in registration
field components, event settings, and portal layout. Create shared `ApiErrorResponse`
type for portal app.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-15 21:54:01 +02:00
513ca519b2 security: migrate auth tokens to httpOnly cookies (hybrid bearer token approach)
Backend:
- CookieBearerToken middleware reads httpOnly cookie and injects Authorization
  header before Sanctum validates (prepended to API middleware group)
- SetAuthCookie trait provides cookie creation/expiry helpers with per-app
  cookie names (crewli_admin_token, crewli_app_token, crewli_portal_token)
- LoginController sets token via Set-Cookie, removes it from JSON body
- LogoutController expires the auth cookie on logout
- AuthRefreshController (POST /auth/refresh) rotates tokens with new cookie
- InvitationController accept also sets token via cookie, not JSON body
- All cookies: httpOnly, SameSite=Strict, Secure (in production)

Frontend (all three SPAs):
- Removed all localStorage token storage (apps/app, apps/portal)
- Removed all JS-readable cookie token storage (apps/admin)
- Removed Authorization: Bearer header interceptors from axios
- Auth stores now rely on GET /auth/me to validate httpOnly cookie
- Admin app: new Pinia auth store replaces useCookie-based auth pattern
- withCredentials: true ensures browser sends cookies automatically

Fixes security findings A13-1 (localStorage tokens) and A13-2 (admin
cookie flags). Tokens are now invisible to JavaScript.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-14 16:06:44 +02:00
230e11cc8d feat: frontend member management
- Leden pagina met VDataTable, rol chips, uitnodigingen sectie
- InviteMemberDialog + EditMemberRoleDialog
- Publieke acceptatiepagina /invitations/[token]
- Router guard uitgebreid met requiresAuth: false support
- MemberCollection backend uitgebreid met volledige pending_invitations lijst
2026-04-08 01:50:38 +02:00