Implementation tools and runtime components¶
This page names the technologies that are actually used in BloqueApp. It is intended for engineering readers; the architecture gives the component boundaries, the algorithms page derives the cost model, and the concept guide links to policy, bank credit, and offline behavior. See the glossary for terms and limitations for incomplete areas.
Android application¶
The phone app is Java 17 with native Android Views. Its current minimum SDK is API 33, and it compiles and targets SDK 36. Android platform APIs provide package visibility and suspension, Device Owner checks, alarms, Usage Events, screen and keyguard state, and foreground-service notifications. The app uses a worker for policy, storage, and usage work rather than doing network or ledger I/O in an accessibility or UI callback.
Runtime policy and the time-bank ledger are plain Java collaborators with unit-testable logic. PolicyDocumentValidator accepts the bounded subset used by the checked-in policy schema. PolicyVerifier and GrantVerifier verify RS256 envelopes with the configured pinned public key. The signed policy snapshot is stored atomically in device-protected files; enforcement and ledger cursors are persisted in device-protected preferences. Pairing credentials are encrypted with an AES key held by Android Keystore in credential-protected storage. These local stores serve different lifecycle needs; the phone does not use a local SQL database for the bank ledger.
Usage accounting calls UsageStatsManager.queryEvents and reduces lifecycle and device-interaction events into intervals. It does not use aggregated daily usage totals as realtime authority. The platform does not expose a unique activity-instance ID in this path, so sustained overlapping package evidence is treated as ambiguous. See the measured algorithm and bounds.
ASP.NET Core service and SQLite¶
The service targets .NET 10 with C# 14, ASP.NET Core Minimal APIs, Microsoft.Data.Sqlite, and SignalR. SQLite is the durable store for pairing, approvals, decisions, policy publication, permanent-app exceptions, push subscriptions, and delivery outbox state. Writes that must be observed as one decision use transactions. The database is local to the service process; the application does not require Redis for the described flows.
The versioned JSON contracts define access requests, policy documents and signed envelopes, grants, decisions, pairing, and push registration. The Android and server policy validators support the keywords used by that document; a new constraint must be added and checked on both sides. The validator is not a general JSON Schema engine.
The service signs grants and policy snapshots with a configured RSA private key. The private signing material is a deployment secret and is not stored in the repository or returned as a client credential. The Android package carries only the matching public trust inputs.
Approver web app, Web Push, and SignalR¶
The approver interface is a static HTML/CSS/JavaScript application served from the same origin as the API. Its service worker registers push subscriptions, displays notifications, and handles notification actions. The API validates subscription endpoints and keys, stores owner-bound subscriptions, and enqueues delivery in SQLite when durable delivery is enabled. A background worker leases outbox items and sends Web Push with VAPID authentication using bounded HTTP timeouts and retries.
SignalR runs in the ASP.NET Core service as a live hint path for a foreground paired device. Durable HTTPS reads remain the source of request and decision truth. Web Push is a separate browser wake-up path. Neither mechanism grants device access.
HTTP and realtime API map¶
The PWA and API share one HTTPS origin. The table lists the main routes used by the Android client and approver; {requestId} is a request identifier supplied by the caller. Device routes use the paired-device bearer credential in the Authorization header unless marked as initial registration. Approver routes use the secure approver-session cookie; browser mutations also require same-origin JSON checks. Treat these paths as a navigation map, not as a replacement for the versioned request and response schemas.
| Method and path | Caller and authentication | Purpose and authority |
|---|---|---|
POST /api/v1/devices |
Initial device enrollment; no existing device bearer | Registers a device identity and begins pairing. It does not establish an approver relationship. |
POST /api/v1/approver/session |
Browser; same-origin JSON, creates or resumes the secure cookie session | Establishes the browser approver session. |
POST /api/v1/approver/pairings, GET /api/v1/approver/pairing |
Approver cookie | Claims a one-time pairing code and reads pairing state. |
POST /api/v1/device/pairing/start, GET /api/v1/device/pairing, POST /api/v1/device/pairing/confirm |
Device bearer | Starts or confirms pairing and reads device-side pairing state. |
GET /api/v1/device/policy |
Paired device bearer | Returns the signed effective-policy snapshot for that device and pairing. The Android client verifies it locally. |
POST /api/v1/device/requests, GET /api/v1/device/requests/{requestId} |
Device bearer | Creates an access request and reads its durable receipt. An approved receipt may carry a signed, scoped grant; the receipt itself is not authorization. |
GET /api/v1/approver/requests, GET /api/v1/approver/requests/{requestId}, POST /api/v1/approver/requests/{requestId}/decision |
Approver cookie | Lists/reads requests and records an acknowledged decision. The server persists the decision before sending any realtime hint. |
POST /api/v1/device/unrestricted-requests, GET /api/v1/device/unrestricted-requests/{requestId}; corresponding /api/v1/approver/unrestricted-requests... routes |
Device bearer for device paths; approver cookie for approver paths | Handles the separate, narrowly scoped permanent-app request and decision flow. |
GET /api/v1/approver/push/config, POST /api/v1/approver/push/subscriptions, POST /api/v1/approver/push/subscriptions/remove |
Paired approver cookie | Reads public push configuration and registers/removes the approver’s browser subscription. Push delivery is optional and is not a decision. |
SignalR wss://<public-host>/api/v1/device/events |
Paired device bearer in the Authorization header; no query token or approver cookie |
Delivers DeviceReady and best-effort RequestChanged hints. The device then fetches its receipt over HTTPS. |
GET /health/ready; GET /api/v1/status |
Operational/read-only probes | Readiness indicates required service stores are available. Status describes selected service configuration. Neither endpoint reports approval authority or phone enforcement state. |
The client authorizes from the currently verified local policy and a valid signed grant, not from a 200 response, a readiness probe, a hub event, or a push notification. See the architecture authority boundary, security, and user guide.
Development and verification¶
The Android project uses Gradle and the repository wrapper with JDK 17. Focused JVM tests cover policy decisions, signed grant rules, bank ledger arithmetic, and event reduction; Android lint and APK checks cover platform packaging. The backend uses the pinned .NET SDK in global.json, locked NuGet dependencies, and xUnit integration tests against SQLite-backed service flows. The PWA is plain static source and ships with the service rather than a separate server runtime.
Builds and unit tests establish source and packaging properties, not physical blocking acceptance. A passing package build does not prove Device Owner provisioning, launcher behavior, real-app suspension, Web Push delivery on a particular browser, or recovery after real-world reboot and network loss. These are distinct acceptance questions documented by the project’s current public limitations.