ROB PETERSON / SYSTEM DESIGN

Charlotte Specials Architecture

I built Charlotte Specials to bring current restaurant specials together in one place, with an emphasis on kids' deals that are easy for families to lose track of. A small maintenance system checks restaurant sources, extracts candidate changes, and updates a Charlotte-only catalog using deterministic software, language-model extraction, and review.

Built and operated by
Rob Peterson
Founder · engineer · operator
Building since March 2026
Public system
Dozens of restaurants
100+ approved specials
Mobile-first Charlotte coverage
Operating constraints
Under $20 per month
Approximately 2 hours per week
Scheduled, bounded workloads

The system turns restaurant sources and user feedback into approved catalog records.

Deterministic software handles scheduling, source checks, validation, routing, caching, and public serving. A language model extracts structured fields from prose, PDFs, screenshots, and photos. I review uncertain changes. The website reads only approved, cached data.

Evidence
Source material from restaurants and users
Candidate
Structured fields extracted from a source
Catalog
Approved records served by the website
01 / 05

THE SYSTEM

The system maintains a Charlotte-only catalog.

Restaurant specials are scattered across web pages, menus, PDFs, images, and social posts. Charlotte Specials checks those sources ahead of time, maintains an approved Charlotte-only catalog, and serves that catalog to people without waiting on a model.

  • Restaurant content and user reports enter as source material. The catalog contains the approved listings served by the website.
  • The operating target is practical: dozens of restaurants and 100+ specials for less than $20 per month and about two hours of owner attention per week.
Restaurant sourcesweb · PDF · imageFetch + fingerprintnormalize · SHA-256Typed candidatesschema · schedule · locationApply or reviewpublish · stageApproved catalogPostgreSQLCharlotte Specials websiteFeedback intakereport · photo · suggestion
02 / 05

OBSERVE

Sources are checked for changes before extraction.

Scheduled jobs discover likely specials pages and revisit known sources. The system normalizes HTML and extracted PDF text, removes unstable boilerplate, and computes a SHA-256 checksum. Unchanged content can stop here.

  • GitHub Actions triggers source discovery, staged curation, feedback triage, backups, and proactive audits. Vercel Cron queues recurring parsing work.
  • URL ranking, content fingerprints, due-date checks, retries, and queueing are deterministic operations.
Restaurant sourcesweb · PDF · imageScheduled workflowsGitHub Actions · CronFetch + fingerprintnormalize · SHA-256
03 / 05

INTERPRET

Structured and unstructured sources follow different extraction paths.

Structured menu data can be read directly. Prose, PDFs, screenshots, and photos are harder, so an LLM or OCR step extracts the useful fields. Both paths produce the same typed candidate shape for the rest of the application.

  • JSON-LD and deterministic rules bypass the model when they are sufficient.
  • Model output is constrained to candidate titles, descriptions, schedules, locations, types, and confidence signals. It does not receive authority to write arbitrary data.
Structured extractionJSON-LD · rulesLLM / OCR extractiontext · PDF · imageTyped candidatesschema · schedule · location
04 / 05

DECIDE

Candidate changes are compared with the approved catalog.

A changed checksum may represent new information, harmless rewording, an old menu, a duplicate, the wrong location, or a bad extraction. Candidates are validated and compared with the approved catalog before the system applies a change or preserves it as a pending diff for review.

  • Schema checks, schedule rules, deduplication, location matching, prior catalog state, and confidence all contribute to the routing decision.
  • Review mode writes a ParseDiff. I can inspect the source and proposed change, then approve, edit, or reject it without re-running extraction.
Typed candidatesschema · schedule · locationApply or reviewpublish · stageOperator reviewapprove · edit · rejectApproved catalogPostgreSQL
05 / 05

SERVE + CORRECT

The website serves approved records and returns feedback to the maintenance loop.

The public website reads cached, approved catalog data and never waits on an LLM. Feedback is stored as untrusted input and routed separately. A report can queue a review-mode source check; a photo can be interpreted into candidates, but the resulting changes are still staged before approval.

  • Feedback routing is deterministic. Reports and photos can produce candidate changes, but they do not publish records directly.
  • Parse jobs, diffs, feedback routes, run records, and change logs record what ran and where review entered the loop.
Approved catalogPostgreSQLCharlotte Specials websiteFeedback intakereport · photo · suggestionOperator reviewapprove · edit · reject

SYSTEM FLOW

THE SYSTEM
softwaremodelapproved dataoperatoractive path
DESIGN CHOICES

How source material moves into the public catalog.

These choices define which work is deterministic, where model extraction is used, and when a change is staged for review.

01

Sources are stored as evidence

Restaurant sources and user reports can be stale, incomplete, or contradictory. The approved catalog contains the records that remain after source checks and review.

In the system: Source snapshots, content hashes, comparisons, and review diffs keep the original evidence separate from the published record.
02

Deterministic checks run first

Scheduling, checksums, JSON-LD, validation, routing, caching, and public serving do not require a model. Model extraction is used when the useful information is embedded in prose or images.

In the system: The least expensive sufficient extraction path runs first.
03

Model output becomes typed candidates

Extraction produces structured fields rather than direct database commands. The application handles schemas, matching, schedule rules, data access, and the apply-or-stage decision.

In the system: Candidates pass through validation and catalog comparison before publication.
04

Ambiguous changes are staged

When a comparison does not support an automatic change, the system keeps the source and proposed diff for review instead of replacing the current record.

In the system: Review mode stages ParseDiff records and leaves the current catalog intact.
05

Public requests read approved records

Interpretation happens before publication. A request to Charlotte Specials reads the approved catalog rather than waiting for extraction to run.

In the system: The website reads cached PostgreSQL records and has no LLM in its request path.
06

Automated work leaves records

Parse runs, diffs, feedback routes, review outcomes, and change logs record what ran and what changed. Tests cover the main application and extraction boundaries.

In the system: Run records and bounded evaluations make automated changes traceable.
OPERATING MODEL

Scheduled work, review, and records support the maintenance loop.

Recurring jobs collect and parse sources. Review tools handle uncertain changes, while tests and run records cover the main system boundaries.

01 / SCHEDULED WORK

Jobs run on recurring schedules.

Vercel Cron queues recurring source parsing. GitHub Actions runs source discovery, staged curation, feedback triage, database backups, and scoped proactive audits through secured endpoints and limited permissions.

02 / HUMAN OVERSIGHT

Uncertain changes enter the review inbox.

The admin inbox groups parse diffs, staged records, source problems, feedback tasks, and failed jobs. I review the evidence and proposed change instead of manually re-entering every special.

03 / VERIFICATION

Tests cover the main system boundaries.

Business-rule tests, API contracts, high-level integration tests, browser smoke checks, and golden extraction examples protect core behavior. Pull requests run type checking, tests, and a production build before deployment.

04 / RECORDS

Runs and changes are recorded.

Parse jobs, feedback routes, review diffs, agent runs, and change logs provide the context needed to understand what ran, what changed, and where human judgment entered the loop.

ConstraintArchitectural response
Under $20 per month

Skip unchanged sources, use deterministic extraction first, cache public reads, and bound model-backed evaluations.

About two hours per week

Schedule recurring work, batch queues, and send only ambiguous or consequential changes to the review inbox.

Charlotte only

Scope discovery geographically, model restaurant locations explicitly, and enforce North Carolina-specific schedule rules.

Public data changes over time

Serve approved catalog records, accept corrections, and keep the source context needed to investigate a change.