# Agent Tracker — white label, email designer, lead CRM (2026-10-14)

## Deploy

1. Upload the changed and new files (list below) over the live copy. Keep the live `.env`.
2. **No SQL to run.** On the first request the app adds what it needs (`email_templates.design`,
   `cards.follow_up_at / follow_up_note / last_activity_at`, `card_notes.edited_at`, more
   `card_notes.kind` values, and a new `media` table), then writes the marker file
   `storage/logs/.schema-20261014` so it never checks again. If the DB user has no ALTER rights,
   run `sql/2026-10-14-white-label-crm.sql` by hand instead.
3. Hard-refresh. Every changed CSS/JS file has a new `?v=20261014wl2` tag, so browsers fetch fresh copies.

Nothing needs to be writable on disk for logos or banners: images are stored in the database
and served from `/api/media/<hash>.<ext>` (public, cached for a year) so email apps can load them.

## Files

New: `app/brand.php`, `app/routes_whitelabel.php`, `public/js/whitelabel.js`,
`public/css/whitelabel.css`, `sql/2026-10-14-white-label-crm.sql`, `tests/white-label/*`

New (update): `public/js/vendor/sortable-1.15.6.min.js`, `public/js/vendor/sortable-LICENSE.txt`

Changed: `app/bootstrap.php`, `app/mail.php`, `app/routes.php`, `app/recruiting.php`,
`public/index.html`, `public/login.html`, `invite.html`, `forgot.html`, `reset.html`,
`register.html`, `public/css/app.css`, `public/css/auth.css`, `public/js/app.js`,
`public/js/auth-pages.js`, `public/js/overview.js`, `public/js/pipeline.js`,
`public/js/settings.js`, `public/js/team.js`

## Update — 10/14 lead window: corners + movable

- **Corners:** the lead window now clips its tinted header and the grey Activity side to its rounded
  corners (they used to paint square edges past the rounding). Slim scrollbars without arrow buttons.
- **Movable (desktop):** drag the window by its header (the grip at the top shows it). It stays fully on
  screen side to side and its header always stays visible; letting go over the dim background doesn't close
  it; fields, buttons and the stage dropdown inside the header still work normally. The next lead opens
  where you left it (for that browser tab); double-click the header to put it back in the centre. On phones
  the window stays full-screen. Reusable: `S.makeMovable()` in `public/js/agent-ui.js`.
- Test: `win_test.py` (14).

## Update — 10/14 sample agents in the left-side list

- **Fixed:** after "Load 20 sample agents" (or "Remove sample data") the left-side agent list kept its old
  contents until the page was refreshed. Both buttons now refresh that list too (`public/js/whitelabel.js`).
  No cap on the list: staff see every active agent, sorted by name.
- Test: `roster_test.py` (desktop + phone).

## Update — 10/14 Settings link + phone banner

- **Settings moved to the bottom left** of the sidebar, above the signed-in user (it was in the main
  Navigate list). It highlights while you are in Settings. The Account button beside the user now has a
  person icon so there aren't two gears side by side. (`public/js/app.js`, `public/css/whitelabel.css`)
- **Fixed: on phones the yellow "Sample data" banner covered the menu button** — the banner wrapped to three
  lines but the page only made room for one. The page now measures the banner's real height, and on phones
  the banner is one short line ("Sample data — demo agents only").
- Test: `settings_link_test.py` (desktop + phone).

## Update — 10/14 redesign (Overview, Onboarding, System, Pipelines)

Built to the four approved mockups, desktop and phone. New: `public/js/agent-ui.js` (shared icons,
the mountain hero art as crisp vector, stage colours) and `public/css/agent-ui.css`. Changed:
`overview.js`, `onboarding.js`, `system.js`, `pipeline.js`, `app/demo_seed.php`, `index.html`.

- **Overview** — mountain hero; "Welcome back, <first name>" when it's the agent's own tracker
  (including Viewing as), the agent's name for staff; progress on dark glass; icon tiles per pipeline;
  onboarding phase cards with the current phase highlighted; Profile with an icon per row; family chips
  (spouse, children with ages, pets); story; Dreams & Goals; Office Hours.
- **Onboarding** — hero "Welcome to <agency>" with the agency name in the accent colour and a quote
  card (Settings → Onboarding `tagline`, else a default); First things first cards with icons; colour
  tool tiles; four-column roadmap you can check off right there; Open the checklist; expectations cards.
- **System** — header card with ring, Expand all / Collapse; numbered phases with % and bar; an open phase
  shows its step groups beside a guidance panel (steps left, and "Licensing unlocks everything" on the
  licensing phase). A › on a step shows its help text (only when the step has some) without checking it.
- **Pipelines** — stage colour dots, ⋯ per column (add a lead here, select everyone here, edit stages),
  an empty-column state, occupation and city on one row, Hot leads flagged with a flame, leads in a won
  stage highlighted. **Phone**: stages are an accordion (first stage with people opens); ⋯ on a card opens
  the phone's own stage picker to move it.
