One moment.
Sign in
Enter the email you signed up with and we'll send you a login link.
Check your inbox.
The link works once and expires in 15 minutes.
Admin panel
Customers, the modules they see, and who gets what at each tier.
Not available
This area is for the Originate team. If you think you should have access, email hello@weareoriginate.com.
Loading customers…
Click a customer to manage their modules below. More columns are coming.
Each module unlocks at a tier and every tier above it. Edit and save per row.
| Module | Label | Description | Maintain | Grow | Perform | Sort |
|---|
New things Originate builds land on customer dashboards from here.
Look a customer up to grant early access or lock a module for them alone.
| Module | Included from | State | Decided by | Override |
|---|
Every audit in the 5 Pillars tool — the same queue the audit admin panel shows.
The audit bridge is not configured. Set AUDIT_APP_URL and AUDIT_BRIDGE_TOKEN on the Worker (matching the audit app's PORTAL_BRIDGE_TOKEN).
| URL | Status | Score | Paid | Submitted |
|---|
Operational toggles on the audit engine.
Discount codes for the report unlock (Stripe promotion codes).
| Code | Discount | Active |
|---|
Drop the *-audit.json from the audit skill. It auto-matches to the right audit by its auditId and builds the report as a preview. No fields needed.
Upload an Apollo CSV (business metadata) or a ZIP of audit JSONs. Processing is queued on the engine; history appears below.
Loading import history…
| Started | Source | Type | Status | Rows | Created | Updated | Failed |
|---|
Contacts
Every email captured across the site — Diagnostic requests, leaderboard report downloads, payments, accounts, quizzes, and login requests — unified per person. Click a row for the full activity timeline.
| Sources | Audits | Downloads | Opt-in | Last seen |
|---|
How Originate is built
A living reference for the Originate platform — architecture, the three services, data stores, the audit pipeline, integrations, and the admin API. Kept in sync with the deployed system.
Overview
Originate runs as three Cloudflare Workers plus a Cloudflare Container, wired together with service bindings and queues. Everything is serverless, edge-deployed, and pay-per-use.
- originate-site — the marketing site + Diagnostic intake (Astro, served as static + a thin worker). Public origin:
originate-site.aaron-7fc.workers.dev. - originate-portal — the customer account app + this admin dashboard + Ori onboarding (Hono API + Astro frontend in
app/dist). Origin:originate-portal.aaron-7fc.workers.dev. - originate-audit-engine — the leaderboard, audit intake/lifecycle, report rendering, and transactional email. Origin:
originate-audit-engine.aaron-7fc.workers.dev. - originate-auditor — a Cloudflare Container (Docker + Chromium/Playwright) that runs the 5-Pillar audit pipeline. Called by the engine via service binding.
Tech stack
| Layer | Tech |
|---|---|
| Runtime | Cloudflare Workers (+ Containers, Durable Objects) |
| API framework | Hono (TypeScript) |
| Frontend | Astro + Tailwind CSS |
| Database | Cloudflare D1 (SQLite) via Drizzle ORM |
| Object storage | Cloudflare R2 (audit JSON, report assets, import staging) |
| Queues | Cloudflare Queues (emails, imports, auto-audits) |
| Auth | Magic-link (JWT via jose); admin via bearer token |
| Payments | Stripe (embedded checkout, webhooks) — test mode until cutover |
| Resend (verified domain: mail.weareoriginate.com) | |
| Audit container | Python + Playwright (Chromium), OpenRouter (Gemini) scoring |
| Validation | Zod (audit-data schema) |
Audit engine — bindings & data
| Binding | Type | Resource |
|---|---|---|
DB | D1 | originate-audit-engine (audits, leaderboard, payments, email_events, settings) |
AUDIT_DATA | R2 | originate-audit-data — audits/{id}.json, leaderboard/{businessId}.json, imports/… |
AUDITOR | Service | → originate-auditor container worker |
EMAIL_QUEUE | Queue | audit-engine-emails (confirmation, report-ready, unlock) |
IMPORT_QUEUE | Queue | audit-engine-imports (CSV/ZIP bulk import) |
AUDIT_QUEUE | Queue | audit-engine-audits (auto-audit-on-submit dispatch) |
Cron: 0 4 * * * daily — retries young failed emails, prunes stale import staging, and reconciles stuck auto-audits (recovers lost container callbacks). Report JSON lives in R2 (not D1); rows carry a has_audit_data flag. Auto-audit results are stored at audits/{id}.json; bulk-imported leaderboard reports at leaderboard/{businessId}.json.
Auto-audit pipeline (Diagnostic → report)
- Visitor submits the Diagnostic form → engine
POST /api/intakecreates a lead, queues the confirmation email, enqueues toaudit-engine-audits. - The audit consumer calls the originate-auditor container
/runin async mode (passes a callback URL). The container runs Playwright crawl → OpenRouter scoring (~2–4 min) in a background thread. - Ecommerce sites are detected and scored on the ecom variant rubric (rubric-ecom.json); service businesses use the standard rubric. Both produce the same 5-pillar / 100-point shape.
- The container POSTs the result to the engine
POST /api/audit-callback. - The engine validates (Zod), stores the JSON in R2, and — if auto-publish is on — publishes, emails the customer the results, and notifies the team.
dead/failedoutcomes notify the team only.
Why async/callback: a queue consumer can't block ~200s on the container, so the container owns the long job and calls back. The consumer fires-and-acks (only retries:2 on dispatch); a lost callback is recovered by the daily cron reconciliation sweep, not queue redelivery. Auto-publish is an engine setting.
Scoring: 4 pillars × 20 binary checks (0–80) + Design Quality by-eye (0–20) = 100. verify.py enforces each pillar's score equals its PASS count and the total matches the exec summary. ecom is a success status (scored on the ecom rubric), treated like ok.
Emails (Resend)
| From | Trigger | |
|---|---|---|
| Diagnostic confirmation | audits@mail. | form submit |
| Diagnostic results (score) | audits@mail. | audit publishes |
| Report unlocked / leaderboard report | audits@mail. | paid unlock |
| Magic sign-in link | hello@mail. | login request |
| Account ready (welcome) | hello@mail. | Foundations checkout |
| Team notifications (plain text) | audits@mail. | new request, published, payment, signup, failure, etc. → aaron@ |
Sender must be the Resend-verified mail.weareoriginate.com subdomain. Engine emails go through a queue (transient retries, permanent 4xx skipped). Portal emails (magic-link, welcome) are sent directly — no retry net; links expire in 15 min.
Portal — bindings & routes
DB(D1: originate-portal) ·ASSETS(Astroapp/dist) ·AUDIT_ENGINEservice binding → the engine.- API:
/api/auth(magic-link),/api/checkout+/api/stripe/webhook(Foundations),/api/onboarding+/api/documents(Ori),/api/audits(engine bridge),/api/admin(this panel),/api/quiz,/api/me. - Frontend served from
app/dist; API routes run worker-first (/api/*,/healthz).
Admin / integrity API (engine — bearer auth)
Authenticated with ADMIN_API_TOKEN or PORTAL_BRIDGE_TOKEN (the same token the portal bridge uses; PORTAL_BRIDGE_TOKEN must equal the engine's AUDIT_BRIDGE_TOKEN).
| Endpoint | Purpose |
|---|---|
POST /api/admin/import | Bulk import (CSV/ZIP) → staged to R2 → import queue |
GET /api/admin/import-runs | List import runs + files |
GET /api/admin/r2-audit | Integrity scan: businesses flagged has-data vs R2 objects present. Returns the missing set. |
POST /api/admin/r2-backfill | Repair: write a batch (≤200) of {id, data} report JSONs to R2 (Zod-validated). |
… /api/portal/admin/* | Audits list, settings (auto-publish, pricing, paid-reports, public base URL), coupons, audit import/publish/transition. |
The r2-audit / r2-backfill pair repaired a partial-import gap where 2,346 of 9,565 leaderboard businesses had a has_audit_data flag but no R2 object (every "view report" 404'd). Re-run r2-audit after any bulk import to confirm 0 missing.
Domains & cutover
Live on *.aaron-7fc.workers.dev preview origins. At cutover, custom domains map to: weareoriginate.com (site), app.weareoriginate.com (portal), audit.weareoriginate.com + leaderboard.weareoriginate.com (engine). The engine's report-link base is a switchable DB setting (public_base_url) — change it in settings at cutover, no redeploy. Stripe stays test-mode until live keys are added.