Today's portal vs. what we're proposing
A licensed door almost nobody walks through
- License wall: Customer Community Plus is at 180/180 — we literally cannot add another portal user today.
- 19 genuinely active customer users in the last 6 months; most accounts log in once on the day they're provisioned, then never again.
- 40% of all login attempts fail (forgotten passwords, "no community access" errors).
- Salesforce page loads, Salesforce UX, Salesforce license cost per seat.
- Seventh attempt at this problem — six earlier portal shells sit abandoned in the org.
A real product on our own infrastructure
- No licenses, no provisioning: passwordless magic-link sign-in. All 23,191 contacts on recently-active accounts can self-serve access on day one.
- Own database synced from Salesforce every 2 minutes — fast dashboards, zero load on the org.
- Orders, sites, billing, and support tickets in one view; service requests flow back into Salesforce as cases.
- Same stack and AWS platform as our checkout site — patterns we already run in production.
- Vendor portal follows on the same backbone (that's where 156 of the 180 licenses go).
Salesforce stays the system of record. AWS serves the customers.
A sync worker copies only an allowlisted set of fields into the portal's own database — vendor rates, margins, and card data physically never leave Salesforce. Customers get fast pages from our database; their service requests write back through the same proven pipeline our checkout site uses.
SALESFORCE (system of record) AWS (customer experience)
┌───────────────────┐ poll changes ┌──────────────────┐
│ Orders │ every 2 min │ Sync worker │
│ Line items │────(allowlisted ───▶│ (Lambda) │
│ Cases / tickets │ fields only) └────────┬─────────┘
│ Invoices │ ▼
│ Payments │ ┌──────────────────┐
│ Accounts/Contacts │ │ Portal database │
└─────────▲─────────┘ │ (RDS Postgres) │
│ └────────┬─────────┘
│ service requests │
└── written back as Cases ──── ┌─────────┴────────┐
(idempotent, retried) │ streamlink. │
│ ldrsiteservices │
│ .com (Next.js) │
└──────────────────┘
Vendor costs and margins live on the same Salesforce records as customer data — roughly a third of the 468 fields on a line item. The sync allowlist is enforced in code with an automated leak test, so exposing a vendor field would require deliberately editing two lists in one reviewed change.
Version 1: see everything, ask for anything
Deliberately scoped: full visibility plus exactly one write path — a service request that lands in Salesforce as a case. No payments, no self-service ordering in v1; those layer on after the foundation earns trust.
Active units, open balance, recent activity
One glance answers "what's on my sites right now and what do I owe."
Every location, grouped the way national accounts think
Orders grouped by store name and number — a Target facilities manager sees #1142 Dallas, not a flat list of 1,900 orders. Each unit shows an honest delivery lifecycle: scheduled → delivered → removal requested → completed.
Payment history, open invoices, cards on file
Built on the live NetSuite-synced records. Balances per order, last-4 card display only.
Real tickets plus new service requests
Customers see their account's cases (with internal noise filtered out) and submit swaps, removals, and issues — each one becomes a Salesforce case marked "Customer Portal," confirmed by email, tracked in the portal. A request is never lost: it persists on our side first and retries until Salesforce accepts it.
Researched, designed, planned — ready to build
This isn't a slide-deck idea. We mapped the live Salesforce org (row counts, field usage, what's dead and what's load-bearing), wrote the design spec, and produced an 18-task implementation plan with test-first steps — then ran an adversarial review that caught and fixed 15 defects in the plan before a line of product code gets written.
Design input brief
What's actually in our Salesforce org: the data inventory, sync inputs, reuse map from the checkout site, and what the current Streamlink really does.
DesignDesign spec
The locked decisions: architecture, auth model, data model, feature scope, security posture, and rollout plan.
ExecutionImplementation plan
18 tasks from repo scaffold to deploy runbook — each with tests, code, and commands. Full 11,000-line plan available for download.
Found during research — needs action regardless of this project
The org is storing card security codes (CVVs) in plain text on Credit_Card__c.Security_Code__c — 77,945 rows, still being written today. Storing CVV after authorization is prohibited under PCI DSS in any form. A legacy portal object also holds plaintext passwords. Both need an owner and a purge plan this quarter, independent of Streamlink v2.
Pilot small, migrate honestly, then go after the vendor side
Build & internal dogfood
Stand up sync + portal against the UAT org, backfill production history, LDR staff verify against real accounts.
Pilot
The ~19 active portal users plus one or two national accounts, personally invited. Existing portal stays live until parity confidence.
Cutover
Redirect the old portal, free the customer licenses, retire the seventh portal attempt for good.
Vendor surface
Same backbone, separate project — this is where 156 of 180 licenses and the deep ops workflows live, and where the larger savings are.