SoConnective

Architecture

ADR 0005 — Internal apps frontend (CRM & client portal)

  • Status: Accepted
  • Date: 2026-06-10

Context

The platform needs polished, cohesive internal web apps: first the team CRM, later the client portal. Earlier attempts assembled the UI from component kits (shadcn/ui primitives, Tailwind Plus Catalyst, Tailwind Plus Application UI). Hand-assembling produced an inconsistent, unfinished look and slow progress — a component kit is raw building blocks, not a finished application.

The documentation site proved the opposite approach: adopting a complete, professionally designed template (Tailwind Plus Syntax) gave an excellent result immediately. We apply the same principle to the apps.

Decision

Adopt Shadcn UI Kit — Dashboard (shadcnuikit.com) as the foundation for apps/crm (and the future portal):

  • Stack: Next.js 16, React 19, Tailwind v4, shadcn/ui — identical to our app stack, so there is zero migration friction.
  • License: one-time commercial (Pro tier), source included, self-hostable, unlimited projects, no feature-gating — consistent with our self-hosted, subscription-free philosophy.
  • Ships a CRM dashboard plus the app surfaces we need (Kanban for the pipeline, Mail/Chat, Calendar, Tasks, Notes) for both the CRM and the portal.

Branding (locked)

  • Theme locked to the Ocean Breeze preset (the closest match to brand blue #467df6) with md radius; the theme customizer is removed so the look stays on-brand for every user.
  • Satoshi (self-hosted, official) as the typeface; official Feedback Studios logo; "Feedback OS" wordmark.
  • Removed vendor artifacts: the assetPrefix pointing at the vendor domain (which broke asset loading in production), the "Get Pro" link, demo projects, and the external analytics script.

Authentication

Server-side session, reusing the backend (Payload) auth:

  • Login posts to PAYLOAD_URL/api/users/login; on success the JWT is stored in an httpOnly cookie named crm_token.
  • lib/payload.ts forwards the JWT as Authorization: JWT <token> on server-side fetches to the backend.
  • proxy.ts (Next.js 16's renamed middleware) guards everything under /dashboard/*, redirects / to /dashboard/crm, and gates unauthenticated users to /dashboard/login/v1.
  • The current user is fetched via /api/users/me and shown in the sidebar.

Structure

  • app/dashboard/(auth)/* — the gated application (CRM dashboard, companies, contacts, deals, services, pipeline, workspace apps).
  • app/dashboard/(guest)/* — login / register / forgot-password.
  • Sidebar trimmed to CRM (Dashboard, Companies, Contacts, Deals, Pipeline, Services) and Workspace (Mail, Chat, Calendar, Tasks, Notes).

Consequences

  • Fast, cohesive, on-brand result; the design work is done by the template authors.
  • We stay within the template's shadcn/ui conventions — a constraint, not a limitation.
  • Data is wired to the Payload backend via payloadFetch; the list pages (companies/contacts/deals/services) start as placeholders and are connected to the backend in a follow-up phase.
  • The same foundation will host the client portal.
Previous
ADR 0004 — CRM on Payload with the multi-tenant plugin