Developer Documentation

πŸ” Authentication & Routing Architecture

Last Updated: November 13, 2025

Production Ready

🎯 Overview

The Reformer Platform uses a dual-portal architecture with domain-based routing for authentication and user access. This document explains how users are authenticated and routed to the correct portal based on their role and domain.

πŸ—οΈ Architecture

Two Portals

  1. Client Portal (my.reformer.la)
    • For paying clients
    • Access via: my.reformer.la/{portalSlug}
    • Shows onboarding checklist on home page
    • No blocking - clients can access everything
  2. Internal Portal (dash.reformer.la)
    • For employees/admins
    • Access via: dash.reformer.la/dashboard
    • No onboarding required
    • Full admin access

πŸ” Authentication Flow

Login Process

  1. User submits login form (/login)
    • Email and password authentication via Supabase Auth
    • Backend API: POST /api/auth/login
    • Returns: { user: {...}, session: { access_token, ... } }
  2. Token stored in localStorage as auth_token
  3. Domain-based routing determines where user goes next

πŸ—ΊοΈ Routing Logic

Client Portal (my.reformer.la)

Flow: Login β†’ Get portal slug β†’ Redirect to my.reformer.la/{slug}

Logic:

  1. Check if hostname === 'my.reformer.la'
  2. After login, fetch /api/auth/me to get member data
  3. Get member.portal_slug from API response
  4. If slug exists:
    • Redirect to https://my.reformer.la/{slug} (ClientPortal component)
    • Client sees onboarding checklist on home page
  5. If no slug:
    • Check if user is employee/admin/owner
    • If NOT employee:
      • Show error: "We cannot find your account. Please contact support@reformer.la for assistance."
      • Remove auth token
      • Stay on login page
    • If IS employee:
      • Redirect to https://dash.reformer.la/dashboard

Internal Portal (dash.reformer.la)

Flow: Login β†’ Navigate to /dashboard

Logic:

  1. Check if hostname === 'dash.reformer.la'
  2. After login, navigate to /dashboard
  3. No portal slug check needed
  4. No onboarding blocking
  5. Direct access to ClientDashboardHome component

πŸ‘₯ User Roles

Employee/Admin

Role Check:

const isEmployee = member?.custom_fields?.role === 'employee' ||
                  member?.customFields?.role === 'employee' ||
                  member?.custom_fields?.role === 'admin' ||
                  member?.customFields?.role === 'admin' ||
                  member?.custom_fields?.role === 'owner' ||
                  member?.customFields?.role === 'owner'

Access:

Client

Access:

πŸ“Š API Response Structure

/api/auth/me Response

{
  "user": {
    "id": "uuid",
    "email": "user@example.com",
    "email_confirmed_at": "timestamp",
    "created_at": "timestamp"
  },
  "member": {
    "id": "uuid",
    "email": "user@example.com",
    "portal_slug": "client-slug",  // From accounts.portal_slug (JOIN)
    "dashboard_slug": "client-slug",
    "custom_fields": {
      "role": "employee" | "admin" | "owner" | null
    },
    "onboarding_completed_at": "timestamp" | null,
    "company_name": "Company Name" | null
  }
}

🚫 Onboarding Logic

No Blocking

Important: There is NO onboarding blocking in the system.

πŸ§ͺ Testing

Test Scenarios

  1. Client Login on Client Portal
    • Login on my.reformer.la
    • Should redirect to my.reformer.la/{portalSlug}
    • Should see client portal with onboarding checklist
  2. Employee Login on Client Portal
    • Login on my.reformer.la as employee
    • Should redirect to dash.reformer.la/dashboard
    • Should see internal dashboard
  3. Employee Login on Internal Portal
    • Login on dash.reformer.la as employee
    • Should go to /dashboard
    • Should see internal dashboard
  4. Client Without Portal Slug
    • Login on my.reformer.la without portal slug
    • Should show error message
    • Should stay on login page
    • Should remove auth token

πŸ“ Code Locations

Frontend

Backend

πŸ› Troubleshooting

Issue: Client can't login

Symptoms: Error: "We cannot find your account", Stays on login page

Solutions:

  1. Check if client has portal_slug in database
  2. Check if client is marked as employee (should not be)
  3. Check if account exists in accounts table
  4. Check if member is linked to account (member.account_id)

Issue: Employee redirected incorrectly

Symptoms: Employee redirected to client portal instead of internal portal

Solutions:

  1. Check if custom_fields.role is set to 'employee', 'admin', or 'owner'
  2. Check if employee has portal_slug (should redirect to internal portal)
  3. Verify domain detection logic

🎯 Summary

The authentication and routing system provides:

  1. Dual-portal support - Client portal and internal portal
  2. Domain-based routing - Automatic routing based on hostname
  3. Role-based access - Employee/admin vs client
  4. Error handling - Clear error messages for missing accounts
  5. No blocking - Clients can access everything, see checklist on home page
  6. Employee support - Employees can login on either portal, redirected appropriately

Status: βœ… Production Ready


Last Updated: November 13, 2025