Buyer Portal
Overview
Section titled “Overview”The buyer portal is the primary user-facing application. It’s an Astro 5 SSR application serving both public and authenticated content. Prospective buyers browse units, register with OTP, save favorites, download documents, and contact agents.
Page Structure
Section titled “Page Structure”| Route | Page | Access |
|---|---|---|
/ | Home / Landing | Public |
/units | Unit listing with filters | Public |
/units/[id] | Unit detail | Public |
/profile | Buyer profile (edit name, contact, preferences) | Auth required |
/brochure | Project brochure download | Public |
/features | Features/amenities | Public |
/location | Location / map | Public |
/imprint | Legal imprint | Public |
/privacy | Privacy policy | Public |
Interactive Components (Preact Islands)
Section titled “Interactive Components (Preact Islands)”| Component | File | Purpose |
|---|---|---|
UnitListing | components/islands/UnitListing.tsx | Filterable grid/list unit view |
UnitDetailPopup | components/islands/UnitDetailPopup.tsx | Full unit detail modal |
UnitFilterBar | components/islands/UnitFilterBar.tsx | Price, rooms, status filters |
LoginForm | components/islands/LoginForm.tsx | OTP email/WhatsApp login flow |
BuyerProfileForm | components/islands/BuyerProfileForm.tsx | Profile editor |
FavoriteButton | components/islands/FavoriteButton.tsx | Save/unsave toggle |
FinancingCalculator | components/islands/FinancingCalculator.tsx | Monthly payment calculator |
ImageBrowser | components/islands/ImageBrowser.tsx | Fullscreen image lightbox |
BrochureDownloads | components/islands/BrochureDownloads.tsx | Document download manager |
PriceRangeSlider | components/islands/PriceRangeSlider.tsx | Dual-handle price range |
CookieConsent | components/islands/CookieConsent.tsx | GDPR consent banner |
PresetTesterOverlay | components/islands/PresetTesterOverlay.tsx | Theme preset preview (dev) |
Data Sources
Section titled “Data Sources”On the main branch, portal data (units, agents, pages, settings) is fetched from Directus API using a static token. On spike/cf-runtime, it reads directly from the tenant-scoped PostgreSQL tables.
Auth Flow
Section titled “Auth Flow”- User enters email or phone number
- OTP is sent via Resend (email) or Meta Cloud API (WhatsApp)
- User enters OTP, server verifies SHA-256 hash
- Lucia session stored in Postgres (
sessions, 30-day expiry). Cookie refreshed when Lucia extends expiry — same session id (no per-request rotation). HTTP-only cookie set - Cloudflare Turnstile protects OTP send endpoints from abuse
Tenant Resolution
Section titled “Tenant Resolution”The portal resolves tenant from the Host header using resolveHost(), which joins portal_domains → portals → projects → organizations. Falls back to Lucia user attributes when hostname resolution fails (e.g., local dev).