Frontend Architecture - Enterprise Angular SPA (@gercia/app)
1. Architectural Strategy & Design System
Section titled “1. Architectural Strategy & Design System”The enterprise presentation layer of the GERCIA Platform is engineered as a unified, high-performance Single Page Application (SPA): @gercia/app (apps/app/). In accordance with ADR-008, @gercia/app decommissioned legacy server-side Blazor WebSockets in favor of a modern Angular 22 client runtime executing at the browser edge and hosted globally on Cloudflare Pages CDN.
Core Frontend Technology Stack
Section titled “Core Frontend Technology Stack”| Technology Layer | Selected Framework | Architectural Responsibility |
|---|---|---|
| Framework & Engine | Angular 22 (Zoneless, Signals) | Reactive client-side architecture using Standalone Components, reactive Signals, and inject() dependency injection without Zone.js overhead. |
| Component Suite | PrimeNG 22 | Enterprise UI components (DataTables, MultiSelect, Dialogs, Toasts, Avatars) natively styled via modern design tokens (Aura / Lara). |
| Utility Styling | Tailwind CSS v4 | Zero-runtime CSS engine providing utility classes, dark mode tokens, and unified responsive layout primitives. |
| Medical Scheduling | FullCalendar v6+ (@fullcalendar/angular) |
Day, Week, Month timegrid views, multi-practitioner resource columns, and drag-and-drop clinical appointment booking. |
| Decoupled Edge Hosting | Cloudflare Pages | Sub-second global Anycast CDN delivery with zero origin server overhead, HTTP/3, and automated branch deployments. |
| API Authentication | angular-auth-oidc-client |
Sovereign OAuth 2.1 with PKCE authenticating against Gercia.Server (OpenIddict STS) with automatic Refresh Token Rotation. |
flowchart TD
subgraph EDGE ["1. Global Anycast Delivery (Cloudflare Pages)"]
CDN["Cloudflare Edge Anycast CDN<br>(HTTP/3 • Zero Origin Server Ingress)"]
STATIC["Static Distribution Bundle (dist/)<br>• ESBuild Chunking & Tree-Shaking<br>• Sub-Second Initial Load Worldwide"]
CDN --> STATIC
end
subgraph RUNTIME ["2. Angular 22 Zoneless Client Engine"]
STANDALONE["Standalone Component Tree<br>(Zero NgModule Declarations)"]
SIGNALS["Signal-Driven Reactivity<br>(computed(), effect(), signal())<br>Ultra-Low Memory & CPU Footprint"]
INJECT["Native Dependency Injection<br>(inject() Functional Invocations)"]
end
subgraph UI_SYSTEM ["3. Design System & Peripherals"]
PRIMENG["PrimeNG 22 Component Suite<br>(DataTables, Menus, Modals, Badges)"]
TAILWIND["Tailwind CSS v4 Engine<br>(Deep Petrol Palette • Dark/Light Modes)"]
CALENDAR["FullCalendar Scheduling Engine<br>(Multi-Resource Clinical & Lab Columns)"]
end
subgraph GATEWAYS ["4. Secure Cloud & Edge Communications"]
API_GW["Gercia.Server REST Minimal APIs<br>(api.gercia.com.br / TLS 1.3)"]
STS["OpenIddict Sovereign STS<br>(OAuth 2.1 PKCE • Token Rotation)"]
HUB_EDGE["GERCIA Hub Workstation Agent<br>(http://127.0.0.1:5050 / RS-232 & Thermal)"]
end
STATIC --> RUNTIME
RUNTIME --> UI_SYSTEM
RUNTIME <--> STS
RUNTIME <--> API_GW
RUNTIME <-->|"Sub-Millisecond Loopback"| HUB_EDGE
2. Dynamic Host-Based Presentation Segregation
Section titled “2. Dynamic Host-Based Presentation Segregation”The enterprise frontend operates as a single consolidated Angular codebase deployed across multiple public and private subdomains. Rather than building and deploying distinct applications for each vertical, @gercia/app resolves its visual layout, navigational menus, and authentication policies dynamically at runtime based on the HTTP Host header via PortalService (apps/app/src/app/core/portal/portal.service.ts):
flowchart TD
REQ["Incoming Browser Request<br>(window.location.hostname)"] --> DETECT["PortalService<br>(Evaluates Subdomain & Domain Boundary)"]
DETECT --> COND{Active Hostname?}
COND -- "ops.gercia.com.br<br>ops-stg.gercia.com.br<br>(or ops.gercia.dev)" --> PORTAL_OPS["PortalContext: 'operations'<br>• Cloudflare Zero Trust (WARP + Google Workspace SSO)<br>• Zero-Click Authentication via /api/ops/me Edge Function<br>• SaaS Subscriptions, Tenants Management, System Health"]
COND -- "app.gercia.vet.br<br>app-stg.gercia.vet.br<br>(or vet.gercia.dev)" --> PORTAL_VET["PortalContext: 'veterinary'<br>• OpenIddict STS B2B Authentication (Tenant Scoped)<br>• Emerald Green branding & MAPA/SIPEAGRO workflows<br>• Animal Patients, Breeds, Legal Tutors, Vet Compounding"]
COND -- "app.gercia.com.br<br>app-stg.gercia.com.br<br>(or app.gercia.dev)" --> PORTAL_APP["PortalContext: 'human' (Default)<br>• OpenIddict STS B2B Authentication (Tenant Scoped)<br>• Petrol Blue branding & CFM/CFO/ANVISA workflows<br>• Medical EHR, FDI/ISO 3950 Odontograms, Galenic Lab SGQ"]
Portal Segregation & Environment Invariants
Section titled “Portal Segregation & Environment Invariants”- Strict Zero-Query-String Override: Portal context resolution relies exclusively on
window.location.hostname. Overriding portal roles via query strings (e.g.,?portal=operations) is strictly prohibited, guaranteeing that client users can never cross security boundaries into administrative routes. - Canonical Staging Subdomain Handling: In accordance with the Cloudflare Universal SSL single-level wildcard rule (
*.gercia.com.brand*.gercia.vet.br), staging portals strictly use hyphenated subdomains:ops-stg.gercia.com.br,app-stg.gercia.com.br, andapp-stg.gercia.vet.br. - Reactive Signals Interface (
PortalService):portal(): Signal<PortalContext>: Returns'human','veterinary', or'operations'.environment(): Signal<PortalEnvironment>: Returns'production','staging', or'local'.isHuman(): Signal<boolean>: Computed signal indicating whether human healthcare features are active.isVeterinary(): Signal<boolean>: Computed signal indicating whether veterinary features are active.isOperations(): Signal<boolean>: Computed signal indicating whether internal backoffice features are active.isProduction(): Signal<boolean>: Computed signal indicating production environment.isStaging(): Signal<boolean>: Computed signal indicating staging environment.isLocal(): Signal<boolean>: Computed signal indicating local workstation environment.
- Local Engineering Wildcard Parity: In local development, host detection resolves
ops.gercia.dev,vet.gercia.dev, andapp.gercia.devto their respective portal modes with zero manual configuration. - Chromium HSTS Preload & SSL Invariant (
ssl: trueon Port 7250): Because the.devgTLD is preloaded in Chromium’s HSTS list, browsers automatically force HTTPS. Inapps/app/angular.json, the dev server is configured with"ssl": trueon port7250withallowedHosts: [".gercia.dev", "localhost", "127.0.0.1"]to deliver valid TLS and preventERR_SSL_PROTOCOL_ERROR.
3. Edge Functions & Zero-Click Backoffice Authentication (ENG-17)
Section titled “3. Edge Functions & Zero-Click Backoffice Authentication (ENG-17)”For internal operators accessing ops.gercia.com.br or ops-stg.gercia.com.br, @gercia/app enforces Zero-Click Authentication without manual login buttons or forms:
sequenceDiagram
autonumber
actor Dev as GERCIA Staff Member
participant CF_EDGE as Cloudflare Zero Trust Edge
participant PAGES as Cloudflare Pages (/index.html)
participant FUNC as Pages Function (/api/ops/me)
participant AUTH as Angular AuthService (Signals)
Dev->>CF_EDGE: GET https://ops.gercia.com.br
Note over Dev,CF_EDGE: Cloudflare Access evaluates WARP Posture + Google Workspace SSO
CF_EDGE->>PAGES: Proxies authenticated request with CF-Access-Jwt-Assertion
PAGES-->>Dev: Delivers Angular SPA Bundle
Dev->>AUTH: App Bootstraps (AuthService.initAuth())
AUTH->>FUNC: GET /api/ops/me
FUNC->>FUNC: Inspects cf-access-jwt-assertion & cf-access-authenticated-user-email
FUNC-->>AUTH: HTTP 200 { authenticated: true, email: "user@gercia.com.br", ... }
AUTH->>AUTH: Updates state signal: operator = { email, roles }
AUTH-->>Dev: Renders Backoffice Dashboard Instantly (Zero Clicks)
Architectural Implementation:
Section titled “Architectural Implementation:”- Cloudflare Pages Function (
apps/app/functions/api/ops/me.ts): Executes natively at the Cloudflare Edge Worker runtime. It inspects thecf-access-authenticated-user-emailandcf-access-jwt-assertionheaders injected by Cloudflare Access. If missing, it returns{ authenticated: false }. - Angular
AuthService(apps/app/src/app/core/auth/auth.service.ts): Uses modern Angular 22 Signals (state,operator,isAuthenticated,userEmail,isDevMock). - Local Dev Mocking (
ops.gercia.dev:7250): When running locally onisLocal() && isOperations(),AuthServiceautomatically simulates authenticated operator session (devsecops@gercia.com.br) withisDevMock: true, completely decoupling local developers from Cloudflare Access Edge infrastructure. - Cloudflare SPA Routing Rule (
apps/app/public/_redirects): Includes/* /index.html 200, guaranteeing that deep links, route refreshes, and internal Angular Router state changes never cause HTTP 404 on Cloudflare Pages CDN.
3. Reactive State Management & Component Taxonomy
Section titled “3. Reactive State Management & Component Taxonomy”@gercia/app enforces modern Angular architecture patterns based on Signals and Smart/Dumb Component Segregation:
flowchart LR
subgraph SMART ["Smart / Container Components (Pages)"]
PAGE["PrescriptionPage / OdontogramPage<br>• Injects Feature State Services<br>• Coordinates Route Parameters & Observables<br>• Dispatches API Actions"]
end
subgraph STATE ["Feature State Services (Signals)"]
SVC["PrescriptionStateService<br>• items = signal<PrescriptionItem[]>([])<br>• totalItems = computed(() => items().length)<br>• isLoading = signal<boolean>(false)"]
end
subgraph PRESENTATIONAL ["Presentational / Dumb Components"]
UI1["ToothSurfaceSelectorComponent"]
UI2["PrescriptionItemRowComponent"]
UI3["WeighingStatusIndicatorComponent"]
end
PAGE <--> SVC
PAGE -->|"inputs (Signal Values)"| PRESENTATIONAL
PRESENTATIONAL -->|"outputs (Events)"| PAGE
Key Architectural Guidelines:
Section titled “Key Architectural Guidelines:”- Signal-Driven Reactivity: All mutable UI state is modeled using Angular Signals (
signal<T>(),computed(), andeffect()). Components consume state reactively without requiring manual RxJS subscription unsubscriptions (takeUntilDestroyed()). - Zoneless Readiness: By eliminating dependence on
Zone.jschange detection monkey-patching, components trigger surgical DOM updates precisely at the signal dependency level, reducing memory footprints and battery drain on clinical laptops and tablets. - Standalone Components Only: The entire codebase is 100% standalone (
standalone: true). Shared reusable components are imported directly into theimportsarray of consuming views.
4. Client-Side Security & OpenIddict PKCE Integration
Section titled “4. Client-Side Security & OpenIddict PKCE Integration”Authentication is orchestrated via angular-auth-oidc-client implementing the OAuth 2.1 Authorization Code Flow with Proof Key for Code Exchange (PKCE):
sequenceDiagram
autonumber
actor User as Healthcare Professional
participant Browser as @gercia/app (Angular 22)
participant STS as Gercia.Server (OpenIddict STS)
participant API as Gercia.Server (REST Minimal APIs)
User->>Browser: Enters Credentials / Selects Provider
Browser->>Browser: Generates Cryptographic PKCE Code Verifier & Challenge
Browser->>STS: Authorization Request (response_type=code, code_challenge)
STS->>User: Renders Login Challenge / TOTP 2FA Verification
User->>STS: Submits Credentials & Authenticator TOTP Code
STS-->>Browser: Redirect with Authorization Code
Browser->>STS: Token Exchange (grant_type=authorization_code, code_verifier)
STS-->>Browser: Issues Signed Access Token (JWT 15m) + Refresh Token (30d)
Browser->>Browser: Stores Access Token in Secure In-Memory Session
loop API Interactions
Browser->>API: HTTP Request with Bearer Access Token
API-->>Browser: 200 OK (Postgres RLS Enforced)
end
Note over Browser,STS: Automatic Silent Refresh Token Rotation prior to 15m expiry
Security Safeguards:
Section titled “Security Safeguards:”- Zero Secrets in Frontend: The client possesses no client secrets. All cryptographic authorization relies on short-lived PKCE code verifiers generated via the browser’s native
window.crypto.subtleAPI. - Refresh Token Rotation (RTR): Every token refresh invalidates the previous refresh token and issues a new cryptographically bound refresh token, immediately detecting token theft attempts.
- Role & Scope Guards (
AuthGuard,RoleGuard): Angular functional router guards (canActivate: [authGuard, roleGuard]) inspect the decoded claims (role,tenant_id,modules) before activating route transitions.
5. Two-Tier Input Validation & Brazilian Healthcare Standards
Section titled “5. Two-Tier Input Validation & Brazilian Healthcare Standards”In compliance with Brazilian medical, dental, and pharmacy regulations, @gercia/app enforces comprehensive client-side form validation before transmitting payloads to backend hosts:
ReactiveFormsModuleStructured Form Hierarchies: Forms are structured using strictly typedFormGroup<T>andFormArray<T>, eliminating untyped form payloads.- Custom Brazilian Legal & Sanitary Validators:
GerciaValidators.cpf: Validates mod-11 check digits on patient and professional Brazilian CPF tax IDs, stripping formatting (.,-) automatically.GerciaValidators.cnpj: Validates corporate tax IDs for compounding pharmacies and healthcare clinics.GerciaValidators.cns: Validates 15-digit Brazilian National Health Cards (Cartão Nacional de Saúde - CNS).GerciaValidators.councilNumber: Validates professional credentials against issuing regional councils (CRM,CRO,CRMV,CRF,CREFITO).
- Instant Ergonomic Feedback: Forms provide real-time field-level validation feedback utilizing PrimeNG
p-messageand Tailwind alert states, preventing user submission frustration.
6. Workstation Hardware Edge Integration (GERCIA Hub)
Section titled “6. Workstation Hardware Edge Integration (GERCIA Hub)”Cleanroom compounding workstations in pharmacies and diagnostic specimen labeling stations require sub-millisecond communication with bench hardware:
flowchart LR
subgraph BROWSER ["Browser Session (@gercia/app)"]
WEIGH_COMPONENT["Assisted Weighing Component<br>(Compounding Workstation View)"]
PRINT_COMPONENT["Thermal Label Printing Service<br>(ZPL / TSPL Formatter)"]
end
subgraph HUB ["Local Workstation Agent (GERCIA Hub - Gercia.Edge)"]
LOOPBACK["Local HTTP/SSE Server<br>http://127.0.0.1:5050<br>(Zero Cross-Origin Restrictions)"]
SERIAL["Serial Scale Worker<br>(RS-232 Toledo/Gehaka Parser)"]
SPOOLER["Raw Thermal Spooler<br>(Zebra ZPL / Argox RAW Port)"]
end
WEIGH_COMPONENT <== "1. Real-time Weight Stream (SSE / < 1ms)" ==> LOOPBACK
LOOPBACK <--> SERIAL
PRINT_COMPONENT -- "2. Silent RAW Print Job (HTTP POST)" --> LOOPBACK
LOOPBACK --> SPOOLER
- Zero Cloud Latency: Tare and weight streaming execute 100% locally over loopback (
127.0.0.1:5050). A transient internet outage never halts laboratory cleanroom weighing. - Silent Printing: Prescription and batch thermal labels print silently in under 50 milliseconds without triggering intrusive browser print preview modals.