Documentation
Dashboard

Client Info Hub

The third hub. A bento grid of everything we know about a client — read-only for clients, fully editable by admins.

Where to find it
Open any client portal and click the Client Info tab in the top dark hub bar. Both admins and clients can see this hub. Admins get pencil icons in every card.

Why this exists

The agency was juggling client metadata across notes, Drive folders, WhatsApp threads and the team's memory. The Client Info hub consolidates it: one canonical place for company info, primary contact, domain & hosting expirations, brand assets, social handles, billing, notes. The client sees the same view we do — proves we have it organised, and lets them spot mistakes early.

Bento grid layout

The hub renders one full-bleed page (no sub-tabs). Cards span across a 12-column grid:

CardSpanContent
About the company7Legal name, industry, founded year, team size, free-text description.
Primary contact5Name, role, email (mailto), phone (tel). The first name drives the Home greeting.
Headquarters5Street, city, state, zip, country.
Domain & hosting7Domain, registrar, hosting provider, plus domain and SSL expiration dates.
Brand assets6Brand colors as live swatches with hex labels + typography description.
Social media6Facebook, Instagram, LinkedIn, YouTube, TikTok URLs (rendered as external links).
Billing & legal5Billing email + tax / business ID.
Notes7Freeform admin notes — sensitivities, scope nuances, internal context.
Expiration tinting
The domain and SSL expiration dates auto-tint: red within 30 days, amber within 90, neutral otherwise. This is purely client-side — no background job. If a date is past, it stays red.

Schema

All fields live as dedicated columns on the clients table prefixed with info_. Migration: supabase/add-client-info.sql.

sql
-- Company
ALTER TABLE clients ADD COLUMN IF NOT EXISTS info_legal_name text;
ALTER TABLE clients ADD COLUMN IF NOT EXISTS info_industry text;
ALTER TABLE clients ADD COLUMN IF NOT EXISTS info_founded_year int;
ALTER TABLE clients ADD COLUMN IF NOT EXISTS info_employee_count text;
ALTER TABLE clients ADD COLUMN IF NOT EXISTS info_about text;

-- Primary contact (name drives the greeting on Home)
ALTER TABLE clients ADD COLUMN IF NOT EXISTS info_primary_contact_name text;
ALTER TABLE clients ADD COLUMN IF NOT EXISTS info_primary_contact_role text;
ALTER TABLE clients ADD COLUMN IF NOT EXISTS info_primary_contact_email text;
ALTER TABLE clients ADD COLUMN IF NOT EXISTS info_primary_contact_phone text;

-- Address
ALTER TABLE clients ADD COLUMN IF NOT EXISTS info_address text;
ALTER TABLE clients ADD COLUMN IF NOT EXISTS info_city text;
ALTER TABLE clients ADD COLUMN IF NOT EXISTS info_state text;
ALTER TABLE clients ADD COLUMN IF NOT EXISTS info_zip text;
ALTER TABLE clients ADD COLUMN IF NOT EXISTS info_country text;

-- Domain & hosting
ALTER TABLE clients ADD COLUMN IF NOT EXISTS info_domain text;
ALTER TABLE clients ADD COLUMN IF NOT EXISTS info_domain_registrar text;
ALTER TABLE clients ADD COLUMN IF NOT EXISTS info_domain_expiration date;
ALTER TABLE clients ADD COLUMN IF NOT EXISTS info_hosting_provider text;
ALTER TABLE clients ADD COLUMN IF NOT EXISTS info_ssl_expiration date;

-- Brand
ALTER TABLE clients ADD COLUMN IF NOT EXISTS info_brand_colors text;  -- comma-separated hex
ALTER TABLE clients ADD COLUMN IF NOT EXISTS info_brand_fonts text;

-- Social
ALTER TABLE clients ADD COLUMN IF NOT EXISTS info_social_facebook text;
ALTER TABLE clients ADD COLUMN IF NOT EXISTS info_social_instagram text;
ALTER TABLE clients ADD COLUMN IF NOT EXISTS info_social_linkedin text;
ALTER TABLE clients ADD COLUMN IF NOT EXISTS info_social_youtube text;
ALTER TABLE clients ADD COLUMN IF NOT EXISTS info_social_tiktok text;

-- Billing & legal
ALTER TABLE clients ADD COLUMN IF NOT EXISTS info_billing_email text;
ALTER TABLE clients ADD COLUMN IF NOT EXISTS info_tax_id text;
ALTER TABLE clients ADD COLUMN IF NOT EXISTS info_notes text;

Editing flow

Admins see two affordances:

  • A global Edit info button in the page header opens the editor at the top.
  • A pencil icon in every card's top-right opens the editor and scrolls to that section automatically.

The editor is one modal split into 8 sections (Company / Contact / Address / Domain / Brand / Social / Billing / Notes). Save writes directly to the clients table via the Supabase browser client; empty strings are coerced to null. After save the page calls router.refresh() so the bento grid re-reads the latest row.

Trust boundary
The save uses the browser-side Supabase client. Authorisation rests on Supabase RLS — only admins can UPDATE the clients table. The pencil icon is hidden for client users in the UI, but RLS is the actual gate.

Primary contact drives the greeting

The Home page used to greet "Good morning, Denver" using the company name. With Client Info shipped, the greeting reads info_primary_contact_name first and falls back to the company name only if the contact field is empty. So once an admin setsinfo_primary_contact_name = 'John Smith', the client sees "Good morning, John."

Component paths

FilePurpose
src/components/portal/sections/ClientInfoSection.tsxRead-only bento grid + per-card pencil affordance.
src/components/portal/editors/ClientInfoEditor.tsxModal editor with all sections; saves to clients table.
src/lib/types/clientInfo.tsShared TS interface mirroring the SQL columns.
supabase/add-client-info.sqlMigration that adds the 29 info_* columns.

Status

live Hub, bento grid, editor, expiration tinting, greeting wiring all shipped in Phase 1.1. Future polish that is intentionally out-of-scope for now: per-section RLS so a sensitive sub-section (e.g. tax ID) can be hidden from client view; audit log of edits; multi-contact support.