Appearance
ADR-0020: The prototype is a web application on the work-permit stack
Status: Accepted — supersedes ADR-0019 Date: 2026-09-02
Decisions
D-37 The prototype is a web application, not a native mobile application
Owner decision, overriding ADR-0019. No native Android or iOS application is built.
D-38 The stack is the sibling work-permit project's stack
Frontend: Vue 3 + Vite, Pinia (with persisted state), vue-router, vue-i18n, PrimeVue, Tailwind, Zod. Backend: ElysiaJS on Bun, Prisma against Postgres. TypeScript throughout, Bun as package manager and runtime. Tests with Vitest and Vue Test Utils.
D-39 Offline-first (D-06) is delivered as a PWA, and the requirement is unchanged
Service worker with a precached app shell, and the Corpus held client-side in IndexedDB. D-06 stands in full: no Safety-Critical read may require the network. Only the mechanism changes.
D-40 A server tier now exists and holds the Corpus of record
The Elysia/Prisma/Postgres service is the origin of truth for the Corpus, serves the sync the client pulls, and hosts the online-only chatbot. It is never in the path of a Safety-Critical read.
Context
The owner directed that this project use the same stack as the sibling work-permit project, verified from its source: Vue 3.5 + Vite 8, Pinia, vue-router 5, vue-i18n 11, PrimeVue 4.5, Tailwind 4, Zod 4 on the frontend; Elysia 1.4 on Bun 1.3 with Prisma 7 and @prisma/adapter-pg on the backend.
This is an organisational constraint — one stack across sibling projects means shared tooling, shared review skills and shared deployment. That reasoning is not visible in this repo's own evidence, which is precisely why it is recorded here.
ADR-0019 chose native Android on technical grounds, and those grounds have not become wrong — they have been outweighed. Its argument is preserved in that document, and the costs it predicted are carried forward as D-41 and D-42 below rather than being quietly dropped.
Consequences carried forward from the superseded ADR
D-41 Camera OCR is materially weaker on the web, and manual search absorbs it
ADR-0019 chose Android specifically for first-party on-device text recognition, and recorded that browser OCR is markedly worse. On the web, Identification by CAS Number becomes getUserMedia plus a WASM OCR library — slower and less accurate against a scuffed drum label. D-05 and D-19's preference order is unchanged, but ADR-0004's requirement that manual search remain first-class is now load-bearing rather than precautionary.
This is the largest single cost of the stack decision. Identification-by-scan is the source's most distinctive feature (R-10, R-29) and it is the part the web does worst.
D-42 Offline reliability and installability are weaker than the native assumption
ADR-0005 was written assuming a native on-device store. A service worker plus IndexedDB is a genuine offline story but a more fragile one: storage can be evicted, installation is a prompt the user may decline, and behaviour varies by browser. The requirement does not soften; the risk is recorded.
Rejected options
- Keep native Android (ADR-0019) — technically better for the camera and for offline, and rejected on organisational grounds rather than technical ones. Recorded plainly so nobody later reads this as a claim that the web is the better technical fit for scanning.
- Native app plus a web admin surface — would preserve OCR quality where it matters and still share the stack for curation tooling. Rejected as two clients to build and maintain in a prototype (D-01).
This ruling may not be re-decided
If a change contradicts this ADR: stop and raise it. Do not implement over it. In particular: do not soften D-06 because service-worker caching is awkward, and do not drop manual search because scanning "mostly works" in a demo on a clean label.
Benefit worth recording
ADR-0019's Consequences warned that iPhone users at the case-study site could not participate in the needs study (D-31). A web application removes that constraint entirely, which widens participant recruitment.
Coverage
| Upstream | Landed in | Evidence | Note |
|---|---|---|---|
| R-17 | D-37, D-38 | "Mobile App" resolved to a web application on a named stack | supersedes ADR-0019's reading of R-17 |