CRM
Overview
Section titled “Overview”The CRM is a built-in replacement for Directus, providing agents and real estate developers with tools to manage units, agents, portal settings, and view leads. It lives in the same Astro project as the buyer portal but under separate route prefixes.
Note: The CRM exists on spike/cf-runtime only. main uses Directus for CRM functions.
Browser URLs use clean paths (e.g. /units, /leads). The /admin/ prefix is a legacy internal detail — the middleware redirects /admin/* requests to clean paths and rewrites clean paths internally.
Sidebar (Verwaltung)
Section titled “Sidebar (Verwaltung)”| Order | Label | Route | Visible to |
|---|---|---|---|
| 1 | Wohneinheiten | /units | Developer, Agent |
| 2 | Dokumente | /documents | Developer, Agent |
| 3 | Makler | /agents | Developer |
| 4 | Portal-Einstellungen | /portal-settings | Developer |
CRM group: Interessenten → /leads (Developer, Agent).
Domains are shown as a read-only card on Portal-Einstellungen (not a separate nav item). /domains redirects to /portal-settings?section=domains.
Page Structure
Section titled “Page Structure”Root / serves the OTP login page for unauthenticated requests and the dashboard for authenticated sessions.
| Route | Page | Role |
|---|---|---|
/ | OTP login (email → 6-digit code) | Public |
/accept | Legacy magic-link (deprecated) | Public |
/ | Dashboard / home | Developer, Agent |
/units | Unit list | Developer, Agent |
/units/new | Create unit | Developer |
/units/[id] | Unit detail/edit | Developer, Agent |
/agents | Makler list + CRM user invite | Developer |
/makler | Self-profile editor | Agent |
/leads | Lead viewer | Developer, Agent |
/portal-settings | Portal branding, features, domains | Developer |
/documents | Document management | Developer, Agent |
/domains | Redirect → portal-settings (domains section) | Developer |
Implementation note: The middleware rewrites clean CRM paths to
/admin/*internally (e.g.,/units→/admin/units). API routes retain the/api/admin/*prefix (the rewrite excludes/api/*).
API Routes
Section titled “API Routes”| Endpoint | Purpose |
|---|---|
POST /api/auth/admin/request-link | Request magic-link email |
POST /api/auth/admin/logout | Invalidate CRM session |
GET /api/admin/session/me | Current user + accessible projects |
POST /api/admin/session/active-project | Switch active project |
GET/POST /api/admin/units | List/create units |
PATCH/DELETE /api/admin/units/[id] | Update/archive unit |
POST /api/admin/units/[id]/images/presign | Get presigned upload URL |
POST /api/admin/units/[id]/images | Confirm image upload |
GET/POST /api/admin/agents | List/create Makler (+ CRM login via crmRole on POST) |
PATCH /api/admin/agents/[id] | Update agent |
GET/PATCH /api/admin/agents/me | Self-profile (agent) |
POST /api/admin/agents/[id]/avatar/presign | Get presigned avatar URL |
PUT /api/admin/agents/[id]/projects | Set agent project assignments |
GET /api/admin/leads | List buyer registrations |
GET/PATCH /api/admin/portal-settings | Read/update portal config |
POST /api/admin/portal-settings/logo | Upload logo to R2 |
GET /api/admin/documents | List documents |
POST /api/admin/documents/presign | Get presigned upload URL |
GET /api/admin/domains | List portal domains |
POST /api/admin/invite | Invite CRM user (role, projectIds, optional organizationId) |
POST /api/admin/invite-developer | Legacy developer invite (requires projectIds) |
Provisioning logic: src/lib/auth/provision-crm-user.ts — every CRM account needs role (developer | agent) and at least one project (agent_project_assignments).
Auth Boundaries
Section titled “Auth Boundaries”| Role | CRM access (current feature set) |
|---|---|
| Developer | Full org scope: Interessenten, Wohneinheiten (incl. create), Dokumente, Makler management, Portal-Einstellungen (incl. domains card). All projects in their organization via memberships. |
| Agent | Interessenten, Wohneinheiten (assigned projects), Dokumente; self-profile at /makler. No Makler admin list or portal settings. |
| Operator | Cross-tenant via Operator Panel (Cloudflare Access, no Lucia session). |
Sessions are stored in Postgres (admin_sessions), not Worker memory — they survive redeploys until expiry (7 days) or logout. See CRM Auth.
Key Island Components
Section titled “Key Island Components”| Component | Purpose |
|---|---|
UnitsTable.tsx | Data table with sort/filter |
AgentManager.tsx | Makler CRUD; on create also provisions CRM login (crmRole + active project) |
AdminProjectSwitcher.tsx | Project selector in top bar |