Application
Frontend app
Build the guided React portal in the order Maya works, wire the remaining endpoints, and rehearse the full demo.
By the end of this stage the project is a product someone can use. The React app walks Maya from welcome to decision, every backend capability has a visible home in the UI, and the complete story runs in the browser from upload to history reset.
The frontend is the final adapter, and it adds no rules. It does not decide VAT validity, merge precedence, approval policy, or email eligibility. It presents what the backend already knows and collects what the human decides. Any time you find yourself re-implementing a backend rule in React, stop and send the data instead.
The stack
Vite, React, TypeScript in strict mode, and Tailwind CSS, managed with pnpm. The frontend talks only to the FastAPI backend, configured through one variable in frontend/.env:
VITE_API_BASE_URL=http://localhost:8000Build the screens in Maya's order
The screens map one-to-one onto the workflow, and building them in usage order keeps every increment demoable:
- Welcome, explain the job and offer one clear starting action
- Upload, choose a PDF, PNG, or JPEG and inspect a local preview before anything is sent
- Processing, show the five conceptual pipeline stages while the backend works, presented as what the system does rather than pretending to be live server telemetry
- Review, lead with passed or needs-attention, then combined fields with provenance, issues, the GL suggestion, and the human actions
- Correction email, copy an LLM-drafted supplier email; the app never sends it
- History, reopen or delete past reviews so the same document can be demonstrated twice
The review screen is the heart. The document preview matters before processing; after processing, what Maya needs is the review itself, field provenance included, so an llm_fallback value looks different from primary evidence.
Fill in the gaps
This is also the stage where the remaining backend endpoints get their frontend wiring, GL account selection, the approve and reject decision, correction-email drafting, and history deletion. One detail shows the philosophy well. The UI shows the correction-email button only when the server says a supplier-fixable issue exists, using eligibility the backend computed, instead of duplicating that rule list in TypeScript.
Verify the frontend the same way every stage verifies its work:
cd frontend
pnpm exec tsc -b --pretty false
pnpm lint
pnpm buildThen run both services together:
cd ..
./scripts/dev.shRehearse the complete story
Walk the exact demo path end to end:
- Start at the welcome screen and state Maya's problem in one sentence
- Upload
02-nl-happy-compact.pdf, show the preview, the model comparison, a fallback field's provenance, the warnings, the GL suggestion, and approve it - Upload
06-de-invalid-vendor-vat.pdf, show the deterministic VAT failure and copy the correction email - Upload
13-nl-fuel-receipt.png, show receipt recognition, the fuel categorization, and the receipt-specific checks - Open History and delete all three, so the demo can run again without duplicate errors
If any step needs explaining beyond one sentence, that screen is not done.
Checkpoint
tsc,pnpm lint, andpnpm buildall pass- The complete welcome, preview, process, review, decide, reset sequence works in the browser
- No business rule exists in the frontend that the backend does not own
Next: Deployment
Ship the whole application to Azure Container Apps with one container, one URL, and persistent storage.