This repository is a reference architecture showcase extracted from a real, production system.
It focuses on architectural decisions, execution boundaries, and operational patterns — not on business-specific logic or a ready-to-deploy application.The full system context, constraints, and outcomes are described in the corresponding case study:
👉 https://rocketdeploy.dev/en/case-studies/kiosk-web-application
The Kiosk Application is a single-page, touch-first client intended for unattended public use, where reliability, determinism, and controlled execution are critical. It is built as a standalone front-end that initializes core providers at bootstrap, renders route-based screens, and communicates with external services via HTTP requests.
The application emphasizes linear navigation, short-lived sessions, and explicit failure boundaries. These characteristics are intentional and reflect the constraints of kiosk environments, where recovery paths must be simple and the system must continuously return to a known, safe state.
This document intentionally omits business rules, validation semantics, and domain-specific outcomes.
- Language: TypeScript — selected to keep component contracts explicit and reduce runtime defects in a long-running, unattended UI environment where recovery paths must be predictable.
- Framework: Angular (standalone APIs) — chosen for its structured dependency injection, first-class routing, and deterministic component lifecycle, which align well with kiosk constraints and clear architectural boundaries.
- State & reactivity model — synchronous UI state is handled using lightweight, deterministic signals, while asynchronous interactions (HTTP calls, polling, health checks) use reactive streams to support cancellation, retries, and explicit error propagation.
- Browser execution model — the application is designed to run without server-side rendering or dynamic code loading, favoring predictable startup behavior and controlled runtime characteristics.
The system consists of a client interface running in a kiosk context and one or more external services responsible for validation, status resolution, and health signaling. The client is the primary execution environment, while external services own all authoritative decisions.
The client also integrates a localization subsystem that dynamically loads language resources at runtime and persists the selected locale across sessions.
- Bootstrap & initialization: Start with the application bootstrap that enables production mode, wires providers, and initializes translation loading and inactivity configuration.
- Routing & screen map: Review the route configuration that defines the navigation contract and per-screen inactivity behavior.
- Shell & composition: Inspect the root shell and shared layout components that wrap routed screens and cross-cutting UI concerns.
- User flows: Trace the code-entry screens, the waiting/polling screen, and the terminal outcome screens.
- State handling: Review client-side session storage and in-memory services used for transient state handoff.
- Integration boundaries: Identify HTTP requests for health checks, code submission, status polling, and localization resource loading.
- Framework: Component-based SPA using standalone components and a centralized provider configuration.
- Navigation: Declarative routing with deterministic, linear flows designed to minimize recovery complexity.
- State: Combination of in-memory services for transient state and browser storage for short-lived session values.
- Integration: HTTP client used exclusively at defined boundaries for external service calls and localization loading.
- Kiosk concerns: Global inactivity monitoring, periodic health checks, and explicit readiness/heartbeat signaling to the host container.
Navigation and session handling are intentionally restrictive to ensure the application can always converge back to a known start state without manual intervention.
- Inside the client: UI composition, navigation control, session and inactivity handling, localization, and HTTP orchestration.
- Outside the client: All validation, decision-making, and outcome computation are delegated to external services.
- Host boundary: The client may notify a parent container of readiness and liveness via explicit signals, but does not manage host runtime behavior.
The client is treated as an untrusted execution environment and is not responsible for enforcing business invariants.
- Application shell: Root component responsible for layout composition, inactivity warning overlay, and health/heartbeat orchestration.
- Routing layer: Declarative route definitions mapping screens to paths and associating inactivity policies.
- Interaction screens: Touch-oriented screens for initial selection, code entry, waiting/polling, and terminal outcomes.
- Shared UI primitives: Header shell and timed-redirect components that enforce consistent layout and reset behavior.
- Inactivity subsystem: Service and overlay that listen for user interaction events and trigger resets on expiry.
- Localization subsystem: Translation service and HTTP loader that fetch language resources and persist locale selection.
- Transient status store: In-memory service that temporarily captures status details for consumption by subsequent screens.
- Code submission: The client submits user-entered codes and request types to an external service using a kiosk authorization header.
- Status polling: The client periodically queries an external service to resolve submitted codes into terminal outcomes.
- Health monitoring: The client checks an external health endpoint on a fixed interval to determine availability.
- Localization resources: Language assets are loaded via HTTP based on the active locale.
All integrations are strictly outbound and mediated through a single HTTP abstraction.
- Visitor selects an action from the start screen.
- Visitor enters a numeric code using the on-screen keypad.
- Client validates completeness, stores the code in session storage, and submits it to an external service.
- Client navigates to a waiting screen that polls for resolution.
- Client transitions to a success, invalid, or error screen and automatically resets to the start screen after a fixed delay.
- Inactivity tracking is enabled on most screens and listens for touch, mouse, and keyboard events.
- A warning overlay appears shortly before the inactivity timeout.
- If no interaction occurs, the client clears transient state and navigates back to the start screen.
- On initialization, the client begins health checks against an external service.
- When the service is healthy, the client emits a one-time readiness signal and periodic heartbeat messages to the host container.
- If health checks fail, heartbeat signaling is suspended until health is restored.
- Transient UI state: Component-local state controls keypad input, timers, and visual feedback.
- Session storage: The last submitted code is stored briefly to bridge the entry and waiting screens.
- In-memory service state: Status details are held temporarily and cleared after consumption.
- Localization preference: The selected language is stored in browser storage and rehydrated on startup.
No durable or privileged data is stored on the client.
- Health-aware behavior: External availability gates readiness and heartbeat signaling.
- Polling limits: Status polling is bounded; exceeding limits results in a controlled error path.
- Error routing: Integration failures route the user to an error screen with an automatic reset.
- Inactivity safety: Idle resets prevent stale or abandoned sessions from persisting.
Failure handling is explicit and converges toward a safe, known entry state.
- Threat model: The client is treated as an untrusted surface running in a public environment.
- Client-to-service authentication: Requests include a kiosk authorization header sourced from runtime configuration.
- Minimal trust: All validation and decision-making are delegated to external services.
- Local storage limits: Only short-lived, non-sensitive values (code, locale) are persisted locally.
No long-term credentials or secrets are embedded in the client.
-
Standalone component architecture
Why: Centralizes configuration and reduces module overhead.
Trade-off: Requires explicit imports and disciplined structure. -
Deterministic, route-driven navigation
Why: Simplifies recovery and reduces edge cases in unattended environments.
Trade-off: Less flexibility for non-linear flows. -
Polling instead of push-based updates
Why: Predictable behavior across constrained or embedded runtimes.
Trade-off: Increased latency and network usage. -
Timed redirects for terminal states
Why: Ensures the kiosk quickly returns to a usable state.
Trade-off: Limits time for user review of outcomes.
- Start with the bootstrap sequence to understand provider wiring and initialization order.
- Review route definitions to see how navigation and inactivity policies are enforced.
- Trace HTTP interactions to confirm clear integration boundaries and error handling.
- Inspect state handoffs between screens via session storage and in-memory services.
- Pay particular attention to kiosk-specific logic: idle resets, warnings, and host signaling.
Business semantics and domain-specific rules are intentionally excluded.
The current implementation is a focused kiosk SPA with a minimal, deterministic flow:
start → action selection → code entry → waiting → outcome → reset
The codebase is structured around clear boundaries and shared primitives, making it suitable for incremental extensions (additional flows, locales, or integrations) without destabilizing the core execution model.
This document presents a neutral, anonymized architectural view of a kiosk-oriented SPA.
It highlights execution flow, boundary enforcement, and operational constraints typical of unattended, public-facing systems.
If you’re dealing with similar challenges — kiosk interfaces, constrained runtimes, or systems that must reliably recover without human intervention — feel free to reach out: