feat(scheduling): dezky Scheduling — Calendly-style booking on Stalwart calendars
First-party booking system on top of Stalwart calendars (no third-party scheduling dependency). Hosts expose public booking pages; visitors pick a slot computed from the host's live Stalwart free/busy, and confirming writes the event to the host's calendar and sends a dezky-branded confirmation with an .ics. platform-api (services/platform-api/src/scheduling): - Schemas: Host, StalwartCredential (AES-256-GCM at rest), AvailabilitySchedule, EventType, Booking, SlotLock (unique (hostId,startUtc) + TTL). - StalwartCalendarModule: JMAP gateway (free/busy via Principal/getAvailability, event create/delete, scheduleAgent=client) + on-behalf app-password provisioning. CredentialCipher for at-rest encryption. - DST-correct slot engine (Luxon) with unit tests; two-layer double-booking guard (atomic SlotLock + live free/busy re-check). - Booking confirm/cancel/reschedule, branded email + .ics via JMAP submission, self-service manage tokens. /api/v1 public + tenant-gated admin routes, per-IP rate limiting. apps/booking: standalone public, whitelabel booking app (booking.dezky.eu) — path-based tenant resolution, per-tenant brand colour, booking + manage flows. apps/portal: admin scheduling page (hosts, event types, availability, bookings with edit/delete + admin cancel/reschedule) and proxy routes. infra: booking dev service in docker-compose; scheduling env vars.
This commit is contained in:
@@ -0,0 +1,41 @@
|
||||
// Nuxt 4 config for the dezky public booking app (booking.dezky.eu).
|
||||
//
|
||||
// Fully public — NO OIDC, no sessions. It only ever calls the unauthenticated
|
||||
// /api/v1/public/* endpoints on platform-api, proxied through this app's own
|
||||
// nitro server routes so the internal API hostname never reaches the browser.
|
||||
// Whitelabel: every page renders the tenant's branding (name + brandColor),
|
||||
// fetched per request — there is no dezky-fixed accent.
|
||||
|
||||
export default defineNuxtConfig({
|
||||
compatibilityDate: '2026-01-01',
|
||||
devtools: { enabled: true },
|
||||
|
||||
css: ['~/assets/styles/base.css'],
|
||||
|
||||
runtimeConfig: {
|
||||
// Server-only: how nitro reaches platform-api inside the docker network.
|
||||
platformApiUrl: process.env.PLATFORM_API_INTERNAL_URL || 'http://platform-api:3001',
|
||||
public: {
|
||||
siteUrl: process.env.NUXT_PUBLIC_SITE_URL
|
||||
|| (process.env.NODE_ENV === 'production' ? 'https://booking.dezky.eu' : 'http://localhost:3000'),
|
||||
},
|
||||
},
|
||||
|
||||
app: {
|
||||
head: {
|
||||
htmlAttrs: { lang: 'en' },
|
||||
link: [{ rel: 'icon', type: 'image/svg+xml', href: '/favicon.svg' }],
|
||||
meta: [
|
||||
{ name: 'viewport', content: 'width=device-width, initial-scale=1' },
|
||||
{ name: 'robots', content: 'noindex' }, // booking pages aren't for search indexing
|
||||
],
|
||||
},
|
||||
},
|
||||
|
||||
vite: {
|
||||
server: {
|
||||
allowedHosts: ['booking.dezky.local'],
|
||||
hmr: process.env.DEZKY_TRAEFIK === '1' ? { protocol: 'wss', clientPort: 443 } : undefined,
|
||||
},
|
||||
},
|
||||
})
|
||||
Reference in New Issue
Block a user