PRD: TVL → Hostaway Distribution MVP (Design‑Aligned v0.1)
This revision inlines our final MVP decisions for Distribution to Hostaway. It preserves scope while hardening auth, data, orchestration, and ops. Sections updated: Goals, Functional Requirements (4.1–4.5), Design/Technical Considerations, UI Scope, Success Metrics, Open Questions. A short change log is at the end.
1. Introduction / Overview
The TVL → Hostaway Distribution MVP empowers The Villa Life (TVL) platform to manage Units centrally and distribute them as listings to Hostaway, while TVL remains the canonical source of truth for supply data. Hostaway handles bookings and payments. This MVP also introduces Google Single Sign-On (SSO) for secure authentication and role-based access.
Each Hostaway site is modeled as a ChannelTarget. A Unit can be linked to multiple ChannelTargets, allowing distribution across multiple Hostaway accounts. Synchronization is one-way (TVL → Hostaway) for this phase.
2. Goals
- Google SSO (OIDC Auth Code + PKCE) with server‑side sessions, RBAC plus ABAC on org_id.
- Manage Spaces and Units as canonical supply; maintain versioned change history via Unit Snapshots.
- Publish Units to one or more ChannelTargets; maintain Unit ↔ Listing mapping.
- Ensure idempotent and rate‑limit‑safe synchronization (per‑target limiter, full‑jitter backoff, capped retries).
- Secure storage and rotation of Hostaway API tokens via cloud Secrets Manager.
- Observability: OTel → Collector (Prometheus receiver) → Prometheus; structured logs; correlation IDs; audit records.
- Operator UX: diff preview before publish; manual replay from snapshot; per‑target health dashboard.
- Prepare for multi‑tenant expansion (org hygiene + RLS policies scaffolded and disabled by default).
3. User Stories
Authentication & Access
- As a User, I can sign in with my Google account to access the Admin Console.
- As an Admin, I can assign roles (Owner,ChannelPublisher,ContentManager,Viewer) to control access.
- As an Owner, I can manage users, roles, tokens, and sync.
- As a Viewer, I can view Units and Channels but not modify them.
Supply Management
- As a Content Manager, I create/update Units (metadata, amenities, media) and can review diffs between versions.
Distribution
- As a Channel Publisher, I connect Hostaway sites (via API tokens), link Units, and publish to one or more sites.
- As an Operator, I can view sync statuses, retry failed syncs, and review audit logs.
- As an Operator, I see per‑target sync health, inspect audit entries, and replay from a prior snapshot when needed.
Observability
- As a Developer/Operator, I monitor metrics (sync volume/latency/429s), traces, and logs to triage issues quickly.
4. Functional Requirements
4.1 Authentication & Authorization
- OIDC: Authorization Code + PKCE.
- Auto‑provision on first login as Viewer(configurable).
- Roles: Owner,ChannelPublisher,ContentManager,Viewer.
- Role Mapping to Platform Spec: MVP roles map to platform authorization model as follows:
- Owner→ combines- admin+- owner_adminpermissions (full org/account management)
- ChannelPublisher→ equivalent to- opswith added- channel.managepermission
- ContentManager→ equivalent to- managerwith- space.write,- media.write,- unit.write
- Viewer→ maps directly to platform- viewerrole (read-only)
- Note: MVP uses simplified role names for operator UX; implementation uses platform permission bundles.
 
