- Extract generateIdempotencyKey() from useFormDraft into reusable lib/
- New types/timetable.ts mirrors PerformanceResource, ArtistEngagementResource,
StageResource, GenreResource and the four enums verbatim
- New schemas/timetable.ts adds zod parsers for runtime validation of API
responses + form payloads (createPerformance, createStage, moveTimetable)
RFC v0.2 §10 contract surface for the upcoming timetable canvas.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Composables (apps/portal/src/composables → apps/app/src/composables/):
- useFormDraft, publicFormInjection → composables/ (root, used by
shared/public-form components)
- api/usePublicForm, api/usePublicFormSections,
api/usePublicFormTimeSlots → composables/api/ (no collisions)
- api/usePortalShifts, api/usePortalProfile, api/useVolunteerRegistration
→ composables/api/portal/ (subfolder per WS-3 PR-B1 charter to
leave room for organizer-side namesakes without clashes)
- api/useMfa → DELETED (apps/app version is a strict superset
with extra invalidateQueries calls and the admin-reset mutation)
Types (apps/portal/src/types → apps/app/src/types/):
- api, portal-shift, portal, registration → moved
- mfa → DELETED (byte-identical to apps/app/src/types/mfa.ts)
Schemas:
- apps/portal/src/schemas/registrationSchema.ts → apps/app/src/schemas/
Utils:
- deviceFingerprint, paginationMeta → DELETED (byte-identical
duplicates already in apps/app/src/utils/)
Lib:
- apps/portal/src/lib/{axios,query-client}.ts → DELETED. apps/app's
callback-bound axios (post-PR-A) and query-client are the
canonical versions. Portal pages currently importing
`@/lib/axios#apiClient` resolve to apps/app's apiClient with no
behavioral change for cookie-based requests.
Tests: 4 composable specs (useFormDraft x2, usePublicFormSections,
usePublicFormTimeSlots) moved into __tests__/ subdirs alongside
their composables.
@form-schema imports inside the moved files rewritten to
@/composables/forms/*.
Vitest now: 23 files / 162 tests passing.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>