Decision: Treat validation as a completion gate for all code changes and require automated tests per functionality change.
Why: Keeps code quality and regression resistance aligned with production-readiness and security goals.
ADR-009: Dev API routing = same-origin /api with proxy¶
Date: 2026-02-22
Status: accepted
Decision: In Docker development, frontend calls /api and Vite proxies to backend (VITE_PROXY_TARGET) instead of hardcoding localhost API URLs.
Why: Allows local-network/mobile testing where localhost on the client device would otherwise break API connectivity.
ADR-010: Home capture UX = explicit locate state + capture slots¶
Date: 2026-02-22
Status: accepted
Decision: Replace manual latitude/longitude fields with explicit Locate flow (GPS + reverse place lookup / No location could be established) and use 3 camera-first photo slots with thumbnail preview/retake/remove controls.
Why: Improves mobile ergonomics and reduces user error in garages/cities while keeping the save flow explicit.
ADR-011: Location optional with evidence fallback¶
Date: 2026-02-22
Status: accepted
Decision: Allow parking record creation without coordinates when a note and/or photos are provided; enforce latitude/longitude as an all-or-nothing pair.
Why: Parking garages can block GPS, so save must still work with contextual evidence while preserving API data integrity.
Decision: Persist reverse-geocoded place text on records (location_label) and render latest/history with a shared expandable card (More info/Close) that shows map preview, saved address text, photos, and map actions.
Why: Improves scanability and avoids repeated geocoding lookups while giving a compact default list view with richer on-demand details.
Decision: Use a locally bundled parked-car background image (frontend/public/images/parking-background-option-3.jpg) from selected royalty-free source, rendered with theme-aware overlays.
Why: Keeps visual identity aligned with app purpose while avoiding external runtime hotlink dependencies and preserving text readability.
ADR-015: Open self-registration + split auth modes¶
Date: 2026-02-22
Status: accepted
Decision: Keep self-registration open (no moderation gate) and render logged-out auth as two explicit modes (Sign in/Register) under the standard top bar.
Why: Matches product direction for immediate onboarding and provides a clearer mobile-first auth flow with space reserved for future banner content.
Decision: Add admin-only user update/delete endpoints and an admin UI with split Add users / Edit users sections, including modal-based role/password changes.
Why: Reduces operational friction for multi-user management while preserving guardrails (no self edit/delete via admin endpoints and no removal of last admin).
Usernames: normalized lowercase, 3-64 chars, restricted character set.
Password policy for create/reset/change: 8-128 chars with uppercase/lowercase/digit.
Text fields (note, location_label) are normalized and reject control characters.
Admin/user path/query identifiers and limits are validated at API boundary where applicable.
ADR-021: Replace plugin-based PWA build chain with local manifest/service worker¶
Date: 2026-02-22
Status: accepted
Decision: Remove vite-plugin-pwa and ship PWA support through static manifest.webmanifest + local sw.js.
Why: Dependency audit showed unresolved high-severity advisories in the plugin/workbox chain; local implementation reduces third-party attack surface while preserving installable PWA behavior.
Security note: service worker cache excludes /api/* to avoid caching authenticated API responses.
ADR-022: PWA cache versioning keyed by release tag¶
Date: 2026-02-22
Status: accepted
Decision: Register service worker with a versioned URL query (/sw.js?v=<APP_VERSION>) and derive cache namespace from that version.
Why: Ensures installed/mobile PWA clients receive deterministic cache rotation on each release deployment instead of remaining on stale app-shell caches.
Details:
Deployment sets APP_VERSION (typically equal to git release tag) and forwards it to frontend build as VITE_APP_VERSION.
Service worker cache key prefix includes release version.
Navigation fetch strategy uses network-first with offline fallback to cached index.html for better update propagation while preserving offline behavior.
ADR-023: Client-side accent color presets for UI controls¶
Date: 2026-02-22
Status: accepted
Decision: Add user-selectable accent presets in profile settings and apply them live to primary buttons and active selector controls.
Why: Improves personalization and quick visual contrast tuning on mobile/desktop without introducing backend profile storage complexity.
Details:
Accent selection is stored in browser local storage (fmr_accent_color).
Accent applies to primary CTA buttons and active navigation/auth selectors.
Each preset defines separate light/dark tone values so contrast remains readable across both themes.
Presets are curated for white foreground label readability over the existing app background treatment.
Decision: Replace Last parked on home with a two-state flow: Parked? start form and You are parked active session panel that ends only on explicit confirmation.
Why: Matches real parking behavior, prevents accidental history writes before a parking action is complete, and improves day-of-use orientation while parked.
Details:
Remember This starts a local active session when location or note/photo evidence exists.
Active session shows start time, running duration, optional map, notes, and photo thumbnails.
End parking requires yes/no confirmation and writes the record to history only after confirmation.
Active session is persisted per user in browser local storage to survive app close/reopen.
While active and permission granted, browser notifications can display parked duration updates.
ADR-026: Manual logout must suppress same-session silent refresh¶
Date: 2026-02-22
Status: accepted
Decision: When logout is user-initiated, set a client-side manual-logout guard that blocks the no-token startup refresh path in the same app session.
Why: Prevents mobile timing races where /auth/logout completion can lag and a background refresh could immediately re-authenticate the user after they sign out.
Details:
Guard is enabled in logout handler before token state is cleared.
Guard is reset on explicit authentication success (login/register/bootstrap).