OverviewFilesCommitsIssuesDocsReleasesPeers

hyper-booking commits / 95ccdd7

Initial design: v1 feature spec + auth spec
Paperbell-inspired booking platform for wellness professionals. Payments via hyper-pay (multi-rail), auth from pear-git/hypernote (ANProto ed25519 challenge-response). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
95ccdd735c4dd67be974b062d75736a9dea105b7
by plankatron <fleeky@gmail.com> · 2026-03-22T14:32:31.000Z

Changed files (3) +1043 -0

README.md +48 -0
……@@ -0,0 +1,48 @@
1# hyper-booking
2
3P2P booking platform for wellness professionals — scheduling, payments, client management.
4
5## What is this?
6
7A Paperbell-style booking system built on the Hypercore stack. Providers (coaches, therapists, trainers) get a public booking page, scheduling engine, and client portal. Payments via [hyper-pay](punch://hyper-pay) — multi-rail (Stripe, ACH, stablecoin, P2P).
8
9## Architecture
10
11```
12hyper-booking/
13├── lib/ # Server-side modules
14│ ├── auth/ # Identity & auth (ANProto ed25519, from pear-git/hypernote)
15│ ├── scheduling/ # Availability, booking, calendar engine
16│ ├── packages/ # Package & pricing management
17│ ├── clients/ # Client portal & management
18│ ├── notifications/ # Email, SMS, in-app
19│ ├── forms/ # Intake forms, contracts, surveys
20│ └── routes/ # HTTP API endpoints
21├── web/ # Provider dashboard + client portal UI
22├── widget/ # Embeddable booking widget for external sites
23└── docs/
24 ├── design/ # v1 feature spec & element specs
25 └── research/ # Payment landscape (see hyper-pay)
26```
27
28## Stack
29
30- **Runtime**: Bare / Node.js
31- **Storage**: Hyperbee (structured data), Hypercore (append-only logs)
32- **Networking**: Hyperswarm (P2P replication)
33- **Auth**: ANProto ed25519 keypairs (same as pear-git & hypernote)
34- **Payments**: hyper-pay (Stripe Connect, ACH, USDC, x402, WDK, hyper-wallet)
35- **Deploy**: pear-git CI/CD (`git push pear master`)
36
37## Integration Points
38
39```
40hyper-booking
41├── hyper-pay (payment rails — Stripe, crypto, P2P)
42├── auth system (shared with pear-git, hypernote)
43└── hyper-wallet (optional P2P settlement)
44```
45
46## Status
47
48Design phase. See `docs/design/` for v1 spec.
docs/design/v1-auth.md +330 -0
……@@ -0,0 +1,330 @@
1# hyper-booking v1 — Identity & Auth Spec
2
3Derived from the proven auth systems in pear-git and hypernote.
4Both use the same ANProto ed25519 challenge-response pattern.
5
6---
7
8## Design Principles
9
101. **Anonymous by default** — browse providers, view packages, check slots without identity
112. **Identity at commitment** — keypair created at checkout (not page load)
123. **Passwordless** — ed25519 keypair IS the credential (localStorage)
134. **Stateless** — no cookies, no sessions; every request is signed
145. **Progressive trust** — anonymous → client → provider → admin
156. **Self-sovereign recovery** — attestations allow permission recovery
16
17---
18
19## Auth Architecture
20
21```
22AuthManager (from pear-git/hypernote pattern)
23│
24├── ChallengeManager
25│ ├── Generate random 32-byte challenge
26│ ├── TTL: 5 minutes
27│ ├── One-time use (consumed after verification)
28│ └── Storage: in-memory cache + Hyperbee persistence
29│
30├── Providers (tried in order)
31│ ├── BearerTokenProvider → Authorization header / X-Auth-Token / ?token=
32│ ├── WebIdentityProvider → X-Wirecore-PublicKey + Signature + Challenge
33│ └── KeetIdentityProvider → X-Keet-PublicKey + Signature + Challenge
34│
35├── IdentityRegistry (Hyperbee)
36│ ├── user:{userId} → User object (role, permissions, linked identities)
37│ ├── identity:{identityId} → Identity record (method, credentials, revocation)
38│ ├── pubkey:{publicKey} → Reverse lookup → identityId
39│ └── username:{normalized} → Reverse lookup → userId
40│
41└── RateLimiter (token bucket, per-IP)
42 ├── auth: 1000 tokens, 100/min refill
43 ├── api: 10000 tokens, 1000/min refill
44 ├── booking: 500 tokens, 50/min refill
45 └── checkout: 100 tokens, 10/min refill
46```
47
48---
49
50## Roles
51
52### Anonymous (no identity)
53- View provider profiles
54- View package listings
55- View available time slots
56- Cannot book, purchase, or access portal
57
58### Client
59- Everything anonymous can do
60- Book sessions (after checkout)
61- Access client portal (own bookings, purchases, forms)
62- Reschedule / cancel within policy
63- Fill intake forms, sign contracts
64- Cannot see other clients' data
65
66### Provider
67- Everything client can do
68- Manage own packages, availability, settings
69- View own clients and their bookings
70- Access provider dashboard + analytics
71- Cannot manage other providers
72
73### Admin
74- Everything provider can do
75- Manage all providers (create, enable, disable)
76- Platform-wide analytics
77- Configure platform settings (fees, enabled rails)
78
79---
80
81## Identity Lifecycle
82
83### Client Identity
84
85```
861. Client browses provider page (anonymous)
872. Client selects package + time slot (still anonymous)
883. Client clicks "Book Now" → checkout begins
894. Browser generates ed25519 keypair (client-side, @noble/ed25519)
905. Keypair stored in localStorage:
91 - hyper-booking-keypair: { publicKey (44 base64), secretKey (88 base64) }
926. POST /api/auth/challenge → get challengeId + challenge
937. Client signs challenge with secret key
948. Checkout request includes:
95 - X-Wirecore-PublicKey: <pubkey>
96 - X-Wirecore-Signature: <sig>
97 - X-Wirecore-Challenge: <challengeId>
989. Server auto-registers new identity with role: client
9910. Client optionally sets display name + email (for notifications)
100```
101
102### Provider Identity
103
104```
1051. Provider visits /signup (or is invited by admin)
1062. Same keypair generation as client
1073. Server registers identity with role: provider
1084. First provider on platform → auto-promoted to admin
1095. Subsequent providers → provider role (admin can invite/approve)
110```
111
112### Returning User
113
114```
1151. User visits site
1162. Browser checks localStorage for keypair
1173. If found → auto-authenticate on first API call
1184. If missing → anonymous browsing (show "Sign In" option)
1195. "Sign In" options:
120 a. Import existing keypair (paste JSON)
121 b. Generate new keypair (creates new identity)
122 c. Restore from attestation (if has backup)
123```
124
125---
126
127## Challenge-Response Protocol
128
129Same protocol as pear-git/hypernote:
130
131```
132Client Server
133 │ │
134 ├── GET /api/auth/challenge ──────────────►│
135 │ ├── Generate 32-byte random challenge
136 │ ├── Store: challengeId → { challenge, expiresAt, used: false }
137 │◄──────────── { challengeId, challenge } ─┤
138 │ │
139 ├── sign(challenge, secretKey) ───────────►│ (on every API request)
140 │ Headers: │
141 │ X-Wirecore-PublicKey: <pubkey> │
142 │ X-Wirecore-Signature: <sig> │
143 │ X-Wirecore-Challenge: <challengeId> │
144 │ ├── Verify signature against pubkey
145 │ ├── Consume challenge (mark used)
146 │ ├── Lookup identity by pubkey
147 │ ├── Check role + permissions
148 │◄──────────────────── { response data } ──┤
149 │ │
150
151Challenge caching (client-side):
152- Cache challenge for 4 minutes (expires server-side at 5 min)
153- On 401: clear cache, fetch new challenge, retry once
154```
155
156---
157
158## Permission Checks
159
160### Middleware Functions
161
162```javascript
163// Require any valid identity
164requireAuth(req, res, server)
165
166// Allow anonymous (req.auth may be null)
167optionalAuth(req, res, server)
168
169// Require specific role
170requireRole('provider')
171requireRole('admin')
172
173// Require access to specific resource
174requireClientAccess(clientId) // only own data
175requireProviderAccess(providerId) // only own provider
176```
177
178### Route Examples
179
180```javascript
181// Public — no auth
182GET /api/providers/:slug → optionalAuth
183GET /api/providers/:slug/packages → optionalAuth
184GET /api/providers/:slug/slots → optionalAuth
185
186// Client — must be authenticated
187POST /api/bookings → requireAuth + requireRole('client')
188GET /api/portal/bookings → requireAuth + requireClientAccess(self)
189POST /api/checkout → requireAuth
190
191// Provider — must be provider
192GET /api/dashboard/calendar → requireAuth + requireRole('provider')
193POST /api/packages → requireAuth + requireProviderAccess(self)
194PUT /api/availability → requireAuth + requireProviderAccess(self)
195
196// Admin — must be admin
197POST /api/admin/providers → requireAuth + requireRole('admin')
198GET /api/admin/analytics → requireAuth + requireRole('admin')
199```
200
201---
202
203## Bearer Tokens (API Access)
204
205For integrations, webhooks, and automation:
206
207```javascript
208{
209 tokenHash: sha256(token),
210 userId: 'usr_abc',
211 description: 'Zapier integration',
212 permissions: ['read:bookings', 'write:bookings'],
213 createdAt: timestamp,
214 expiresAt: timestamp | null,
215 lastUsedAt: timestamp
216}
217```
218
219- Created via provider dashboard
220- Sent as `Authorization: Bearer <token>`
221- Scoped permissions (not full provider access)
222- Revocable
223
224---
225
226## Permission Attestations (Recovery)
227
228Same pattern as pear-git — server-signed proof of user permissions:
229
230```javascript
231{
232 version: 1,
233 serverPublicKey: '<hex>',
234 userPublicKey: '<hex>',
235 userId: '<hex>',
236 role: 'provider',
237 permissions: ['read', 'write', 'manage-packages', 'view-clients'],
238 signature: '<ed25519 sig>'
239}
240```
241
242- Auto-fetched after identity creation
243- Stored in localStorage alongside keypair
244- Used for recovery if server loses identity data
245- User proves key ownership via challenge-response
246
247---
248
249## Multi-Provider Client Identity
250
251A single client identity (keypair) can be a client of multiple providers:
252
253```
254Client Identity (pubkey: abc123)
255├── Client of Provider A (coaching)
256│ ├── Purchases: [pkg_1, pkg_2]
257│ └── Bookings: [bk_1, bk_2, bk_3]
258├── Client of Provider B (yoga)
259│ ├── Purchases: [pkg_5]
260│ └── Bookings: [bk_7]
261└── Client of Provider C (therapy)
262 └── (no purchases yet, just browsing)
263```
264
265Client portal shows all providers they're connected to.
266
267---
268
269## Security Considerations
270
271### From pear-git/hypernote (proven in production)
272
2731. **Secret key never leaves browser** — signing is client-side only
2742. **Challenge prevents replay** — each auth request uses unique signed challenge
2753. **Rate limiting** — per-IP token bucket on auth + booking + checkout endpoints
2764. **Auto-registration is conservative** — clients get minimal permissions
2775. **Token hashing** — bearer tokens hashed before storage
2786. **Revocation list** — instant identity revocation via `revoked:` prefix
279
280### Booking-specific additions
281
2827. **Payment isolation** — hyper-pay handles all payment data (PCI scope stays there)
2838. **Client data isolation** — clients can only access own bookings/purchases
2849. **Provider data isolation** — providers can only see their own clients
28510. **Booking rate limits** — prevent slot hoarding (max N pending bookings per client)
28611. **Checkout rate limits** — prevent payment abuse
287
288---
289
290## Shared Code Strategy
291
292### Option A: Copy from hypernote (simpler, v1)
293- Copy `lib/auth/` directory from hypernote
294- Adapt identity registry for booking-specific roles
295- Copy `web/js/identity.js` for browser-side auth
296
297### Option B: Extract shared module (better, v1.1)
298- Create `hyper-auth` shared package
299- Both hypernote and hyper-booking depend on it
300- Single source of truth for auth logic
301
302### Recommendation
303- **v1**: Copy from hypernote (ship faster)
304- **v1.1**: Extract `hyper-auth` once patterns stabilize
305
306---
307
308## Browser Identity Script
309
310Adapted from pear-git/hypernote `identity-ui.js`:
311
312```javascript
313// hyper-booking identity.js
314
315// 1. Load @noble/ed25519 (vendored, zero CDN)
316// 2. Check localStorage for existing keypair
317// 3. Intercept fetch() to inject auth headers
318// 4. On checkout: generate keypair if not exists
319// 5. Challenge cache: 4 min TTL, auto-refresh on 401
320
321const KEYPAIR_KEY = 'hyper-booking-keypair'
322const ATTESTATION_KEY = 'hyper-booking-attestation'
323
324// Same fetch interceptor pattern as pear-git:
325// - Intercept window.fetch()
326// - For /api/* requests: add X-Wirecore-* headers
327// - If 401: refresh challenge, retry once
328```
329
330All crypto libraries vendored locally (zero CDN deps — P2P offline requirement).
docs/design/v1-feature-spec.md +665 -0
……@@ -0,0 +1,665 @@
1# hyper-booking v1 — Feature Spec
2
3Target: MVP booking platform for wellness professionals (coaches, therapists, yoga, massage).
4Inspired by Paperbell ($57/mo, all-in-one coaching platform).
5
6---
7
8## 1. Provider Profile
9
10Public landing page at `/<provider-slug>`.
11
12- Display name, photo, bio, specialties
13- Social links
14- Available packages displayed as cards
15- Custom accent color + logo
16- SEO-friendly (server-rendered HTML)
17
18**Storage**: Hyperbee `provider:{providerId}` → profile object
19
20---
21
22## 2. Packages & Pricing
23
24Providers create packages that clients purchase.
25
26### Package Types
27
28| Type | Description | Example |
29|------|-------------|---------|
30| **Single session** | One-off booking | "60min Massage — $120" |
31| **Multi-session bundle** | N sessions, book individually | "6 Sessions — $500" |
32| **Subscription** | Recurring auto-charge | "Weekly Coaching — $200/mo" |
33| **Discovery call** | Free intro session | "Free 15min Consultation" |
34| **Group session** | Multiple clients, one slot | "Group Yoga — $30/person" |
35
36### Pricing Features
37
38- Pay-in-full discount (e.g., 10% off upfront)
39- Installment plans (split over N months)
40- Sliding scale (client picks price within range)
41- Promo codes / coupons
42- Multi-rail pricing via hyper-pay (provider enables: card, ACH, USDC, P2P)
43
44### Package Object
45
46```javascript
47{
48 id: 'pkg_abc123',
49 providerId: 'prov_xyz',
50 name: '6-Session Coaching Package',
51 description: 'Deep-dive coaching...',
52 type: 'bundle', // single | bundle | subscription | discovery | group
53 sessionCount: 6, // for bundles
54 sessionDuration: 60, // minutes
55 price: 50000, // cents ($500.00)
56 currency: 'USD',
57 installments: 3, // optional: split into 3 payments
58 discountFullPay: 10, // optional: 10% off if paid in full
59 groupCapacity: null, // for group sessions
60 intakeFormId: 'form_abc', // optional
61 contractId: 'ctr_abc', // optional
62 materials: [], // attached files/links
63 active: true,
64 createdAt: timestamp
65}
66```
67
68**Storage**: Hyperbee `package:{packageId}` → package object
69
70---
71
72## 3. Scheduling Engine
73
74The core of the booking system.
75
76### Provider Availability
77
78- **Weekly schedule**: recurring time blocks (e.g., Mon 9am-12pm, 2pm-5pm)
79- **Date overrides**: specific dates with custom hours or marked unavailable (vacations)
80- **Buffer time**: minutes between sessions (default 15min)
81- **Advance booking window**: min/max days ahead (e.g., 2 days to 60 days out)
82- **Session durations**: defined per package (30, 60, 90min, custom)
83
84### Slot Calculation
85
86```
87Available slots = weekly_schedule
88 + date_overrides
89 - existing_bookings
90 - buffer_time
91 filtered by advance_window
92 grouped by session_duration
93```
94
95### Timezone Handling
96
97- Provider sets home timezone
98- Client sees slots in their local timezone (browser `Intl.DateTimeFormat`)
99- All storage in UTC
100- Display conversion at render time only
101
102### Calendar Sync
103
104- **iCal export**: `/api/providers/:id/calendar.ics` (subscribe from Google/Apple Calendar)
105- **iCal import**: provider can import external calendar to block busy times
106- **Two-way sync** (v2): Google Calendar API integration
107
108### Booking Rules
109
110- **Cancellation policy**: configurable window (24h, 48h, 72h, none)
111- **Rescheduling**: client self-service within policy window
112- **No-show handling**: provider marks no-show, configurable penalty
113- **Recurring bookings**: auto-book same slot weekly (within a subscription/bundle)
114- **Waitlist**: for full group sessions, notify on cancellation
115
116### Availability Object
117
118```javascript
119{
120 providerId: 'prov_xyz',
121 timezone: 'America/New_York',
122 weeklySchedule: {
123 monday: [{ start: '09:00', end: '12:00' }, { start: '14:00', end: '17:00' }],
124 tuesday: [{ start: '10:00', end: '16:00' }],
125 // ...
126 },
127 overrides: [
128 { date: '2026-04-15', available: false, reason: 'Vacation' },
129 { date: '2026-04-20', slots: [{ start: '08:00', end: '11:00' }] }
130 ],
131 bufferMinutes: 15,
132 advanceBooking: { minDays: 1, maxDays: 60 }
133}
134```
135
136### Booking Object
137
138```javascript
139{
140 id: 'bk_abc123',
141 providerId: 'prov_xyz',
142 clientId: 'cli_abc',
143 packageId: 'pkg_abc',
144 purchaseId: 'pur_abc', // links to payment
145 startTime: '2026-04-10T14:00:00Z', // UTC
146 endTime: '2026-04-10T15:00:00Z',
147 status: 'confirmed', // pending | confirmed | cancelled | no-show | completed
148 cancelledAt: null,
149 cancelReason: null,
150 notes: '', // provider notes post-session
151 createdAt: timestamp
152}
153```
154
155**Storage**: Hyperbee
156- `availability:{providerId}` → availability config
157- `booking:{bookingId}` → booking object
158- `bookings-by-provider:{providerId}:{date}` → booking IDs (index)
159- `bookings-by-client:{clientId}` → booking IDs (index)
160
161---
162
163## 4. Client Booking Flow
164
165The end-to-end experience for a client booking a session.
166
167### Step 1: Landing Page
168- Client visits `/<provider-slug>`
169- Sees provider profile + available packages
170- No auth required (anonymous browsing)
171
172### Step 2: Select Package
173- Client clicks a package card
174- If single session or discovery: go straight to calendar
175- If bundle/subscription: show pricing details + payment options first
176
177### Step 3: Choose Time Slot
178- Calendar picker (week view, mobile-friendly)
179- Only shows available slots for selected package duration
180- Timezone auto-detected, can override
181- For bundles: book first session now, remaining sessions later
182
183### Step 4: Checkout
184- hyper-pay widget renders payment form
185- Client selects payment method (from provider-enabled rails)
186- For free discovery calls: skip payment, just confirm
187- For bundles with installments: show payment schedule
188
189### Step 5: Intake (if configured)
190- Intake form (custom questions set by provider)
191- Contract/agreement (e-sign with ed25519 keypair)
192- Displayed between payment and confirmation
193
194### Step 6: Confirmation
195- Booking confirmed screen
196- Email confirmation with calendar invite (.ics attachment)
197- SMS reminder opt-in
198- Client gets access to client portal
199
200### Authentication During Booking
201
202- **Anonymous through step 3** (browsing + slot selection)
203- **Identity created at checkout** (keypair generated, stored in localStorage)
204- Same ANProto ed25519 pattern as pear-git/hypernote
205- Passwordless — keypair IS the credential
206- Client can optionally set a display name / email for notifications
207
208---
209
210## 5. Client Portal
211
212Passwordless portal for clients to manage their bookings.
213
214### Access
215- Keypair-based (same as pear-git/hypernote identity)
216- Client returns to site → keypair in localStorage → auto-authenticated
217- Can also access via magic link (email with signed token)
218
219### Features
220- **Upcoming sessions**: list with reschedule/cancel buttons
221- **Past sessions**: history with provider notes
222- **Remaining sessions**: for bundles, shows N of M used
223- **Book next session**: calendar picker for unused bundle sessions
224- **Purchase more**: browse provider packages, buy additional
225- **Forms & surveys**: fill intake forms, exit surveys
226- **Materials**: access shared files/links
227- **Messages**: simple messaging with provider (v2)
228- **Payment history**: receipts, upcoming charges for subscriptions
229
230### Client Object
231
232```javascript
233{
234 id: 'cli_abc123',
235 identityId: 'id_xyz', // ANProto public key
236 displayName: 'Jane Smith',
237 email: 'jane@example.com', // optional, for notifications
238 phone: '+1234567890', // optional, for SMS
239 providerId: 'prov_xyz', // which provider they're a client of
240 purchases: ['pur_abc'], // purchased packages
241 formResponses: ['fr_abc'], // intake form submissions
242 createdAt: timestamp,
243 lastActiveAt: timestamp
244}
245```
246
247**Storage**: Hyperbee
248- `client:{clientId}` → client object
249- `client-by-identity:{identityId}` → clientId (reverse lookup)
250- `client-by-provider:{providerId}:{clientId}` → clientId (index)
251
252---
253
254## 6. Provider Dashboard
255
256Admin interface for providers to manage their practice.
257
258### Calendar View
259- Day / week / month views
260- Sessions shown as blocks with client name + package
261- Click to view booking details, add notes
262- Drag to reschedule (with client notification)
263
264### Client Management
265- Client list with search/filter
266- Per-client: purchase history, session count, notes, form responses
267- Client tags (e.g., "VIP", "New", custom)
268- Export client list (CSV)
269
270### Package Management
271- Create / edit / archive packages
272- Duplicate existing package as template
273- Toggle active/inactive (doesn't delete, just hides from booking page)
274- Per-package analytics (purchases, revenue, completion rate)
275
276### Availability Settings
277- Visual weekly schedule editor
278- Date override calendar (mark days off, add special hours)
279- Buffer time configuration
280- Advance booking window
281
282### Forms & Contracts
283- **Intake form builder**: text, textarea, radio, checkbox, dropdown, file upload
284- **Contract template editor**: rich text with signature placeholder
285- **Exit survey builder**: post-package completion feedback
286- Attach forms/contracts to specific packages
287
288### Revenue & Analytics
289- Revenue by period (day/week/month/year)
290- Revenue by package
291- Revenue by payment rail (card vs ACH vs crypto)
292- Session completion rate
293- Client retention (rebooking rate)
294- Upcoming payouts
295
296### Settings
297- Profile editing
298- Notification preferences
299- Payment rail configuration (via hyper-pay)
300- Cancellation policy
301- Timezone
302
303---
304
305## 7. Notifications
306
307### Email
308- Booking confirmation (client + provider)
309- Reminder: 24h before session (configurable)
310- Reminder: 1h before session (configurable)
311- Cancellation notice
312- Rescheduling notice
313- Package purchase receipt
314- Subscription renewal notice
315- Intake form reminder (if not completed before session)
316
317### SMS (v1.1)
318- Session reminders (24h, 1h)
319- Cancellation/reschedule alerts
320- Opt-in only (client provides phone at checkout)
321
322### In-App
323- Provider dashboard: new booking, cancellation, payment received
324- Client portal: upcoming session reminder, materials shared
325
326### Implementation Notes
327- Email: transactional email service (Resend, Postmark, or SES)
328- SMS: Twilio or similar (research needed for P2P alternatives)
329- In-app: Hyperbee notifications feed, polled by client
330- Calendar invites: .ics file generation + email attachment
331
332---
333
334## 8. Payments (via hyper-pay)
335
336hyper-booking does NOT implement payments — it delegates to hyper-pay.
337
338### Integration Points
339
340```javascript
341const hyperPay = require('hyper-pay')
342
343// At checkout
344const payment = await hyperPay.charge({
345 merchantId: provider.merchantId,
346 amount: package.price,
347 currency: package.currency,
348 description: `${package.name} — ${provider.displayName}`,
349 customer: { email: client.email },
350 metadata: { bookingId, packageId, providerId }
351})
352
353// For subscriptions
354const subscription = await hyperPay.subscribe({
355 merchantId: provider.merchantId,
356 amount: package.price,
357 currency: package.currency,
358 interval: 'month',
359 customer: { email: client.email }
360})
361
362// For refunds (cancellation within policy)
363await hyperPay.refund({
364 paymentId: purchase.paymentId,
365 amount: refundAmount // full or partial
366})
367```
368
369### Platform Fee
370- Configurable per-provider (default 5%)
371- Collected by hyper-pay via Stripe Connect application_fee
372- For P2P rails: platform fee collected separately or waived
373
374### Purchase Object
375
376```javascript
377{
378 id: 'pur_abc123',
379 clientId: 'cli_abc',
380 providerId: 'prov_xyz',
381 packageId: 'pkg_abc',
382 paymentId: 'pay_abc', // hyper-pay payment ID
383 paymentRail: 'stripe-card', // which rail was used
384 amount: 50000, // cents
385 platformFee: 2500, // cents
386 status: 'paid', // pending | paid | refunded | partial-refund | failed
387 sessionsTotal: 6, // from package
388 sessionsUsed: 2,
389 installmentsPaid: 1,
390 installmentsTotal: 3,
391 createdAt: timestamp
392}
393```
394
395**Storage**: Hyperbee
396- `purchase:{purchaseId}` → purchase object
397- `purchases-by-client:{clientId}` → purchase IDs
398- `purchases-by-provider:{providerId}` → purchase IDs
399
400---
401
402## 9. Group Sessions
403
404Extension of the scheduling engine for multi-client sessions.
405
406- Provider creates group session with max capacity
407- Shows current enrollment count on booking page
408- Multiple clients book same time slot independently
409- Each client goes through normal checkout flow
410- Waitlist when capacity reached (notify on cancellation)
411- Provider sees full attendee list in dashboard
412- Different pricing from 1:1 (usually lower per-person)
413
414### Group Booking Object
415
416```javascript
417{
418 id: 'grp_abc123',
419 providerId: 'prov_xyz',
420 packageId: 'pkg_abc',
421 startTime: '2026-04-10T10:00:00Z',
422 endTime: '2026-04-10T11:00:00Z',
423 capacity: 12,
424 enrolledCount: 8,
425 attendees: ['cli_1', 'cli_2', ...],
426 waitlist: ['cli_9'],
427 status: 'open', // open | full | completed | cancelled
428 createdAt: timestamp
429}
430```
431
432---
433
434## 10. Forms & Content
435
436### Intake Forms
437- Custom per-package
438- Field types: text, textarea, select, checkbox, radio, file upload, date
439- Required vs optional fields
440- Submitted before first session (enforced or reminder-based)
441- Responses visible in provider dashboard per-client
442
443### Contracts
444- Rich text template with variables (client name, package name, date)
445- E-signature via ed25519 keypair (cryptographic proof)
446- Both parties sign (provider template + client acceptance)
447- Stored as signed document in Hyperbee
448
449### Exit Surveys
450- Triggered after final session in a package
451- Custom questions (same field types as intake)
452- Anonymous option
453- Aggregated results in provider analytics
454
455### Materials
456- Attach files/links to packages
457- Pre-session materials (e.g., questionnaire, reading)
458- Post-session materials (e.g., homework, resources)
459- Provider can add per-session notes visible to client
460
461---
462
463## 11. Identity & Auth
464
465Reuse the proven auth pattern from pear-git and hypernote.
466
467### Architecture
468
469```
470AuthManager
471├── WebIdentityProvider (ANProto ed25519 — browser keypairs)
472├── BearerTokenProvider (API tokens for integrations)
473└── KeetIdentityProvider (BIP39 mnemonic — Keet federation)
474```
475
476### Flow
477
4781. **Anonymous browsing** — provider pages, package listings, slot viewing
4792. **Identity created at checkout** — ed25519 keypair generated client-side
4803. **Challenge-response auth** — every API call signed (no cookies/sessions)
4814. **Auto-registration** — first provider = admin, clients = read on their own data
4825. **Passwordless return** — keypair in localStorage, auto-authenticates
483
484### Roles & Permissions
485
486| Role | Permissions |
487|------|------------|
488| **Anonymous** | View provider profile, packages, available slots |
489| **Client** | Book sessions, view own bookings/purchases, fill forms, access portal |
490| **Provider** | All client perms + manage packages, availability, clients, view analytics |
491| **Admin** | All provider perms + platform settings, provider management |
492
493### Identity Registry
494
495Same Hyperbee schema as pear-git/hypernote:
496- `user:{userId}` → user object + role + permissions
497- `identity:{identityId}` → identity method + credentials
498- `pubkey:{publicKey}` → reverse lookup
499- `username:{normalized}` → reverse lookup
500
501### Shared Code
502
503Extract auth into a shared module (or copy from hypernote):
504- `lib/auth/` — AuthManager, providers, challenge manager, rate limiter
505- `web/js/identity.js` — browser keypair management, fetch interceptor
506
507### Provider-Client Relationship
508
509- Provider identity: created at signup (first user = admin provider)
510- Client identity: created at first checkout
511- One identity can be client of multiple providers
512- Provider can also be a client of another provider
513
514---
515
516## 12. Data Model Summary
517
518### Hyperbee Key Prefixes
519
520```
521provider:{id} → Provider profile
522provider-by-slug:{slug} → providerId (reverse lookup)
523
524package:{id} → Package definition
525packages-by-provider:{providerId} → packageId list
526
527availability:{providerId} → Availability config
528
529booking:{id} → Booking record
530bookings-by-provider:{pid}:{date} → bookingId list
531bookings-by-client:{clientId} → bookingId list
532
533group:{id} → Group session record
534
535client:{id} → Client record
536client-by-identity:{identityId} → clientId
537clients-by-provider:{providerId} → clientId list
538
539purchase:{id} → Purchase/payment record
540purchases-by-client:{clientId} → purchaseId list
541purchases-by-provider:{providerId} → purchaseId list
542
543form:{id} → Form template
544form-response:{id} → Form submission
545contract:{id} → Contract template
546contract-signature:{id} → Signed contract
547
548notification:{id} → Notification record
549notifications-by-user:{userId} → notificationId list
550
551user:{userId} → User (identity registry)
552identity:{identityId} → Identity record
553pubkey:{publicKey} → identityId
554username:{name} → userId
555```
556
557---
558
559## 13. API Endpoints (Draft)
560
561### Public (no auth)
562```
563GET /api/providers/:slug Provider profile
564GET /api/providers/:slug/packages Available packages
565GET /api/providers/:slug/slots Available time slots for date range
566GET /api/auth/challenge Get auth challenge
567```
568
569### Client (auth required)
570```
571POST /api/bookings Create booking
572GET /api/bookings/:id Get booking details
573PUT /api/bookings/:id/reschedule Reschedule booking
574PUT /api/bookings/:id/cancel Cancel booking
575GET /api/portal/bookings Client's bookings
576GET /api/portal/purchases Client's purchases
577GET /api/portal/materials Client's materials
578POST /api/portal/forms/:id Submit form response
579POST /api/checkout Initiate payment (delegates to hyper-pay)
580```
581
582### Provider (provider auth required)
583```
584GET /api/dashboard/calendar Calendar view data
585GET /api/dashboard/clients Client list
586GET /api/dashboard/analytics Revenue & stats
587POST /api/packages Create package
588PUT /api/packages/:id Update package
589DEL /api/packages/:id Archive package
590PUT /api/availability Update availability
591POST /api/forms Create form template
592POST /api/contracts Create contract template
593PUT /api/settings Update provider settings
594```
595
596### Admin
597```
598GET /api/admin/providers All providers
599POST /api/admin/providers Create provider account
600PUT /api/admin/providers/:id/status Enable/disable provider
601GET /api/admin/analytics Platform-wide analytics
602```
603
604---
605
606## 14. What's NOT in v1
607
608- Video call integration (Jitsi/Jitter/custom)
609- Marketplace / provider discovery
610- In-person POS (Stripe Terminal)
611- AI agent booking via x402
612- Multi-provider organizations (studios)
613- Two-way Google Calendar sync (iCal export only in v1)
614- Client messaging (v2)
615- Mobile app (web-first)
616- Multi-language / i18n
617- Custom domain per provider
618
619---
620
621## 15. Build Phases
622
623### Phase 1: Core Booking
624- Provider profile + package creation
625- Scheduling engine (availability + slot calculation)
626- Client booking flow (select → calendar → confirm)
627- Hyperbee storage for all entities
628- Auth (reuse from hypernote)
629
630### Phase 2: Payments
631- hyper-pay integration (Stripe Connect)
632- Checkout flow with hyper-pay widget
633- Purchase tracking
634- Platform fee collection
635- Refunds
636
637### Phase 3: Client Portal
638- Passwordless client portal
639- Booking management (reschedule, cancel)
640- Bundle session tracking
641- Payment history
642
643### Phase 4: Provider Dashboard
644- Calendar view
645- Client management
646- Package analytics
647- Availability editor UI
648
649### Phase 5: Notifications
650- Email (transactional service)
651- Calendar invites (.ics)
652- In-app notifications
653- SMS (v1.1)
654
655### Phase 6: Forms & Content
656- Intake form builder
657- Contract e-signing
658- Exit surveys
659- Material attachments
660
661### Phase 7: Groups & Advanced
662- Group sessions + waitlist
663- Subscriptions + recurring billing
664- Installment plans
665- Promo codes