1 · URL & personalization
| Param | Meaning | Example | Default |
|---|---|---|---|
f | Firm display name | f=Hale+%26+Mercer | "Your Firm" |
p | Practice area (pi, estate, family, immigration, business) | p=pi | business |
s | Firm slug — keys the logo file and the send token | s=halemercer | none |
k | Signed send-token (only on links where live send is enabled) | k=eyJ... | absent → simulation only |
Logo system: per-prospect logo committed at /logos/{slug}.png. On load: if s is present and the logo exists, it renders in the demo header and document previews; otherwise a neutral mark + firm-name text. Adding a prospect = drop one PNG, commit, push. No code changes per prospect.
Sanitization: escape f, cap lengths, strip anything URL-like. All params are untrusted input.
Link generator (/make, noindex): firm name, slug, practice area, optional live-send enablement (prospect email domain + expiry) → outputs the personalized URL. 60 seconds per prospect.
2 · The tool toggle — one page, two buyers
A prominent pill button in the hero: "Already on Clio, MyCase, or PracticePanther? Tap here →". Tapping switches the entire page between two stakeholder framings:
| Default mode (standalone e-sign or no system) | PM mode (toggled) | |
|---|---|---|
| Hero | "{Firm}, stop paying per seat to send documents." | "{Firm}, your intake and your documents should talk to each other." |
| Cost slider | Savings math vs. per-seat e-sign plans | Reframed as time math: hours/week of retyping × staff rate → annual cost of manual handling. Same component, different formula and labels. |
| Integration caption | — | "Works alongside your intake tool — we read from it, we don't replace it." |
The toggle doubles as qualification telemetry — an analytics event fires on tap, so we know what the prospect runs before the first call.
3 · Page structure
§A Hero
Firm name, logo if present, mode-aware copy, toggle button, CTA anchors ("Try the send flow" / "See the math").
§B Interactive send demo
Three-step simulation: template → recipient → live status dashboard with a Remind button and audit-trail modal. Template cards render the practice-area engagement letter with the firm's letterhead and merge fields highlighted.
Live-send button (rendered only with a valid k token — §6): "Send this to yourself for real →". The prospect signs the demo letter on their own phone. Every sent document carries the SAMPLE disclaimer.
§C Intake → auto-fill
Three-field mini intake form live-renders into the engagement-letter preview. This is the conversion section.
§D The gap calculator — no fee disclosure
currentAnnual = seats × rate × 12 // flag if vol×12 > seats×100: "over the per-seat envelope cap — // your real bill is higher than this." sendingCost = 300 + max(0, vol−100) × 0.25 × 12 gap = currentAnnual − sendingCost
"Our build and support fees come out of that gap — scoped to your firm's needs on a 15-minute call. If the total doesn't beat your current bill, we'll tell you, and the call ends early."
Honesty rule: if the gap is small (<$1,000 at their settings), don't inflate — show "at your size this is a workflow play, not a cost play" and emphasize §C instead. Never fake a big number.
§E Compliance strip
ESIGN/UETA, audit trail, SOC 2, HIPAA-capable — and wet-ink exclusions (wills/codicils) stated plainly.
§F What you own + CTA
Repo handoff, the e-signature account in the firm's name, month-to-month support — no annual lock-in. No fee figures anywhere in this section. Closing line: "Bring your current invoice — if we can't beat it, the call ends early."
4 · Engagement letter templates
Five practice-area letters, selection driven by p. Each renders with firm letterhead, live-bound merge fields ({{client_name}}, {{matter_description}}, {{fee}}, {{date}}), and a visible footer in all rendered and sent versions:
"SAMPLE DOCUMENT — for demonstration purposes only. Not legal advice. Production systems use the firm's own approved language."
That disclaimer is non-negotiable: we are not supplying legal language to law firms, we're demonstrating plumbing.
5 · Build plan (1–2 days for v1, simulation-only)
- Param parser (
f,p,s) + logo loader with fallback - Mode toggle + two-key content config
- §D slider with both formulas + honesty state (unit-test the math)
- §B send simulation + letter templates wired to
p - §C live merge preview
/makegenerator (link only; token minting ships with v1.5)- Deploy, DNS, param/mode matrix test, Lighthouse, noindex
Live send is v1.5 — it ships, but never delays v1 outreach. Build cost ≈ half a day (one serverless function + token minting + rejection tests). Marginal cost per prospect after that: zero.
6 · Live send: bot-protection spec
Threat model, in priority order: (1) spam relay — bots using the endpoint to email arbitrary addresses, poisoning sender reputation; (2) resource abuse of the serverless function; (3) harassment via a leaked link.
| # | Control | Implementation |
|---|---|---|
| 1 | No public endpoint behavior. Send exists only with a valid k token; everything else renders simulation only. | HMAC-signed payload {slug, allowedDomain, exp}; secret in env vars, never client-side; signature + expiry verified on every call. |
| 2 | Recipient domain lock. A leaked link cannot email anyone outside the prospect's own domain. | Server-side check; client pre-locks the domain portion of the email field. |
| 3 | Hard caps. 3 sends/token/day, 10 lifetime, per-IP rate limit. | Counter in a KV store; in-function throttle. |
| 4 | Invisible CAPTCHA on the send action. | Client widget → server-side verification before sending. |
| 5 | Honeypot + timing check. | Hidden field must be empty; reject submissions <2s after render. |
| 6 | Test-mode envelopes only. No billing exposure even if everything else fails. | Separate API key from any production client work. |
| 7 | Token expiry, 30 days. Stale links die — and refresh is a re-engagement excuse. | exp in payload, set by /make. |
| 8 | Logging + alert. | Every attempt logged (slug, IP, outcome); alert on rejection spikes. |
Residual risk after controls: low. Worst case with a leaked valid link is a handful of test-mode sample letters to the prospect's own domain — annoying, capped, recoverable. The catastrophic failure mode (open spam relay) is structurally impossible: no token → no send path.
7 · Definition of done
- Logo loads for slugged prospects; falls back cleanly when absent or broken
- Tool toggle switches all four mode-aware surfaces with no layout shift
- All five practice-area letters render with merge highlighting; SAMPLE footer visible in preview and any sent envelope
- No fee, retainer, or build-price figure appears anywhere on the public site — grep the build output
- Gap calculator's modest-gap honesty state triggers correctly at low-seat/low-rate settings
- (v1.5) Send rejected without token, with expired token, to off-domain address, over daily cap, and with failed CAPTCHA — all five rejection paths tested
- Analytics events: page open, mode toggle, slider interaction, send attempt