3.9 KiB
3.9 KiB
Tasks: enterprise-r3f-booking
Change ID: enterprise-r3f-booking
Package: @suaveplan/r3f-booking
Target path: r3f/commerce/r3f-booking
Prerequisites on Verdaccio: @suaveplan/error, @suaveplan/types, @suaveplan/logger
0. Pre-flight (non-negotiable)
- 0.1 Confirm clean working tree (
git statusreports nothing) and no in-flight worktrees with uncommitted work (git worktree listthengit statusin each) - 0.2 If any worktrees exist under
.claude/worktrees/, account for each one: still-active agent, work-pending-merge, or stale-and-prune. Stale worktrees MUST be removed (git worktree remove) before opening a new one — code that has been lost twice on main is the failure mode this guards against. - 0.3 Confirm the package set in
MANIFEST.mdmatchesfind packages -maxdepth 3 -name package.jsoncount. Drift here means a prior change archived without regenerating the manifest.
1. Scaffold
- Create directory tree per
proposal.md. package.jsonat0.1.0,"sideEffects": false, exports"."+ component + hook + schema subpaths.- Same dep stack as
enterprise-r3f-earth(R3F + React stack). tsconfig.jsonextendingreact-library.json;vitest.config.tswith jsdom,pool: 'forks',fileParallelism: false.- Scripts:
lint,typecheck,test,test:coverage,build,docs:check.
2. Types, errors, and venue schema
- Define all interfaces and Zod schemas (
VenueDefinitionSchema,SectionDefinitionSchema,RowDefinitionSchema,SeatDefinitionSchema) insrc/types/r3f-booking.types.ts. - Write
r3f-booking.types.md(≥200 words). src/error-codes.ts:R3F_BOOKING_INVALID_VENUE,R3F_BOOKING_SEAT_NOT_FOUND,R3F_BOOKING_MAX_SELECTION; eager registration.- Implement
src/schemas/venue-schema/venue-schema.ts: exportparseVenueDefinition(data: unknown): VenueDefinitionusing Zod; throw typed error on parse failure. - Write
venue-schema.test.ts: valid full venue; missing required field; invalid seat status.
3. useVenueSelection hook
- Implement
useVenueSelectioninsrc/hooks/use-venue-selection/use-venue-selection.ts:useState<string[]>for selected seats.select(seatId): add ifmaxSelectablenot exceeded; throwR3F_BOOKING_MAX_SELECTIONotherwise.deselect(seatId)/clear()/isSelected(seatId).
- Write
use-venue-selection.test.ts: select/deselect/clear/isSelected; maxSelectable enforcement. - Write
use-venue-selection.md(≥200 words).
4. Components
For each of VenueSeat, VenueSection, VenueFloorPlan, VenueMap:
- Implement the R3F component:
VenueSeat: a<Box>mesh positioned in 3D space; color bystatus(green/red/grey/blue for selected); hover highlight; click →onSeatSelect/onSeatDeselect; keyboard aria-label.VenueSection: grid ofVenueSeatcomponents laid out fromRowDefinition[]; section label via<Html>.VenueFloorPlan: flat 2D orthographic view showing all sections.VenueMap: 3D perspective view wrapping all sections in a<Canvas>withOrbitControls.
- Write
.test.tsxfor each: renders without crash; seat click fires callback; reserved seat click does nothing;{ timeout: 5000 }. - Write
.stories.tsx: default + playground + variants (e.g. concert hall vs office floor). - Write
.mdper component (≥200 words).
5. Docs + verify + publish
- Root
README.md: quick-start with sample venue JSON, selection hook example, component API table. bunx turbo lint --filter=@suaveplan/r3f-booking— zero errors.bunx turbo typecheck --filter=@suaveplan/r3f-booking— zero errors.bunx turbo test --filter=@suaveplan/r3f-booking— all pass.bunx turbo test:coverage --filter=@suaveplan/r3f-booking— 100%.bun scripts/publish.ts --package @suaveplan/r3f-booking.- Update
CLAUDE.md; archive toopenspec/archive/2026-04-24-enterprise-r3f-booking/.