Bilko Mobile Architecture

Bilko Mobile Companion Architecture

Product: Bilko Mobile Companion
Markets: HR / RS / BA
Status: Direction approved — iPhone + Samsung/Android native companion; implementation details remain draft
Date: 2026-05-25
Updated: 2026-06-04
Related PRD: docs/mobile/MOBILE-PRD.md

1. Architecture Decision

Approved framework: React Native with Expo for iPhone and Samsung/Android delivery.

Rationale:

Decision status: final for Bilko mobile direction. The older PWA-for-MVP note in /Users/makinja/system/specs/bilko-tech-stack.md is superseded for mobile app work; responsive/PWA web may still exist as web capability, but it is not the mobile companion app delivery path.

2. Core Principles

  1. Backend is source of truth for accounting, tax, invoice numbering, e-invoice submission, audit logs, and permissions.
  2. Mobile is an action companion, optimized for capture, approvals, alerts, and simple workflows.
  3. Offline-first only where valuable: drafts, queued uploads, cached dashboard, and pending approvals.
  4. Country behavior is configuration/plugin-driven, not hardcoded screen forks.
  5. No regulated secrets or certificates in the mobile app unless a future legal/security review explicitly approves it.
  6. Security and auditability are product features, not afterthoughts.

3. Proposed App Structure

apps/mobile/
├── app/                         # Expo Router routes
│   ├── (auth)/
│   ├── (tabs)/
│   │   ├── today/
│   │   ├── inbox/
│   │   ├── invoices/
│   │   ├── expenses/
│   │   └── more/
│   ├── invoice/[id].tsx
│   ├── expense/[id].tsx
│   └── document/[id].tsx
├── src/
│   ├── api/                     # typed API client + endpoint modules
│   ├── auth/                    # session, refresh, company switcher
│   ├── components/              # UI primitives and feature components
│   ├── country/                 # country metadata and formatting adapters
│   ├── db/                      # local SQLite schema and repositories
│   ├── features/                # dashboard, inbox, invoices, expenses
│   ├── notifications/           # push registration, handlers, deep links
│   ├── security/                # secure storage, app lock, logger scrubber
│   ├── sync/                    # queue, retry, conflict handling
│   ├── types/                   # shared DTOs and local models
│   └── utils/
├── assets/
├── app.config.ts
└── package.json

4. Navigation

Root
├── Auth Stack
│   ├── Login
│   ├── Forgot Password
│   └── MFA / Device Verification (future)
└── App Tabs
    ├── Today
    ├── Inbox
    ├── Invoices
    ├── Expenses
    └── More

Deep links:

5. Country Plugin Layer

The mobile app should request country/company metadata from the backend after login.

Example mobile country config:

type BilkoCountry = 'HR' | 'RS' | 'BA'

type CountryMobileConfig = {
  country: BilkoCountry
  currency: 'EUR' | 'RSD' | 'BAM'
  vatLabel: 'PDV' | 'VAT'
  invoiceStatusProvider?: 'SEF' | 'HR_FISK_ERACUN' | null
  supportsRegulatedEInvoiceSubmission: boolean
  supportsMobileSimpleInvoice: boolean
  complianceReminderTypes: string[]
}

Initial defaults:

Country Currency Regulated status in mobile Submission in mobile
HR EUR eRačun/HR-FISK readiness/status when backend supports it Backend-only, mobile initiates only approved backend workflow
RS RSD SEF status and failure alerts Backend-only, mobile initiates only approved backend workflow
BA BAM VAT/PDV reminders and document/accountant workflow No e-invoice submission until official specs are stable

6. API Boundary

Mobile should eventually consume a stable API/BFF layer rather than directly reproducing web internals.

