Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/AdriP-maker/JAAR_Antigravity/llms.txt

Use this file to discover all available pages before exploring further.

SIMAP Digital is built around a single architectural principle: the app must work perfectly without internet access. This page explains how every layer of the stack is designed to uphold that guarantee, from local data writes through cloud synchronisation.

The offline-first paradigm

Traditional web apps treat the server as the source of truth. Offline-first apps invert that model — the local store is the source of truth, and the server is a durable replica. When a cobrador processes a payment in a hillside community with no cellular signal:
  1. The write goes straight to IndexedDB on the device — sub-millisecond, no network needed.
  2. A corresponding record is added to the pendingSync queue inside the same IndexedDB database.
  3. The UI reflects the new state immediately — no spinners, no errors.
  4. Hours later, when the device comes back online, the queue is flushed to Supabase automatically.
The pending-sync pattern means the cobrador never has to think about connectivity. The app behaves identically whether the device is online or offline — the only difference is when data reaches the cloud.

Architecture diagram

Technology stack

LayerTechnologyVersionPurpose
FrontendReact + React Router19.x / 7.xComponent-based SPA with hash-based routing
Build toolVite + @vitejs/plugin-react8.xFast HMR dev server and optimised production bundle
Local DBDexie.js (IndexedDB wrapper)4.xOffline-first persistence with versioned schema migrations
Cloud backendSupabase (@supabase/supabase-js)2.xPostgreSQL database, Auth, and REST API
Excel exportSheetJS (xlsx)0.18.xClient-side .xlsx generation — no server required
PDF generationjsPDF + jsPDF-AutoTable4.x / 5.xSigned payment receipts and official MINSA reports

Sync strategy

The five-step sync lifecycle ensures no data loss regardless of connection quality:
1

Local write

Every user action (payment, expense, jornal, user registration) is written to IndexedDB through a Dexie service function (e.g., pagosService.js, gastosService.js). The write is synchronous from the UI’s perspective — it resolves before any network call is attempted.
2

Queue pendingSync record

Immediately after the local write, a corresponding record is inserted into the pendingSync table with type, payload, and timestamp fields. This record acts as the work item for the sync worker.
// Simplified example from syncService.js
await db.pendingSync.add({
  type: 'pago',
  payload: pagoRecord,
  timestamp: Date.now(),
});
3

Detect online event

syncService.js listens to the browser’s window.addEventListener('online', ...) event. On app load, if a Supabase session exists in sessionStorage, an initial sync is also triggered immediately.
// From App.jsx — triggered on mount
const session = sessionStorage.getItem('simap_session');
if (session) {
  import('./services/syncService').then(({ syncFromSupabase }) => {
    syncFromSupabase();
  });
}
4

Push to Supabase

The sync worker iterates through all pendingSync records in chronological order and upserts each payload to the corresponding Supabase table via the REST API. Requests are made sequentially to respect foreign-key ordering.
5

Mark as synced

On a successful Supabase response, the pendingSync record is deleted from IndexedDB. If a request fails (e.g., the connection drops mid-sync), the record remains in the queue and will be retried on the next online event.

Role-based access control (RBAC)

Route-level access is enforced by two functions exported from src/services/authService.js:
  • isRouteAllowed(role, pathname) — returns true if the given role may access that path.
  • getHomeRoute(role) — returns the default landing route for a role.
The ProtectedRoute component in App.jsx wraps every authenticated route. If a user navigates to a forbidden path, they are immediately redirected to their own home route — no flash of forbidden content.
┌─────────────┬──────────────────────────────────────────────────────────┐
│ Role        │ Permitted Routes                                         │
├─────────────┼──────────────────────────────────────────────────────────┤
│ admin       │ /admin, /puntos-admin                                    │
├─────────────┼──────────────────────────────────────────────────────────┤
│ cobrador    │ /cobros, /jornales, /gastos, /comisiones, /reporte,      │
│             │ /foro, /chat, /mapa                                      │
├─────────────┼──────────────────────────────────────────────────────────┤
│ minsa       │ /reporte (read-only download only)                       │
├─────────────┼──────────────────────────────────────────────────────────┤
│ cliente     │ /historial, /foro, /chat                                 │
├─────────────┼──────────────────────────────────────────────────────────┤
│ dev         │ /admin (audit log tab only — no financial data)          │
└─────────────┴──────────────────────────────────────────────────────────┘

Module overview

ModuleSource fileResponsibility
Paymentssrc/services/pagosService.jsRegister payments (monthly, daily, multi-month, partial, advance, catch-up); calculate resident status (Al día / Moroso / Corte); SHA-256 receipt hashing.
Points / Gamificationsrc/services/puntosService.jsAward points for on-time payments (+5), advance months (+10), and jornales; redeem points as monetary discounts (1 pt = B/.0.10, max B/.1.50/month); quarterly and annual bonus detection.
AI enginesrc/services/aiService.jsScore each household 0–100 using five risk factors; predict delinquency via composite formula; generate optimised collection queue; detect anomalies with Z-score analysis.
Auth / RBACsrc/services/authService.jsisRouteAllowed(), getHomeRoute(), session management — the single source of truth for access control.
Commissionssrc/services/comisionesService.jsCalculate and record the cobrador/devs commission split (40 % / 60 %) per payment; query accumulated balances.
Syncsrc/services/syncService.jsFlush pendingSync queue to Supabase on online events; pull latest cloud state into IndexedDB on login.
Databasesrc/services/db.jsDexie instance SIMAPDigital with six versioned schema migrations; initDB() seed function; localStorage → IndexedDB migration utility.
Reportssrc/services/reportesService.jsGenerate the official MINSA financial report as an eight-sheet Excel workbook and PDF receipts with jsPDF.

Data versioning

Dexie’s built-in schema migration system lets SIMAP Digital evolve its IndexedDB schema non-destructively. Each db.version(n) call adds new stores without touching existing data.
VersionWhat was added
1Core tables — usuarios, pagos, saldos, gastos, jornales, pendingSync, config, registeredUsers
2foro — community announcement board
3juntas (B2B water-board registry), auditoria (immutable audit log), archivos (file-hash metadata for receipt integrity)
4puntos_historial — full transaction history for the gamification points ledger
5notificaciones — per-user push notification inbox
6mensajes — direct-message conversations between cobrador and residents (AI-suggested dialogue delivery)
Dexie applies migrations lazily when the database is first opened on a device running an older schema version. This means a cobrador who hasn’t opened the app in months will have their local database upgraded seamlessly on the next launch — no data loss, no manual intervention.

Build docs developers (and LLMs) love