Project Overview
What FPM Client Hub / FPM Client Portal is, who uses it, and what problem it solves.
A quick note on naming
Internally the codebase is called FPM Client Hub. Externally — what the client sees, what we link to in proposals — it is called the FPM Client Portal (Flooring Pros Marketing). Same product, two names. Treat the two as interchangeable when reading these docs.
Mission
The FPM Client Portal is a white-label, per-client web application that serves as the single source of truth for every active client relationship. It replaces spreadsheets, email threads, Slack DMs, WhatsApp messages, and disconnected reporting tools with one branded, bookmarkable URL that the client uses throughout their entire program — from onboarding through growth and scale.
What problem does this solve?
- Clients don't know what we're working on without a weekly call.
- Approvals happen over email, Slack, WhatsApp and calls — never in one place.
- Reporting is scattered across Looker Studio, GHL, SE Ranking and Local Dominator.
- There's no structured way to onboard clients into the program and set expectations.
- Action items from calls get lost — no permanent record of what was agreed.
- Clients can't easily see the wins and proof of work accumulating over time.
Who uses it?
| User | Role in the portal |
|---|---|
| Client (owner / stakeholder) | Reads updates, approves deliverables, submits requests, books calls, views KPIs. |
| Chesney — Account Manager | Adds meeting notes, manages deliverables, responds to requests, sends weekly recap. |
| Kenan — Head of Fulfillment | Manages deliverable pipeline, marks items ready for review, closes requests. |
| Client Revenue Strategist (CRS) | Currently hiring. Adds game plan updates, scorecard scores, wins, meeting summaries. |
| Dan — CMO / Co-founder | Full admin access. Oversees all portals, adds strategy content, owns the roadmap. |
| Aniello — Engineering / Data | Owns the codebase, the deployment, and the data integrations. The repo lives in Aniello's GitHub account. |
Access model
- Each client gets a unique URL:
clients.flooringpros-marketing.com/[client-slug]. - Client login is required — the URL is the access control. Visiting the URL without a session redirects to
/login. - The FPM team accesses an admin overlay on the same URL — same screen the client sees, plus internal fields and edit controls.
- The admin overlay shows internal fields, editing pencils, raw integration data, and detail tabs (Paid Marketing, Social, Website, SEO, Local SEO, Email/SMS, Calculated KPIs) that the client never sees.
profiles.client_id. The middleware checks the logged-in user's profile and forces the URL to that client. Sharing your URL with another client's user does not leak data — they will be redirected to their own portal.Three hubs in the per-client portal
Inside /dashboard/clients/[id] the layout is a sticky black HubNav at top with three switchable hubs. State is in the URL via ?hub=client&tab=home so admins can deep-link to any view.
| Hub | Audience | Purpose |
|---|---|---|
| Client Hub | Admin + Client | Relationship, strategy, accountability. Sub-tabs: Home, Onboarding, Scorecard, Game Plan, Deliverables, Wins & Progress, Content & Authority, Meeting Notes, Resources & Docs, Billing & Package. |
| Reporting | Admin only (today) | Performance data. Sub-tabs: Reporting Home, Pipeline Overview, Website Performance, SEO & AEO Performance, Paid Ads, Social Media, Email & Automation. The previous top-level admin tabs all live here. |
| Client Info | Admin + Client | Single-page bento grid of company metadata — primary contact, address, domain & hosting expirations, brand assets, social, billing, notes. Admin pencils to edit; client read-only. |
Surface area (technical)
/login— Supabase email/password./dashboard— admin home (client list)./dashboard/clients/[id]— the FPM Client Portal for one client. Three hubs as above. This is where 95% of usage happens./dashboard/clients/[id]/edit— admin-only client config form (integrations, branding, logo upload)./settings— user profile and global integration toggles./documentation— this internal documentation site.
Sidebar behaviour
- Admin everywhere — dark
#202020sidebar stays visible on every/dashboard/*route, including the per-client portal, so admins can hop between clients without leaving the view. Each client row has a pencil icon (visible on hover) that jumps directly to the edit page. - Client on the per-client portal — sidebar hidden, full-bleed layout. They only ever see their own portal.
- Stripped admin nav — Overview / Dashboard / Analytics / Reports / Settings rows are gone. The sidebar is now just the Web Clients list + user profile (with Settings inside the profile menu).
Data flow summary
At a high level: the browser renders a client portal component. That component fires a parallel set of fetch() calls to /api/metrics/* endpoints. Each endpoint reads the connected integration from Supabase, calls the upstream API with the appropriate OAuth token, normalises the response and returns a JSON payload. The component renders the data into MetricCard rows.
For external sources we cannot OAuth into directly (n8n, DataForSEO when budget is tight), data is pushed to /api/metrics/external via a webhook and cached in Supabase. The frontend reads from the cache the same way as a live source.
Where we are right now
As of the last review (May 2026):
- live Google Analytics 4, Search Console, Google Business Profile (Performance API), Google Business Profile reviews (Places API), YouTube Data API, PageSpeed Insights, GoHighLevel.
- partial Google Ads (scope added, requires per-client re-auth), Meta Ads (account ID flow exists), DataForSEO (only via n8n proxy).
- pending Microsoft Clarity, Windsor.ai connectors, n8n outbound metrics for email/SMS.
- planned SE Ranking replacement, Local Dominator integration.
The canonical reference for status is the Where We Are page.
Vocabulary
| Term | Meaning |
|---|---|
| FPM Client Hub | Internal name for this codebase. |
| FPM Client Portal | External / product name. Same thing. |
| Client | A row in the clients table — represents one of our customers. |
| Integration | A row in the integrations table connecting a client to an external API. We have agency-level Google integrations (one OAuth token serves every client) and per-client integrations (GHL, Meta). |
| Source | The 3-letter tag shown on each metric row indicating where the data came from (GA4, GSC, GBP, GHL, n8n, etc.). |
| MetricCard | The React component that renders a card with a title and a list of metric rows. Auto-hides rows with no data and the entire card if all rows are hidden. |
| Pipeline | The GHL CRM pipeline. Leads → Appointments Booked → Showed → Quoted → Won. |
| ext() | Helper inside ClientDashboard that reads a key from the externalData webhook cache. |
| n8n | Workflow automation tool we use to push aggregated metrics into the dashboard from sources we cannot pull directly. |
| Admin overlay | The same per-client URL viewed by an FPM team member with admin role — adds edit controls and internal-only tabs. |