Role: Main developer in a team of four senior engineers — designed and built the core platform end to end: the SmartSync ETL and its move to Temporal, the CDC projection into the ClickHouse read model and the PostgreSQL mirror, the Express + Sequelize API, the Next.js frontend on Cloudflare Workers, the Python AI content service, and CI/CD.
What it is. Main developer in a team of four senior engineers on a 7-package monorepo whose core is a data platform: the SmartSync ETL on Temporal, CDC into a ClickHouse read model, a PostgreSQL mirror, an Express + Sequelize API, a Next.js frontend on Cloudflare Workers and a SLED Admin SPA.
Data layer. 32 Temporal schedules on 6 task queues ingest SAM.gov and USAspending.gov data into PostgreSQL (~7M contracts, ~94M award transactions); completeness is checked against SAM.gov's own files (0 of 80,922 active notices missing), and ClickHouse is kept in checksum parity with PostgreSQL.
Speed and caching. A headline query cut from 13.6 s to ~1 s, a single-flight guard on the API response cache, React Query / ISR / API cache TTLs aligned at 10 min (worst-case feed lag ~3–5 h → ~10 min), and Next.js 16 on Cloudflare Workers via OpenNext, where I added the D1 tag cache that makes on-demand revalidation work.
Deployment. Tests gate every deploy across 24+ workflows on a self-hosted runner; the backend moved from Railway to Hetzner and then to OVHcloud (August 2026, after a change of stakeholders), with the frontend on Cloudflare.
Engineering: Data Platform, AI & Frontend
Main developer on GovChime: the data platform, the AI features, and the frontend performance work, one view at a time.
A Temporal-orchestrated ETL from SAM.gov into PostgreSQL, projected by CDC into a ClickHouse read model and mirrored to a second PostgreSQL — every hop is checked against a second copy of the data.
Orchestrate — Temporal
Temporal is the control plane: Schedules start Workflows, rows never pass through it. Production cut over on 2026-09-25 and the legacy scheduler was deleted.
Extract
Every SAM.gov call runs on one task queue with a queue-wide rate limit and leased API keys.
Transform + Load
One canonical transform per source, then change-aware idempotent upserts into PostgreSQL — a failed window just reruns.
Verify
A green run proves execution. Completeness is proven against a second copy of the source.
A green run proves execution, not completeness — every dataset is checked against a second copy of the source.
0 of 80,922 active notices and 0 of 733,627 FY2025–26 archive notices missing against SAM.gov's own files; PostgreSQL and ClickHouse checksums match on 94.4M award transactions.
Enrich
Follow-up pipelines fill what the source APIs leave out, started by each source run and backed by their own Schedules.
~7.06M contracts · ~1.48M entities · every pipeline writes here
~94.4M award transactions · fed by CDC · analytics reads here
CQRS read model — ClickHouse
PostgreSQL stays the write model; one Temporal coordinator per table projects new rows into ClickHouse, and a daily reconciliation proves parity.
PostgreSQL mirror
A logical-replication mirror of production into a second PostgreSQL, run as Temporal Workflows on its own worker.
Serve
Express + Sequelize API reading the ClickHouse read model, with a ClickHouse → Postgres fallback chain that was later simplified.
Present
Next.js 16 frontend on Cloudflare Workers via OpenNext, with cache freshness matched to the sync cadence.
9. Guards & alerts
cross-cutting · spans every layerScheduled guards watch the pipelines themselves; alerts are stored and shown in the admin UI.
10. Delivery
cross-cutting · spans every layerTests gate every deploy; each push to main deploys SmartSync, then the app.
11. Infrastructure
cross-cutting · spans every layerSelf-hosted compute on OVHcloud, fronted by Cloudflare.
Key Features
- 7-package monorepo: SmartSync ETL on Temporal, Express + Sequelize API, Next.js on Cloudflare Workers, SLED Admin SPA
- SAM.gov + USAspending.gov ingestion checked against SAM.gov's own files (0 of 80,922 active notices missing)
- ClickHouse read model over ~94M award transactions in checksum parity with PostgreSQL; headline query 13.6 s → ~1 s
- Next.js on Cloudflare Workers: D1 tag cache for on-demand revalidation, edge-cached sitemaps, TTLs aligned at 10 min
- ~242 API endpoints, 78 filters, iron-session + JWT hybrid auth, Stripe billing, PostHog analytics (67 events)
- Tests gate every deploy; backend moved from Hetzner to OVHcloud (August 2026); frontend on Cloudflare Workers
Tech Stack
Data Platform / ETL
Backend
Frontend & Edge
Database & OLAP
Infrastructure
AI & Dev Tools
Challenges & Solutions
An ETL That Must Prove It Is Complete
The SAM.gov pipelines ran on a hand-rolled scheduler, and a green run only proved that code executed. The opportunities sync once reported success while holding only 17.5% of notices — API-key quota starvation, plus a completeness check that passed when nothing was proven.
Rebuilt SmartSync on Temporal: 32 schedules on 6 task queues, per-window extract → transform → load → verify, a 13-key SAM.gov pool with a usage ledger, and replay tests of production histories in CI. Completeness is checked against SAM.gov's own files — 0 of 80,922 active notices and 0 of 733,627 FY2025–26 archive notices missing. Production cut over on 2026-09-25 and the legacy scheduler was deleted.
Keeping ClickHouse and a Mirror in Exact Sync
Analytics read from ClickHouse, and a second PostgreSQL needs a live copy of production. Both drift silently if nothing proves they match.
Rewrote the teammate's first PostgreSQL → ClickHouse copy scripts with checkpoints and a parity check and moved them onto Temporal. PostgreSQL is the CQRS write model; a coordinator per table projects new rows into ClickHouse by watermark (query-based CDC), and a daily reconciliation compares counts, distinct ids and checksums — contracts, entities and 94.4M award transactions match. The PostgreSQL mirror uses logical replication (pgoutput; snapshot, then streaming) as Temporal Workflows, with hourly slot-lag checks and a daily count-and-hash reconciliation.
Slow Queries and Stampedes on ~94M Rows
A headline Postgres query took 13.6 s because it applied a slug function to every row of an 89M-row table, which forces a full scan. Separately, concurrent requests for the same heavy ClickHouse count could pile up into several multi-GiB scans at once.
Filtered on a trigger-maintained indexed slug column with a 2-year window instead (13.6 s → ~1 s) and on an agency-code lookup in ClickHouse (2.2 s → 0.27 s). Added a single-flight guard to the API's in-memory response cache, so concurrent callers share one query and a failed refresh serves the last good value. Built the ClickHouse → Postgres fallback chain on the team's ClickHouse read model, then simplified it — 32 Postgres MVs dropped, ClickHouse MVs 31 → 14.
Next.js Caching on Cloudflare Workers
The Next.js 16 frontend runs on Cloudflare Workers via OpenNext with an R2 page cache. With a long-lived regional cache and no tag cache, a published page kept serving the stale copy and on-demand revalidation did nothing; in the worst case feed pages lagged the database by ~3–5 hours.
Switched the regional cache to short-lived mode and added a D1 tag cache, so revalidatePath and revalidateTag take effect after a publish; aligned the React Query, ISR and API cache TTLs at 10 minutes (worst-case feed lag ~10 min by design); and edge-cached the sitemaps with the Cloudflare Cache API.
AI Content Without Invented Figures
AI-generated blog, social and SEO copy about federal contracts must never state numbers the data doesn't support.
A Python AI content service generates the copy from contract data, a guard strips any AI-stated figure not present in the source data, and every piece goes through a human review queue. It moved from the Anthropic API to Cloudflare Workers AI (Llama 4 Scout) in September 2026.
Silent Data Loss in Ingestion
For 10 days the SAM.gov sync reported success while silently dropping ~95–99% of records: SAM.gov changed `totalRecords` from a number to a string, the pipeline read it as null, `null ?? 0` coerced it to 0, and the completeness check `0 >= floor(0 × 0.95)` always passed — no exception thrown, no alert.
A `parseTotalRecords()` helper that accepts both string and number shapes and treats any NaN / 0 / missing value as an API error (triggering key rotation) rather than coercing to 0. The deeper fix was completeness verification comparing expected vs actual counts — `no exception thrown` does not mean the data is correct.