- Sample data: every sample agent now has family on file.
- Progress rings use a cool grey track (the mockups' cream track would read beige).
- Tests: `redesign_test.py` (44, desktop + phone), `viewas_test.py`.

## Update — 10/14 late

- **Sample data now loads in the PropHog workspace too.** The Settings button refused the shared
  `prophog` workspace (a guard copied from the old automatic demo). An owner clicking Load is an explicit
  request, so it is allowed everywhere; only the automatic first-run demo still skips that workspace.
  Removal still only deletes the DEMO-coded sample agents.
- Error messages are a clear red (were brown). Settings-menu tooltips show beside the menu. The selected
  sidebar item is a neutral light lift with the accent bar (the accent tinted over the dark menu looked
  muddy). The collapse button no longer overlaps a long agency name.
- Test: `prophog_test.py` (loads samples in a workspace with the `prophog` slug).

## Update — 10/14 evening

- **Sample agency** — Settings → Sample data (owners): "Load 20 sample agents" / "Remove sample data".
  Or on the server: `php bin/seed-demo-agency.php <workspace-id|slug>` (add `--clear` to remove).
  Each agent: birthday, NPN, level, dates, spouse, children with ages, pets, back story, office hours,
  checklist progress (stage worked out the same way the app does), licenses, carrier appointments,
  4–6 dreams, 4–5 goals, 60–140 leads across all six pipelines and their stages with **every card field
  filled**, background notes, notes/calls/texts/emails/meetings/stage moves over the last 60 days,
  follow-ups (overdue, today, upcoming), and 60 days of daily production + recruiting numbers. Four
  agents lead small teams. Sample agents use agent codes DEMO1–DEMO20; removing them never touches real
  agents. Loads in about 1–2 seconds. New file: `app/demo_seed.php`, `bin/seed-demo-agency.php`.
- **Sidebar quick links**: rounded, calm hover with an "opens in a new tab" arrow. Tooltips for anything
  in the dark menu now show beside the menu (white, with a pointer) instead of navy-on-navy on top of
  it, and no longer flicker off when the pointer crosses a link's icon or text (`public/js/core.js`).
- Tests: `sample_test.py` (33), `tip_test.py`, `phone_sample.py`.

## Update — 10/14 afternoon

- **Moving leads between stages now uses SortableJS** (the same mover as the Pledge board), bundled
  at `public/js/vendor/sortable-1.15.6.min.js` — no CDN. It runs on its own pointer handling, so it
  works with a mouse, pen or touch screen and doesn't depend on the browser's built-in drag-and-drop
  (which was failing on the live machine). A drag never opens the record; a click still does.
- **The board fills the screen**: the 1400px cap around the Pipelines tab is gone, columns stretch to
  fill the width and run to the bottom of the window, 6px between columns.
- **Cleaner cards** (Pledge layout): initials, name and time-in-stage on one row; phone, occupation and
  city under it (email only when there's no city or occupation); due badge and badges only when set.
- **No workspace switcher in the sidebar.** Superadmins reach other workspaces from Settings → Platform admin.
- New test: `tests/white-label/drag_test.py` (real mouse drags at 1905 and 1440 wide).

## What changed

**Agency brand (Settings → Brand & agency).** Agency name, what the tool is called, a main logo,
an optional logo for dark backgrounds, accent and dark colours (presets or custom; text on them
switches black/white automatically), the sender name for emails and a reply-to address. Applies
to the menu, page titles, every screen's colours, the sign-in/invite/reset pages and every email.
No PropHog or "Agent Tracker" shows to agents unless the agency chooses that name.

- Before the first invite, owners/admins get **"First, set up your agency"** (name, logo, colours,
  live preview). Every invite path goes through it once.
- Agency names are kept as typed. The forced "… Team" suffix is gone; a name typed all in
  lower case is capitalised. Once an agency sets its brand, SSO sign-in from Agent Recruiting no
  longer renames the workspace.
- Sign-in pages: email sign-in is the main action; "Agency owner? Continue from Agent Recruiting"
  is a link under it. An invite link shows the inviting agency's logo and name; any device that
  has signed in shows its agency.

**Email designer (Settings → Emails).** Invitation, Welcome and Password reset, built from blocks
(logo, image/banner, heading, text, button, divider, space, footer): drag or arrow to reorder,
duplicate, delete, undo/redo (Ctrl+Z), insert merge fields, font/colours/corners, live Desktop
(real 600px email) and Mobile (375px phone) preview, Send me a test, Restore the original. Preview,
test and real sends all use one renderer (`email_render()` in `app/brand.php`). Invites and resets
can't be saved without their link. Text is cleaned server-side (formatting kept, scripts/handlers/
`javascript:` links removed). Emails come from the agency's name; invite replies go to whoever sent it.
The password-reset text message is edited on the same page.

**Lead CRM (Pipelines).** Pipeline dropdown with counts (no pill row); Overdue / Due today / This
week strip that filters the board; cards show only what is on file, with a due badge and the next
step. The lead record: Call / Text / Email, the stage dropdown in the header (any pipeline — picking
another pipeline's stage moves the lead and its history), Details beside Activity on wide screens
(tabs on narrow), follow-ups with Today 5pm / Tomorrow / In 3 days / Next week / a date, a composer
that logs a note, call, text, email or meeting (Ctrl+Enter), an editable timeline, and autosave.
Phones pick the stage from a dropdown and open on the first stage that has someone in it.

**Removed:** the team leaderboard (All agents and Overview). Overview now shows the agent's
follow-ups; clicking one opens that lead.

## Bugs fixed on the way

- "Move to another pipeline" called `/cards/:id/transfer`, which did not exist on the server.
- The password-reset email ignored its template (hard-coded HTML).
- Every email's From line read "PropHog Agent Tracker".
- Cards printed "No phone" / "No email" placeholders.

## Tests (all passing)

- `tests/white-label/api_test.py` — 31 checks against the real PHP + MySQL.
- `tests/white-label/ui_test.py` — 102 checks in a real browser, desktop 1440 and phone 390,
  including no sideways scroll on every screen and no script errors.

Run both against a dev copy (see README §6); `reset_at.sh` rebuilds a clean demo workspace.
Google Fonts (Inter) were not reachable from the test machine, so screens were checked in the
fallback font; the live site loads Inter as before.
