WS-3 session 1b-ii Task 3 (audit Bucket B — 34 items: 21 absorbed
via ignorePatterns + 14 real fixes; the count of 21 is the actual
non-Tier-3 lint-count drop from the .eslintrc edit, slightly above
the audit's predicted 20 because additional vendored-Vuexy items
beyond the 23 no-explicit-any landed in those paths too).
Config:
- .eslintrc.cjs: add src/@core/** and src/@layouts/** to ignorePatterns.
Vendored Vuexy code, precedent: src/plugins/iconify/*.js. The
CLAUDE.md no-any rule remains in force for our own code under src/.
Real type-safety fixes:
- B.1 ref<any> in our code (3 occurrences):
* blank.vue / default.vue: AppLoadingIndicator template ref now
typed as InstanceType<typeof AppLoadingIndicator> | null. Picks
up the defineExpose'd fallbackHandle / resolveHandle methods.
* NavSearchBar.vue:109: useApi<any>(...) → useApi<SearchResults[]>(...)
matching the existing searchResult ref type.
- B.2 ShiftDetailPanel.vue: moved the Cancel-dialog ref declarations
(isCancelDialogOpen, cancellingAssignment) from line 305-307 to
line 248 — directly above the onCancel handler that uses them.
Resolves all 7 no-use-before-define items in one move. Same-file,
no logic change.
- B.3 useImpersonationStore.ts:119: renamed inner 'stored' to
'storedSnapshot' to resolve shadowing of the outer 'stored' on
line 18.
- B.4 useFormSchemas.ts:97-99: renamed local mutationFn parameter
'confirmed_name' to camelCase 'confirmedName'. Wire-format key
stays snake_case via destructure-alias:
params: confirmedName ? { confirmed_name: confirmedName } : undefined
No callers found in apps/app/src — safe rename.
Tests + typecheck verified green.
Lint baseline: 97 → 62.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The approve() and bulkApprove() methods in ShiftAssignmentService
hard-blocked with a 422 when all slots were filled. This was incorrect
for organiser actions — only volunteer claims (portal self-service)
should enforce capacity limits. Organiser assign() already allowed
overbooking, making the approve block inconsistent.
Changes:
- Remove capacity hard-block from approve() and bulkApprove(), replace
with audit log entry (shift.overbooked_approval)
- Add overbook confirmation dialog in ShiftDetailPanel before approving
a full shift (single + bulk approve)
- Add onError handlers to all mutations in ShiftDetailPanel (approve,
reject, cancel, bulk-approve) so errors display in the snackbar
- Add global 422 validation error display in axios interceptor via
useNotificationStore as safety net for all components
- Add PHPUnit test for approve-when-full scenario
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Move all authenticated organiser-facing event sub-resource routes from
/events/{event}/... to /organisations/{organisation}/events/{event}/...
to enforce multi-tenancy at the routing layer.
Changes:
- Routes: restructured api.php to nest all event sub-resources under
the existing organisation prefix group
- Controllers: added Organisation parameter and VerifiesOrganisationEvent
trait to all 12 affected controllers (sections, time-slots, shifts,
persons, crowd-lists, locations, shift-assignments, registration-fields,
availabilities, field-values, section-preferences, stats)
- Tests: updated all 20 feature test files with new route paths
- Frontend: updated 8 API composables and 20 Vue components/pages
- API.md: updated documentation to reflect new route structure
Portal routes, public routes (volunteer-register), and invitation routes
remain unchanged as they operate without organisation context.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Cross-cutting migration affecting the entire stack:
- Database: 3 migrations splitting name columns with data migration
- Models: first_name/last_name on User, Person; contact_first_name/contact_last_name on Company; backward-compatible name accessors
- API: all resources return first_name, last_name, full_name; assignablePersons endpoint updated
- Requests: validation rules updated for all person/user/company forms
- Services: VolunteerRegistrationService, ShiftAssignmentService, InvitationService updated
- Frontend: TypeScript types, Zod schemas, all forms split into Voornaam/Achternaam fields
- Display: all person/user name references use full_name; initials use first_name[0]+last_name[0]
- Tests: all 371 tests passing
- Docs: SCHEMA.md and API.md updated
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add cancelled_by, cancellation_source (organiser|volunteer|system), and
cancelled_at columns to shift_assignments. Cancel flow now records who
cancelled and why. Assign flow reactivates existing cancelled/rejected
records instead of creating duplicates, preventing UNIQUE constraint
violations. Assignable-persons endpoint returns previous_assignment data
for contextual UI indicators. Frontend shows cancellation source labels,
previous assignment history in assign dialog, and "Opnieuw toewijzen"
buttons with volunteer-cancelled confirmation dialogs.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add GET /events/{event}/shifts/{shift}/assignable-persons endpoint that
returns approved persons with availability status, conflict details, and
already-assigned flags. Improve ShiftAssignmentService conflict errors to
include section name, time slot, and time range. Replace both assign
dialogs with a new AssignPersonDialog featuring search, crowd type
filtering, availability toggle, and inline conflict warnings.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>