How it is built
Architecture
Two views of the same production system. Logical is responsibility. Physical is where those responsibilities run. A request carries its own inputs and ends with the response — there is no login and no database.
Living design document last updated 2026-10-03.
Read the full document on GitHub
How to read the diagrams
Start on the left and follow the arrows. The person never talks to the tax
engine directly in the browser; pages talk to routes, and only the form
path asks espp_tax for characterization. Python callers skip
the pages and import the engine. Hosting details stay on the physical
diagram so the logical one does not name Vercel or GitHub.
- Logical: what each layer may do. Presentation never decides qualifying versus disqualifying.
- Physical: one Vercel project plus GitHub for source and deploy. CI is not on the request path.
Logical
The calculator, App, Vision, and Architecture pages share one app shell. Forms sit between HTTP and the domain: they parse what someone typed and ask the library for characterization and a simplified dollar estimate. A Python caller can skip the browser entirely.
flowchart LR
person["Person"]
python["Python"]
subgraph pages["Pages"]
calc["Calculator"]
sim["App"]
vision["Vision"]
arch["Architecture"]
end
subgraph core["Application"]
http["Routes"]
forms["Forms"]
end
subgraph engine["Engine"]
tax["espp_tax"]
end
person --> calc --> http --> forms --> tax
person --> sim --> http
person --> vision --> http
person --> arch --> http
python --> tax
- Pages: Calculator form (sessionStorage draft in the tab), App simulation (iOS/Android chrome around the same form), Vision summary, Architecture diagrams, and the header release chip
- Application: Route HTTP, parse the form, build the report dict, load living docs and `version.json`
- Engine: The only place characterization and tax-dollar math may run
Physical
Production is one Vercel project. HTML comes from a Python serverless
function (web.app:app). CSS, JS, and images ride the Static
CDN. Fonts, HTMX, and Mermaid come from public CDNs. Those names sit on
the arrows, the same way HTML does. GitHub Actions tests and tags
releases; that pipeline is not on the request path.
flowchart LR
browser["Browser"]
subgraph vercel["Vercel"]
fn["FastAPI"]
files["Static CDN"]
end
cdns["Public CDNs"]
github["GitHub main"]
browser -->|HTML| fn
browser -->|"CSS · JS · images"| files
browser -->|"Fonts · HTMX · Mermaid"| cdns
github -->|deploy| vercel
- HTML: FastAPI + Jinja2 on a Vercel Python serverless function (`web.app:app`)
- Static CDN: CSS, JS, images, and `version.json` from `public/static/`
- Public CDNs: Google Fonts, HTMX, and Mermaid load in the browser; they are not on the tax path
- Tax engine: In-process `src/espp_tax` — no separate service
- Identity / data store: None
- CI / release: GitHub Actions on `main`; Vercel deploys the resulting commits
What this omits on purpose
There is no user store, no session, and no separate tax microservice. The engine runs in-process with the function that rendered the page. Product intent — who this is for, and what it must not claim — lives on the Vision page, not here.