- ABAC: requests scoped by org_id; future RLS policies are scaffolded (disabled by default in MVP).
- Google Workspace domain restriction: optional; if enabled, enforced server‑side (do not rely solely on hd).
- Sessions & Cookies: server‑managed, HttpOnly,Secure,SameSite=Lax, ~24h TTL; rotate session ID on privilege changes.
4.2 Supply Domain
- Entities: Space(physical estate),Unit(bookable inventory).
- CRUD: /v1/unitscreates/updates Units; each write incrementsversion.
- Unit Fields: Each Unit includes name, description, capacity, amenities, media, and house rules.
- Unit Snapshots: on write, persist normalized snapshot (unit_snapshots) with(unit_id, version, snapshot, diff_hash)for diff preview and recovery.
- Media: URL‑based in MVP; single primary image enforced by constraint.
4.3 Distribution Domain
- ChannelTarget: represents a Hostaway site; stores only a reference to the token in Secrets Manager.
- ChannelListing: unique (unit_id, target_id)mapping; trackexternal_listing_id,status,last_synced_at, andlast_payload_hash.
- Sync Trigger: unit.updated(or outbox drain) enqueues one job per (unit, target) when payload hash differs.
- Idempotency: idempotency_key = sha256(unit_version|target_site_id); DB unique constraint on(listing_id, idempotency_key)prevents duplicates.
- API Calls: Hostaway POST /v1/listings,PUT /v1/listings/{id}(full‑object). PATCH considered post‑MVP.
- Retries & Backoff: max 5 attempts; full‑jitter backoff. Persist retry_after_aton 429 and honor when rescheduling.
- Rate Limits: BullMQ per‑target limiter (≤12 requests / 10s, configurable via env/DB for negotiated limits) with alerting on sustained 429s; continue other targets if one fails.
- Outbound Audit: immutable record with redacted body hashes and metadata (no raw PII); include a short body_excerptfor operator triage.
4.4 Observability & Ops
- Metrics (Prometheus‑style): tvl_sync_jobs_total{action,state,target},tvl_sync_latency_ms{target},tvl_hostaway_http_requests_total{status},tvl_rate_limited_total{target},tvl_auth_logins_total{result}.
- Tracing: OTel spans around enqueue, map, HTTP call, and persist; attributes include unit_id,listing_id,target_id,external_listing_id.
- Logs: structured JSON with correlation IDs (trace/span), key job fields.
- SLOs: see §9; alerts for 429 spike rate and job latency p95.
4.5 Admin APIs (MVP)
- /v1/auth/login|- /v1/auth/callback|- /v1/auth/logout|- /v1/me
- /v1/unitsCRUD
- /v1/channels/hostaway/targetsCRUD
- /v1/units/{unit_id}/channels/hostaway/links(create mapping)
- /v1/units/{unit_id}/channels/hostaway/sync(manual resync)
- /v1/sync-status(read-only, paginated per‑Unit/Target summary with target, state, attempts, retry_after_at)
5. Non‑Goals (MVP)
- No Hostaway → TVL ingestion (bookings/messages).
- No pricing or availability sync.
- No selective field publishing (full object writes only).
- No media upload pipeline (URL only).
- No public signup; Google SSO only.
6. Design Considerations
- Canonical entity: Unit.
- One site → one ChannelTarget; Unit may link to multiple targets.
- PUT for full payloads (simpler validation); PATCH in MVP+1.
- Secrets: store Hostaway tokens in cloud Secrets Manager with rotation policy and client‑side caching.
- Sync status polling: every 15s for real-time feedback; pause/back off when tab hidden; exponential backoff on ≥429/503; org/session caps to protect the API.
- Retry and diff logic: centralized in connector layer.
- Transactional Outbox (optional): may be enabled to decouple API latency from enqueue; not mandatory for MVP.
- Time zones: All DB times UTC; Hostaway check‑in/out fields mapped in local listing timezone.
7. Technical Considerations (decisions)
| Concern | Decision | 
|---|---|
| Auth | Google OIDC + server sessions; cookie hardening per OWASP | 
| Authorization | RBAC + ABAC ( org_id), RLS scaffolded (disabled) | 
| Tokens | Cloud Secrets Manager; long‑lived Hostaway tokens with T‑60/T‑30 alerts | 
| Queue | BullMQ on Redis noeviction; per‑target limiter | 
| Retries | Full‑jitter backoff; cap at 5; persist retry_after_aton 429 | 
| Idempotency | App de‑dupe + DB UNIQUE(listing_id, idempotency_key) | 
| DB | Postgres; citextenabled; partial indexes for worker/session cleanup | 
| Pooling | PgBouncer (or managed) in production | 
| Observability | OTel SDK → OTel Collector (Prometheus receiver) → Prometheus; JSON logs | 
| Deployment | Feature flags: auth.google.enabled,channels.hostaway.enabled | 
8. UI Scope (Admin)
Auth
- Google login/logout; show user + org; domain restriction banner if enforced.
Supply
- Unit CRUD with diff preview between current form and last published snapshot; flag fields that map to Hostaway time‑localized values.
Distribution
- Manage ChannelTargets (token reference, label, status).
- Manage ChannelListings (Unit → Hostaway links).
- Link Units ↔ ChannelTargets; publish and replay from snapshot actions.
- View per-channel sync status and audit logs.
- Owner-only token management.
- Health dashboard: per‑target queue depth, 429 count, last success latency; drill‑down to audit entries.
Backed by metrics: tvl_sync_jobs_total{action,state,target},tvl_sync_latency_ms{target},tvl_hostaway_http_requests_total{status},tvl_rate_limited_total{target}.
UX Principles
- Minimal, operator-focused UI.
- Real-time feedback on syncs.
- Visual enforcement of role-based access.
9. Success Metrics (MVP)
| Metric | Target | 
|---|---|
| 95% of syncs complete within 5 minutes | ✅ | 
| < 1% sync failures per day | ✅ | 
| 100% outbound audit coverage | ✅ | 
| < 0.1% login failures | ✅ | 
| 429 ratio < 2% for any target (rolling 10m) | ✅ | 
| Mean time to recover via snapshot replay < 10m | ✅ | 
10. Open Questions (answered for MVP)
- Restrict Google login to @thevillalife.com? Optional; if enabled, enforce in callback using verified email domain.
- Auto‑sync on Unit delete? No hard delete; status='archived'in TVL; enqueue delete to Hostaway per mapping.
- Token expiry rotation & alarms? Yes; alerts at T‑60/T‑30 days; handle 403 as rotation hint.
- OutboundAudit retention? 90 days default with scheduled purge; export summary metrics before deletion.
11. Acceptance Criteria (selected)
- Creating/updating a Unit persists a snapshot, increments version, and enqueues exactly one job per linked ChannelTarget when hash differs.
- Publishing respects per‑target limiter; 429s update retry_after_atand are retried with full‑jitter; no other targets are blocked.
- Health dashboard reflects state changes within ≤20s under nominal load; polling backs off on ≥429/503 and pauses when tab is hidden.
- Duplicate enqueue prevented by DB uniqueness on (listing_id, idempotency_key).
- Admin can preview diffs and replay from a selected snapshot; changes are reflected in audit and metrics.
- All session cookies are Secure,HttpOnly,SameSite=Laxand rotate on role changes.
12. Change Log (relative to prior PRD)
- Added Unit Snapshots and diff/replay flows.
- Added DB UNIQUE(listing_id, idempotency_key) and partial indexes; added retry_after_atfield.
- Clarified per‑target rate limiters, jitter strategy, and 429 alerting.
- Clarified cookie hardening and optional domain enforcement.
- Added PgBouncer in prod, Redis noeviction, OTel Collector with Prometheus receiver.
- Expanded metrics/SLOs and health dashboard scope.
13. Questions
- Q1. Do we not get back in v0 the booking details from Hostaway?
- A1. No, in v0 we will push properties out to Hostaway, but in v0.1 we can start to get data back, and definitely before we get 2 hostaway sites.