Initial Commit
This commit is contained in:
122
openspec/changes/enterprise-r3f-booking/proposal.md
Normal file
122
openspec/changes/enterprise-r3f-booking/proposal.md
Normal file
@@ -0,0 +1,122 @@
|
||||
# OpenSpec Change: enterprise-r3f-booking
|
||||
|
||||
- **Change ID**: enterprise-r3f-booking
|
||||
- **Package**: `@suaveplan/r3f-booking`
|
||||
- **Category**: r3f/commerce
|
||||
- **Target path**: `r3f/commerce/r3f-booking`
|
||||
- **Status**: PROPOSED
|
||||
- **Date**: 2026-04-24
|
||||
- **Reference spec**: `/mnt/s/web/suaveplan/enterprise/r3f-booking.md`
|
||||
|
||||
---
|
||||
|
||||
## Summary
|
||||
|
||||
Deliver `@suaveplan/r3f-booking` on the genesis branch from scratch at enterprise quality. The package provides interactive 3D venue maps for seat/space booking — concert halls, stadiums, offices, conference rooms. It ships `<VenueMap />`, `<VenueSeat />`, `<VenueSection />`, `<VenueFloorPlan />`, and a `useVenueSelection` hook. Seats have availability states (available/reserved/selected/disabled), animated selection feedback, accessible keyboard navigation, and a JSON venue schema for data-driven layout. Storybook stories for every component; Vitest + `@testing-library/react` tests.
|
||||
|
||||
---
|
||||
|
||||
## Current-state audit (genesis)
|
||||
|
||||
Does not exist on genesis — fresh build.
|
||||
|
||||
---
|
||||
|
||||
## Available workspace deps on genesis
|
||||
|
||||
Same R3F + React stack as `enterprise-r3f-earth`, plus no additional deps.
|
||||
|
||||
---
|
||||
|
||||
## Public API surface
|
||||
|
||||
```tsx
|
||||
function VenueMap(props: VenueMapProps): JSX.Element
|
||||
function VenueFloorPlan(props: VenueFloorPlanProps): JSX.Element
|
||||
function VenueSection(props: VenueSectionProps): JSX.Element
|
||||
function VenueSeat(props: VenueSeatProps): JSX.Element
|
||||
function useVenueSelection(options: UseVenueSelectionOptions): VenueSelectionState
|
||||
|
||||
interface VenueMapProps {
|
||||
venue: VenueDefinition
|
||||
selectedSeats?: string[]
|
||||
onSeatSelect?: (seatId: string) => void
|
||||
onSeatDeselect?: (seatId: string) => void
|
||||
maxSelectable?: number
|
||||
colorScheme?: VenueColorScheme
|
||||
cameraControls?: boolean
|
||||
}
|
||||
|
||||
interface VenueDefinition {
|
||||
id: string
|
||||
name: string
|
||||
sections: SectionDefinition[]
|
||||
}
|
||||
|
||||
interface SectionDefinition {
|
||||
id: string
|
||||
label: string
|
||||
rows: RowDefinition[]
|
||||
color?: string
|
||||
position: { x: number; y: number; z: number }
|
||||
rotation?: number
|
||||
}
|
||||
|
||||
interface RowDefinition {
|
||||
id: string
|
||||
label: string
|
||||
seats: SeatDefinition[]
|
||||
}
|
||||
|
||||
interface SeatDefinition {
|
||||
id: string
|
||||
label: string
|
||||
status: 'available' | 'reserved' | 'disabled'
|
||||
category?: string
|
||||
price?: number
|
||||
}
|
||||
|
||||
type VenueSelectionState = {
|
||||
selected: string[]
|
||||
select: (seatId: string) => void
|
||||
deselect: (seatId: string) => void
|
||||
clear: () => void
|
||||
isSelected: (seatId: string) => boolean
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## File layout
|
||||
|
||||
```text
|
||||
r3f/commerce/r3f-booking/
|
||||
package.json
|
||||
tsconfig.json
|
||||
vitest.config.ts
|
||||
src/
|
||||
index.ts
|
||||
error-codes.ts
|
||||
types/
|
||||
r3f-booking.types.ts
|
||||
r3f-booking.types.md
|
||||
components/
|
||||
venue-map/ (tsx + md + types + test + stories + index)
|
||||
venue-floor-plan/ ...
|
||||
venue-section/ ...
|
||||
venue-seat/ ...
|
||||
hooks/
|
||||
use-venue-selection/
|
||||
use-venue-selection.ts / .md / .test.ts / index.ts
|
||||
schemas/
|
||||
venue-schema/
|
||||
venue-schema.ts / venue-schema.md / venue-schema.test.ts / index.ts
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Impact
|
||||
|
||||
Downstream: booking UI, event ticketing, office space booking.
|
||||
|
||||
**Prerequisites on Verdaccio**: `@suaveplan/error`, `@suaveplan/types`, `@suaveplan/logger`.
|
||||
62
openspec/changes/enterprise-r3f-booking/tasks.md
Normal file
62
openspec/changes/enterprise-r3f-booking/tasks.md
Normal file
@@ -0,0 +1,62 @@
|
||||
# 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 status` reports nothing) and no in-flight worktrees with uncommitted work (`git worktree list` then `git status` in 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.md` matches `find packages -maxdepth 3 -name package.json` count. Drift here means a prior change archived without regenerating the manifest.
|
||||
|
||||
## 1. Scaffold
|
||||
|
||||
- [ ] Create directory tree per `proposal.md`.
|
||||
- [ ] `package.json` at `0.1.0`, `"sideEffects": false`, exports `"."` + component + hook + schema subpaths.
|
||||
- [ ] Same dep stack as `enterprise-r3f-earth` (R3F + React stack).
|
||||
- [ ] `tsconfig.json` extending `react-library.json`; `vitest.config.ts` with 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`) in `src/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`: export `parseVenueDefinition(data: unknown): VenueDefinition` using 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 `useVenueSelection` in `src/hooks/use-venue-selection/use-venue-selection.ts`:
|
||||
- `useState<string[]>` for selected seats.
|
||||
- `select(seatId)`: add if `maxSelectable` not exceeded; throw `R3F_BOOKING_MAX_SELECTION` otherwise.
|
||||
- `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 by `status` (green/red/grey/blue for selected); hover highlight; click → `onSeatSelect`/`onSeatDeselect`; keyboard aria-label.
|
||||
- `VenueSection`: grid of `VenueSeat` components laid out from `RowDefinition[]`; section label via `<Html>`.
|
||||
- `VenueFloorPlan`: flat 2D orthographic view showing all sections.
|
||||
- `VenueMap`: 3D perspective view wrapping all sections in a `<Canvas>` with `OrbitControls`.
|
||||
- [ ] Write `.test.tsx` for 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 `.md` per 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 to `openspec/archive/2026-04-24-enterprise-r3f-booking/`.
|
||||
Reference in New Issue
Block a user