Skip to content
Rafael Rojas

OrigenLab

Commercial software for a laboratory-equipment business: public site, email intelligence pipeline, operator API behind a Cloudflare Worker, CRM dashboard, and a Supabase V2 data platform under migration

Status
Production (CTO)
Years
2026
Repository
1542 commits last push Oct 2026
Stack
Astro Tailwind CSS TypeScript React Vite Python 3.12 uv FastAPI SQLite PostgreSQL 17 Supabase Alembic pgTAP Cloudflare Workers Cloudflare Access pytest Playwright

OrigenLab sells laboratory equipment across Chile. Its software has to turn years of email into a commercial memory, let operators act on it, and never send a message the business would regret. The work is mostly boundaries: who may write what, through which path, with what evidence.

Screenshots show the public site only. Dashboard, pipeline, and data are described, not shown; no customer or message content appears here.

origenlab.cl homepage on desktop: headline, six-point application diagram, and the list of equipment families
origenlab.cl, October 2026. The homepage leads with what a laboratory needs to do with its sample, then lists six equipment families from six manufacturers.
Centrifuges product family page with the Ortoalresa brand and the first catalogue model
A product family page. Figures come from manufacturer documentation and are validated in CI before the site builds.
origenlab.cl homepage on a phone
The same page at phone width. Interaction QA covers the mobile menu, keyboard order, and reduced motion.
01

Problem

Years of commercial history lived in mailboxes and PST archives. Nobody could say which organisations had bought, which threads were still warm, or which addresses must never be contacted again. Quotations were built by hand and sent from personal accounts.

The business needed software that matched how it actually works: review before send, evidence for every claim, and a schema that answers operational questions without exposing raw mail to everyone.

02

What runs today

V1 is a monorepo of five deployable parts. Each one has a single job and a documented list of things it must never do.

  • apps/web: the public site, rebuilt in September 2026 as static Astro. Six equipment families, six manufacturer pages, application and category hubs, one quotation call to action. Deployed to shared hosting with security headers.
  • apps/email-pipeline: Python 3.12 with uv. PST and Gmail ingestion into SQLite, business marts, commercial intelligence, outbound safety memory, and an operator CLI (status, daily health, refresh safety, build mart, mirror dashboard). The machine write path.
  • apps/api: FastAPI on port 8001. Dashboard reads, read-only Postgres mirror reporting, and the only human write path: durable CRM commands under POST /operations/* with trusted operator identity, Idempotency-Key receipts, and optimistic concurrency.
  • apps/dashboard-proxy: a Cloudflare Worker at dashboard.origenlab.cl/api. Method and path allowlist, Cloudflare Access service token plus origin API token, upstream redirects and cookies stripped, every other method answered 405. The browser never holds a token.
  • apps/dashboard: the React CRM. Google Workspace sign-in, eight sections (summary, opportunities, organisations, people, suppliers, Drive archive, marketing, review), role-based masking for viewers, and labels that say when a case is imported history rather than live work.

Responsibility map

Each component owns one thing and carries a list of what it must never do. The lists are tested where they can be, and written down where they cannot.

apps/web Astro, static
The public marketing site: six equipment families, manufacturer pages, application hubs, one quotation call to action.
Never touch operator, CRM, or outbound data.
apps/dashboard React
Presentation and operator interaction: eight CRM sections behind Google Workspace sign-in.
Never hold truth, compute money, call the database, or hold a secret.
apps/api FastAPI
The only business command boundary: authentication checks, validation, idempotency receipts, transactions, domain events.
Never ingest mail, call Gmail, render PDFs, or run long jobs.
apps/dashboard-proxy Cloudflare Worker
Same-origin access to the API: method and path allowlist, Access service token, origin token, response hardening.
Never forward a redirect, a cookie, a non-allowlisted path, or any PUT, PATCH, or DELETE.
apps/email-pipeline, then apps/worker Python 3.12, uv
Gmail and PST sync, the single send path, MIME parsing, PDF rendering, ChileCompra fetching, classification, reconciliation.
Never write CRM tables directly; the one exception is a single privileged function for quote PDF evidence.
PostgreSQL Supabase, 7 schemas
Every durable fact, the closed list of privileged send functions, and the constraints that make the invariants true.
Never store bodies, attachments, or PDFs; hold a browser identity; authorise a human.
03

Who may write what

SQLite in the pipeline is the authority for outbound safety: sent memory, suppression, and outreach state. The API is read-only outside the enumerated command routes, and a CI test asserts the exact write surface and scans the API source for any import of a pipeline script that ingests, migrates, syncs, or sends.

Postgres holds rebuildable machine mirrors plus the durable human CRM. Mirror data is never treated as send truth. Sending is a pipeline script run by a person, with history and suppression checks in front of it.

04

V2: one database, one command boundary

The V2 architecture was accepted in September 2026. Everything moves onto one Supabase PostgreSQL 17 project with seven private schemas (crm, comms, outbound, evidence, catalog, procurement, platform) and 36 application tables. FastAPI becomes the only business command boundary; a Python worker owns Gmail sync, MIME parsing, PDF rendering, ChileCompra fetching, and classification; the dashboard never touches the database.

Every mutation is a POST command with a trusted operator identity and an idempotency receipt. One command is one transaction and writes exactly one domain event, into a table with no UPDATE or DELETE grant. Each table has one writer; sending happens only through a closed list of privileged functions.

Identity comes from Supabase Auth as ES256 JWTs verified against JWKS; the dashboard holds only the publishable key. FastAPI authorises from an operator table, and admin commands require a second authentication factor.

  • Local foundation done: 23 migrations, 4 roles, 139 row-level-security policies, 408 pgTAP assertions, zero security advisor findings.
  • Clean-room rebuild as the recovery procedure: rebuild from migrations, import the evidence waves, verify 41 exact probes against a committed baseline.
  • Hosted audit tooling in the Python standard library: read-only SQL proofs, 308 unit tests, failure-injection scenarios, one completed run against the hosted project.
  • Slices 1 to 7 (auth, CRM identity, quotes, evidence, loading, sender handoff, rollback) not started. V1 remains authoritative until the handoff gate passes.
05

Documentation as infrastructure

Seven canonical documents each own exactly one concern: domain, data, workflows, architecture, migration, operations, and the map itself. Any other document links to the owner instead of restating a rule. Every non-obvious claim is labelled as a V1 fact, a V2 decision, or planned work.

A separate status file reports only what is built, applied, and deployed, with the date and commit it was measured against, and must change in the same pull request as the fact it reports. It owns no rule and cannot override the seven.

06

What I learned

The highest-leverage features were guardrails and auditability, not more automation.

A one-writer rule per table removes a whole class of arguments about which number is right.

When the data is sensitive, folder layout, runbooks, and the list of forbidden operations are part of the product.