Phase 1 decision: use existing /api/v1/* endpoints where they are already live, plus a small Phase 0 auth bridge for Microsoft Entra External ID. Do not build the full /mobile/* BFF before the first iPhone/Android internal build.

Phase 2+ target endpoints:

GET    /mobile/bootstrap
GET    /mobile/dashboard
GET    /mobile/country-config
GET    /mobile/invoices
GET    /mobile/invoices/{id}
POST   /mobile/invoices/{id}/reminders
POST   /mobile/invoices/{id}/mark-paid
POST   /mobile/invoice-drafts
GET    /mobile/expenses
GET    /mobile/expenses/{id}
POST   /mobile/expense-drafts
POST   /mobile/approvals/{id}/approve
POST   /mobile/approvals/{id}/reject
POST   /mobile/documents/upload-url
POST   /mobile/documents/complete-upload
GET    /mobile/sync/pull?since={cursor}
POST   /mobile/sync/push
POST   /mobile/push-token
DELETE /mobile/push-token/{id}

All mutation endpoints must:

7. Local Storage

Phase 1 storage:

Phase 2+ target storage:

Local data categories:

Data Storage Offline? Notes
Access token / ID token SecureStore Yes short-lived; issued via Entra/Bilko auth bridge
Refresh token/session token SecureStore Yes rotation required; never AsyncStorage
Company/session metadata SQLite Yes non-secret but sensitive
Dashboard cache SQLite Read-only stale indicator required
Invoice/expense list cache SQLite Read-only limited retention
Draft expense/invoice SQLite Yes sync queue item
Captured document file FileSystem Yes encrypted/retention-managed
Push token Server + memory/cache No revocable

8. Offline and Sync Strategy

Phase 1 offline scope:

Phase 2+ offline target scope:

Sync queue item:

type SyncQueueItem = {
  id: string
  entityType: 'expenseDraft' | 'invoiceDraft' | 'document' | 'approval'
  entityId: string
  operation: 'create' | 'update' | 'upload' | 'approve' | 'reject'
  payload: unknown
  fileUri?: string
  baseVersion?: string
  retryCount: number
  createdAt: string
}

Retry rules:

  1. Drain queue on app foreground and network restore.
  2. Use FIFO order per entity.
  3. Use exponential backoff.
  4. Preserve item after failure; never silently discard user-captured document.
  5. Move to user-visible “needs attention” state after max retries.

Conflict rules:

9. Push Notification Design

Provider options:

  1. Expo Notifications for fastest Phase 3 implementation.
  2. Direct FCM/APNs if advanced routing/compliance requirements require it later.
  3. Third-party service only if product/ops wants non-engineering campaign controls.

Phase 1: no push permission prompt and no push-token registration unless a backend device-token endpoint is explicitly added and approved. Avoid asking users for notification permission before the product can deliver useful notifications.

Transactional notification types:

Type Trigger Deep link
approval.requested Expense/invoice needs user approval approval detail
document.requested Accountant requests missing document inbox task
invoice.overdue Invoice crosses overdue threshold invoice detail
tax.deadline VAT/PDV deadline approaching compliance card
einvoice.accepted SEF/eRačun provider accepted invoice invoice detail
einvoice.rejected Provider rejected/failed invoice invoice detail
certificate.expiring HR/country integration certificate warning settings/compliance

Rules:

10. Security Architecture

Required baseline:

Sensitive screens:

11. Analytics and Observability

Track product events without PII:

Operational telemetry:

12. Build Variants

Variant Bundle ID example API Analytics Push
Dev no.alai.bilko.dev local/dev off sandbox
Staging no.alai.bilko.staging staging limited sandbox
Production no.alai.bilko production consent-based production

Secrets and environment values must be injected via CI or secure config, not committed.

13. Testing Strategy

Required test layers:

Critical acceptance tests:

  1. Receipt captured offline survives app restart and syncs after network restore.
  2. HR/RS/BA company displays correct currency and country labels.
  3. Push notification opens correct invoice/expense/document.
  4. Stale approval action receives conflict and does not silently approve wrong version.
  5. Token is not stored in AsyncStorage/MMKV/plain SQLite.

14. Implementation Phases

Phase 0 — API and Design Foundations

Phase 1 — Read-Only App

Phase 2 — Capture and Upload Queue

Phase 3 — Notifications and Approvals

Phase 4 — Simple Invoice Actions

Phase 5 — Regulatory Status Views

15. Open Technical Questions

  1. Does Bilko currently expose mobile-safe BFF endpoints, or should apps/api add /mobile/*?
  2. Which auth/session mechanism is canonical for mobile refresh token rotation?
  3. Which local DB encryption approach is acceptable under Expo constraints?
  4. Which OCR provider meets cost, language, and privacy requirements for HR/RS/BA receipts?
  5. Should push be Expo-managed for MVP or direct APNs/FCM from day one?
  6. What is the maximum local retention period for cached financial data and attachments?

Revision #1
Created 2026-06-07 19:43:14 UTC by John
Updated 2026-06-07 19:43:14 UTC by John