Monorepo (pnpm workspaces) with two deployable apps and three pure packages. apps/api (Hono on Node): Zod validated env that fails fast and names the problem, Kysely factories for SQLite and Postgres chosen by DATABASE_URL scheme, portable migrations covering the whole SPEC section 5 schema, Better Auth with the four roles and seeded demo accounts, localized error envelope, /healthz and /readyz, graceful SIGTERM drain. Dialect specific SQL is confined to the two factories. apps/web (Next.js App Router): locale routed shell in es and en with a language switcher, sign in screen, and a runtime /api proxy so the browser only ever sees one origin and cookies stay first party. packages/i18n ships both catalogs complete; es is generated from COPY.md and a test re-derives it from the document on every run so it cannot drift. packages/contracts holds the Zod schemas and the typed client the web app uses. Verified: 43 vitest tests, 14 Playwright tests on mobile and desktop, typecheck and lint clean, migrate and seed from a clean database, sign in through the proxy with CSRF rejection of foreign origins. Not verified here: docker compose. This user has no access to the docker socket. RULES.md is absent from docs/, so packages/rules exports only RULES_VERSION and no tax rule, check digit or deadline was invented. See DECISIONS.md. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
120 lines
12 KiB
Markdown
120 lines
12 KiB
Markdown
# FLOWS.md: Screens, Flows and Design System
|
|
|
|
Companion to PROMPT.md and SPEC.md. This file is authoritative for UX. Apply the `ui-ux-pro-max-skill` within these constraints.
|
|
|
|
---
|
|
|
|
## 1. Design system
|
|
|
|
**Feel:** calm fintech. A clean banking app, not accounting software. Generous whitespace, one accent color, big confident numbers. Mobile-first (design at 390px, scale up), fully responsive, dark mode supported (system preference + toggle).
|
|
|
|
**Tokens (Tailwind theme):**
|
|
- Accent: deep teal family (pick one scale, use for primary actions and links only).
|
|
- Semantic status colors, used EVERYWHERE consistently:
|
|
- `positive` (green): a favor, al dia, savings found.
|
|
- `attention` (amber): action required, needs review, T-10 to T-2 deadlines.
|
|
- `overdue` (red): ONLY for missed deadlines and invalid documents. Never use red for "tax to pay". Owing tax on time is neutral.
|
|
- `neutral` (slate): everything else.
|
|
- Typography: Inter (self-hosted) for UI; tabular-nums for every money figure. Money display component `<Money value>` renders `Gs. 1.234.567`, large variant for headline numbers.
|
|
- Radius: rounded-2xl cards, rounded-full pills. Shadows: subtle, one elevation step.
|
|
- Spanish voseo in all copy ("Ingresá tu RUC", "Revisá tus facturas"). No tax jargon at surface level; technical terms live behind "Ver detalle".
|
|
- **Multi-language:** `es` default and `en` fully shipped (COPY.md policy). Language switcher: compact globe menu in the header on marketing/auth screens, and a row in `/perfil` when authenticated (persists to profile and drives notification language). Locale is in the URL (`/es/...`, `/en/...`); switching preserves the current page. Dates localize; money never does (always `Gs.`). Form previews and PDFs remain Spanish in both locales, with a small caption in the active locale: "Formato oficial DNIT (en español)".
|
|
|
|
**Loading:** boneyard skeletons on every data screen (`<Skeleton name>` per component: `dashboard-position`, `bandeja-card`, `doc-list-item`, `declaration-summary`, `admin-user-row`, etc.). Content loads never show spinners.
|
|
|
|
**Component inventory (build once in `/components`):** `Money`, `StatusChip` (al dia | por vencer | en revision | atrasado), `DeadlinePill` (countdown), `TraceableNumber` (tappable money that opens source drill-down sheet), `DocCard`, `CategoryPicker` (8 IRP categories as icon grid bottom sheet), `FormPreview` (renders form definition + values as an official-looking document), `EmptyState` (illustration + one action), `ConfettiMoment` (GSAP, used sparingly).
|
|
|
|
---
|
|
|
|
## 2. Flow A: Landing and onboarding
|
|
|
|
**A1. Landing `/`** hero: headline "Tus impuestos, en piloto automatico", subline about scanning facturas and never missing a vencimiento. Single input: "Ingresá tu RUC o CI" + button "Ver mi situacion". canvas-ui permitted here: ONE subtle full-hero effect (e.g. Liquid or Ripple) behind the content, disabled on `prefers-reduced-motion`, graceful static fallback. Below: three value cards, pricing placeholder, footer with legal pages.
|
|
|
|
**A2. Instant preview (no account yet):** on submit, call the public lookup. Show a personalized card: formatted document, taxpayer kind guess, detected deadline day ("Tus vencimientos caen el dia 19 de cada mes") with the next 3 dates. GSAP: card flips in, deadline dates stagger. CTA: "Crear mi cuenta gratis". Invalid RUC/CI: inline validation with the check-digit explanation, never a dead end.
|
|
|
|
**A3. Account creation:** email + password, then email OTP verification screen (6-digit input, auto-advance). Better Auth flows. Keep to one screen each, no marketing interruptions.
|
|
|
|
**A4. Consent:** one screen, plain language: what we store, why, retention, revocation. Two switches: data processing (required to continue), notifications (optional). Link to full policy. Grant writes `consents` + audit.
|
|
|
|
**A5. Profile setup (max 3 steps, progress dots):**
|
|
1. Confirm identity: full name, doc from A2 prefilled, taxpayer kind.
|
|
2. "¿Que obligaciones tenes?": two big toggle cards: "IVA mensual (tengo RUC activo)" and "IRP (gano mas de Gs. 80 millones al año)". Either, both, or "No estoy seguro" (picks IRP-only view, flag for review). If IRP: optional annual income estimate slider/input (for projections) + add dependents (name + relationship, skippable).
|
|
3. Notifications: enable push (browser prompt behind an explainer card), optional email/Telegram if configured.
|
|
|
|
**A6. First-run state:** land on `/inicio` with a guided empty state: "Escanea tu primera factura" big button + "o cargala a mano". After the first confirmed document, GSAP counter rolls the first savings number: this is the wow, protect it.
|
|
|
|
## 3. Flow B: Ingestion
|
|
|
|
**B1. Scan:** persistent FAB `[+ Escanear]` on all `(app)` screens (bottom right, above tab bar). Opens full-screen camera with frame guide and torch toggle; also "Subir archivo" (image/PDF). Client QR decode runs live; on QR hit: instant haptic + green frame flash, auto-capture, no shutter needed.
|
|
- QR path result sheet (target under 3 seconds): "Verificado ✓" badge (or "Registrado" when verification is off), emitter name/RUC, date, total, suggested classification with confidence chip. Buttons: "Confirmar" (primary), "Cambiar categoria", "Descartar".
|
|
- No QR detected after 4 seconds: hint chip "¿Factura sin QR? Sacale una foto igual" → shutter → OCR path: uploading state on the card (boneyard shimmer), then same result sheet with per-field confidence; low-confidence fields get amber underline and tap-to-edit.
|
|
- No OCR configured: straight to manual form (B3) with the photo attached.
|
|
- Duplicate: sheet says "Ya tenias esta factura" with the existing card and a merge note. Never an error tone.
|
|
|
|
**B2. Offline:** captures queue locally with a chip "Se sincroniza al conectarte"; sync silently, notify only on failure.
|
|
|
|
**B3. Manual entry:** one screen form, big numeric keypad for amounts, RUC field with live check-digit validation, date defaulting to today, IVA split auto-computed from total with editable override ("¿Todo al 10%?" quick toggle). Same result sheet after save.
|
|
|
|
**B4. Bandeja `/bandeja`:** card stack of `needs_review` documents, newest first, count badge in tab bar.
|
|
- Card shows: emitter, date, `<Money>` total, suggested category icon + label, confidence chip, thumbnail corner (tap to zoom).
|
|
- Gestures: swipe right = confirm (GSAP: card flies right with green check trail), swipe left = opens CategoryPicker sheet then confirms, swipe down = reject sheet ("No es mia" / "Duplicada" / "Otro"). Buttons mirror every gesture (accessibility + desktop).
|
|
- Desktop: keyboard J/K navigate, Enter confirm, 1-8 category, X reject.
|
|
- Auto-confirm notice: subtle footer "Las facturas con alta confianza se confirman solas en 7 dias" linking to the setting.
|
|
- Empty state: "Bandeja limpia ✓" with a small GSAP checkmark draw-on.
|
|
|
|
## 4. Flow C: Dashboard `/inicio` ("Mi situacion")
|
|
|
|
Three stacked zones:
|
|
1. **Position header (one card, swipeable between obligations):** IVA card: "IVA de agosto" + big `<Money>` a pagar / a favor (colored by sign, never red), sub-line "debito Gs. X, credito Gs. Y". IRP card: "IRP proyectado 2026" + big number + delta chip "bajaste Gs. 900.000 este mes". Numbers are `TraceableNumber`s: tap opens a bottom sheet listing contributing documents with amounts, each tappable through to detail. GSAP counter roll-up on first paint and on value change.
|
|
2. **Next action strip:** exactly ONE card. Priority: overdue > declaration ready > deadline within 10 days > bandeja count > all-clear ("Todo al dia ✓ Proximo vencimiento: 19 sep"). One primary button.
|
|
3. **Insight feed:** stack of dismissible cards, max 3 visible: deduction gap ("Casi no cargaste facturas de Educacion este año, son deducibles"), monthly close summary, deadline preview. Dismissals persist.
|
|
|
|
## 5. Flow D: Declarations
|
|
|
|
**D1. List `/declaraciones`:** grouped by year, rows: form badge (120/515), period, status chip, amount. Generate button for the current open period when enough data exists.
|
|
|
|
**D2. Review `/declaraciones/:id`:** two layers:
|
|
- **Human summary first:** "Vendiste Gs. 12.4M, compraste Gs. 8.1M. Te corresponde pagar **Gs. 430.000**." Plus 3-4 line breakdown with TraceableNumbers.
|
|
- **Form preview below:** `FormPreview` renders the official-style layout from the rules form definition, every casilla filled, monospace values, watermark "BORRADOR" until approved.
|
|
- Sticky footer: "Aprobar" (primary) + "Descargar PDF".
|
|
|
|
**D3. Approve:** confirmation sheet restating the number → on approve: ConfettiMoment (short, tasteful), status → approved, then the **guided filing checklist**: numbered steps to present it in Marangatu yourself, with copy buttons per casilla value and a final "Ya lo presente" check that records completion and schedules the payment reminder. canvas-ui permitted here (second and last spot): a brief celebratory effect on the success screen, reduced-motion safe.
|
|
|
|
**D4. F515 annual:** same pattern, preceded by a "Tu año" story screen: income, each deduction category with totals and small bars, the final tax, share-nothing (no social buttons, this is private).
|
|
|
|
## 6. Flow E: Documents and profile
|
|
|
|
**E1. `/comprobantes`:** filterable list (month, direction, category, status), monthly totals header, search by emitter. Row: DocCard compact. Detail: full data, image viewer, classification editor, audit trail of changes, delete (soft, confirm).
|
|
|
|
**E2. `/vencimientos`:** vertical timeline of upcoming deadlines (12 months), each with DeadlinePill, obligation, linked declaration state. Personal deadline day explained at top ("Por tu RUC terminado en 6, tus vencimientos caen el dia 19").
|
|
|
|
**E3. `/perfil`:** identity data, obligations toggles, dependents CRUD, income estimate, notification prefs (channel toggles + digest hour), auto-confirm setting, **"Tus datos"** section: what we store (plain list), consent status with revoke, "Descargar mis datos" (JSON export), "Eliminar mi cuenta" (danger, double confirm). This screen is a trust feature; give it real design attention.
|
|
|
|
## 7. Flow H: Admin `(admin)`
|
|
|
|
Plain, dense, desktop-first, shadcn tables. No playfulness here.
|
|
- **/usuarios:** search by email/RUC/name → results table → user overview: profile summary, document counts, recent activity, links to their error rows. Every search and view writes an audit row; a banner reminds staff "Todos los accesos quedan registrados".
|
|
- **/errores:** table of ingest_errors + dead jobs, filters by stage/status, row expand shows payload, actions: retry job, resolve with note.
|
|
- **/auditoria:** filterable audit table (actor, action, subject, date range), read-only, export CSV.
|
|
- Superadmin extra: role management on user overview (with confirm + audit).
|
|
|
|
## 8. Motion system (GSAP)
|
|
|
|
Principles: fast (150-300ms), purposeful, interruptible, `prefers-reduced-motion` disables all non-essential motion globally (CSS + GSAP context).
|
|
- Counter roll-ups on headline Money values (dashboard, declaration summary).
|
|
- Bandeja card physics: drag with rotation, fly-out on commit, next card scales up.
|
|
- Sheet/dialog transitions: spring-ish ease, no bounce overdose.
|
|
- Success moments only at: first document confirmed, declaration approved, "Ya lo presente". Nowhere else.
|
|
- Skeleton→content: crossfade 150ms (boneyard handles layout, GSAP the fade).
|
|
|
|
## 9. Notification doctrine
|
|
|
|
- Bundled daily digest (default 09:00 local) when there is anything: bandeja count, upcoming deadline, savings found.
|
|
- Immediate sends ONLY: deadline T-2 and T-0 ("Mañana vence tu IVA: Gs. 430.000 → Revisar"), declaration ready, filing confirmation.
|
|
- Every notification: one number + one action deep link. Never two notifications where one suffices.
|
|
- Channels per prefs; unconfigured channels hidden everywhere.
|
|
|
|
## 10. States checklist (every screen ships all four)
|
|
|
|
1. boneyard skeleton, 2. empty state with one clear action, 3. error state with retry (friendly copy, never a stack trace), 4. content. Playwright asserts empty and content states on the golden paths.
|