phase-7: motion, an installable app, and a capture that survives no signal
GSAP carries the counter roll-ups, the bandeja card physics, the dialog transitions and the three success moments FLOWS.md allows. Every one of them checks prefers-reduced-motion first and does nothing when it is set. boneyard and canvas-ui are not what SPEC.md's stack table says they are: on npm the names belong to two abandoned projects that do neither job. The skeletons were already ours; the two canvas spots are now sixty lines each with no dependency. DECISIONS.md records the substitution. The app installs, keeps a scan taken with no network in IndexedDB and sends it when there is one, falls back to a page that explains itself, and can push a deadline notice. Reading the log of what is queued is the source of truth, so the notice clears when the capture actually lands. The CSP now allows scripts by per-request nonce rather than by 'unsafe-inline'. That forced /offline to render per request: a prerendered page carries a build-time nonce no live policy matches, so its scripts were blocked and it never hydrated. Two crashes fixed on the way. web-push throws on a VAPID subject that is not https: or mailto:, and the code handed it APP_PUBLIC_URL, so any machine with push keys died at boot; a misconfigured optional channel now switches itself off and says why. And a subscription the push service answers 410 for is deleted rather than retried forever. Lighthouse on the production build: accessibility 100, best practices 96, SEO 100, performance 73. The performance number is not trustworthy on this machine and DECISIONS.md says why; total blocking time did fall from 17.6s to 1.7s once the hero canvas stopped drawing at full resolution every frame and the landing page stopped importing GSAP. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
4c39926483
commit
e4eb1617d1
@@ -7,11 +7,12 @@ and ready to file yourself.
|
||||
Working name. See `docs/` for the specifications, `DECISIONS.md` for choices made along the
|
||||
way and the gaps that still need answers.
|
||||
|
||||
> **Status: phase 6 of 8.** The whole taxpayer path works: scan a comprobante, confirm it,
|
||||
> **Status: phase 7 of 8.** The whole taxpayer path works: scan a comprobante, confirm it,
|
||||
> watch the position move, and take the resulting Formulario 120 or 515 from review to
|
||||
> approved to a PDF you file yourself in Marangatu. Staff have a console: look an account
|
||||
> up, work the ingestion error queue, read and export the audit log. The PWA polish and the
|
||||
> scale-out work are still ahead.
|
||||
> up, work the ingestion error queue, read and export the audit log. It installs to a home
|
||||
> screen, keeps a capture taken with no signal and sends it later, and can send a push when
|
||||
> a deadline is close. The scale-out work is the last phase.
|
||||
|
||||
---
|
||||
|
||||
@@ -130,6 +131,30 @@ S3. The k8s manifests assume both.
|
||||
Rate limiting is in memory and therefore per replica. At this scale that is deliberate;
|
||||
the limiter is behind an interface for when it is not.
|
||||
|
||||
## Installing it, offline and push
|
||||
|
||||
`app/manifest.ts` and the icons in `apps/web/public` make the web app installable; the
|
||||
icons are generated from one SVG by `apps/web/scripts/generate-icons.mjs` and committed, so
|
||||
a build never needs a browser.
|
||||
|
||||
The service worker (`apps/web/src/lib/service-worker.js`) caches the app shell and the
|
||||
`/offline` page and nothing else. No API response is cached: a tax figure that is quietly
|
||||
out of date is worse than one that is honestly missing.
|
||||
|
||||
A scan taken with no network is stored whole in IndexedDB and sent when there is one. The
|
||||
chip in the shell says so and clears itself.
|
||||
|
||||
Push needs VAPID keys on the API:
|
||||
|
||||
```bash
|
||||
npx web-push generate-vapid-keys
|
||||
```
|
||||
|
||||
Put them in `apps/api/.env` as `PUSH_VAPID_PUBLIC_KEY` and `PUSH_VAPID_PRIVATE_KEY`, plus
|
||||
`PUSH_VAPID_SUBJECT` (an `https:` or `mailto:` URL) unless `APP_PUBLIC_URL` is already
|
||||
https. Without keys the offer is hidden everywhere; with keys and no usable subject, push
|
||||
switches itself off and logs why rather than taking the API down.
|
||||
|
||||
## Adding a locale
|
||||
|
||||
1. Add the code to `SUPPORTED_LOCALES` in `packages/i18n/src/locales.ts`.
|
||||
|
||||
Reference in New Issue
Block a user