Sole developer, end to end
Express Ops
Operations platform that turns manifest photos into driver lists, double-booking checks and customer documents.
Status: In daily use by the operations team
The problem
Tour-transfer teams were rebuilding daily driver lists and customer documents by hand from photographed manifests, against a departure clock. A miscount or a double booking has to be caught before a vehicle leaves, not after.
What I built
I built a role-based web app that reads the photographed manifests, reconciles each one against the totals printed on the page, flags double bookings, and produces the finished driver lists and customer documents.
OutcomeIn daily use by the operations team. I estimate it saves them roughly 3–5 hours a day.
What it does
- Manifest extractor: OCR per image, reconciled against the footer totals; failures and mismatches go to an editable review queue with undo.
- Driver's List: batches of per-shift screenshots become one styled XLSX with per-driver subtotals and a grand total.
- List Maker: imports group workbooks, classifies bookings, routes languages by agency and phone country, exports formatted DOCX lists.
- Double-booking detector ranks duplicate guests across or within agencies by severity.
- Customer Lists with role-aware import, live restaurant rosters, presence and audit workflows. Guides see only their own surface.
- Saves the operations team roughly 3–5 hours a day.
Try it
A working replica of the real interface, running on made-up sample data.
Architecture
How the pieces connect, drawn from the project's own documentation.
Engineering decisions
- Check every OCR result against the totals printed in the image footer, and send mismatches to an editable review queue instead of exporting them. Wrong counts surface before a vehicle leaves.
- Keep a person in control of corrections: rows and footer totals are editable in place, and the last reprocess can be undone with Cmd/Ctrl+Z, even after a reload.
- Treat the visible DOCX as authoritative. Embedded metadata is only a fast path when its fingerprint exactly matches the visible document, so manual edits always win.
- Store immutable driver and plate snapshots on each daily list, so editing a preset later never rewrites historical origins.
- Send server-to-server calls over the internal Docker network. Going through the public hostname triggered Cloudflare's managed challenge and broke Server Component rendering, so the app reads internal URLs first and falls back to public ones for local development.
- Gate production on CI: main is the sole production branch, and the commit that passed audit, lint, tests, typecheck and build is the one deployed over SSH, followed by a sign-in check.
- Invite-only, role-based access (admin, operator, guide) with no public sign-up; guides see only the Customer Lists surface.
How it's secured and shipped
- Every push and PR runs a dependency audit, lint, unit tests, typecheck and a production build.
- A green push to main deploys the same commit to the production host over SSH, then verifies the sign-in endpoint.
- Recent audit failures (ip-address, undici advisories) were patched via lockfile-only updates.
- Server-to-server calls use internal Docker-network URLs so they never hit the Cloudflare managed challenge.
- Role-gated navigation, MFA in account settings, and a non-root multi-stage Docker image.
Stack
- Next.js
- TypeScript
- Convex
- Mistral OCR
- Docker Compose
- GitHub Actions
- Vitest