AZ-002 — Mobile application shell and navigation
Status
Done
Context
Read the epic contract. React Router's reusable appRoutes and AppLayout already
exist; Home displays a real database message and * renders not-found. AZ-001 supplies translations
and language/appearance preferences. No side menu or MUI exists. All workspace versions are 0.0.0;
the root manifest currently has no version field.
Goal
Deliver the mobile-first Foodtruck Order shell with centralized brand/theme, localized icon navigation, simple page registration, and meaningful build/version information.
Requirements
- Add compatible Material UI, Emotion and
@mui/icons-materialdependencies in frontend. UseThemeProvider/CssBaselineand a theme factory for palette, typography, spacing and justified touch/focus defaults. Consume AZ-001 light/dark/system preference; listen to system appearance changes and respect reduced motion. Do not distribute brand/style constants through pages. - Define one static identity configuration for Foodtruck Order name, logo asset/fallback mark, document title and theme palette inputs. Use a repository-owned simple mark/text fallback; no asset-generation service or remote logo dependency is required. Decorative logos have empty alt text when adjacent product text supplies identity; standalone meaningful logos are labeled.
- Replace the affected Tailwind shell/Home/NotFound/async-state styling with MUI/theme styles, preserving message retrieval and state semantics. Inspect all class usages; remove Tailwind dependency/plugin/CSS import only after none remain. Do not keep conflicting reset systems or undertake unrelated domain refactors. Update build/test expectations for styling changes.
- Mobile default: application bar with labeled menu button, product area, single main content column, no reserved sidebar width. Temporary drawer opens/closes conventionally, traps focus, closes on Escape/backdrop/navigation, and restores toggle focus when appropriate. After a route change, close drawer and move focus logically to page content/heading without fighting focus restoration. Prevent background scroll only while modal drawer is open.
- At MUI
mdand above use a permanent side drawer with content offset. Test transition both ways, not just initial render. Navigation content scrolls when needed; version footer stays toward the bottom without hiding items/actions on short viewports. Prefer document scrolling for main content; avoid nested full-height scroll traps or clipped safe-area controls. - Create one typed page declaration and derive route tree/menu from it using existing React Router. Include path, translation label key, MUI icon, element, optional menu visibility, public/authenticated access metadata, and developer-only metadata. No separate hand-maintained menu or page-plugin system. Hidden/detail/fallback routes must work without icon/menu entry. Auth enforcement itself is AZ-006; do not expose a protected page before it exists.
- Register Home
/and an initial/settingspage. Settings provides the real language and appearance controls from AZ-001 (move the temporary Home selector there). It is public until AZ-006 deliberately protects it; do not imply account operations exist yet. Home remains the vertical-slice demonstration. Preserve*, deep links/refresh, and normal browser history. - Each visible item uses one MUI icon, localized human name and real router link, with active
styling plus
aria-current="page". Home matches only/, not every route. Use semantic nav with ordinary links, not an ARIA menu requiring application-menu keyboard behavior. Provide a skip link/main landmark, visible focus and accessible toggle expanded/controlled state. - Establish root
package.jsonversionas the sole application-release version, initially0.1.0for the foundation unless an existing release convention appears on reinspection. Workspace versions remain package versions; OpenAPIinfo.versionremains API-contract version. Do not copy/keep a second app release number in frontend source or env examples. - Vite reads root version at build/configuration time and injects a typed public build constant.
Optional short commit comes only from allowlisted
APP_BUILD_SHA, supplied from CI revision; local absence displays version alone (orlocal), never a misleading SHA. Displayv0.1.0and optional short SHA in a separated drawer footer. Do not introduce build date/network/env details just for decoration. Test with injected fixture metadata rather than git availability. - Ensure frontend Docker build copies/reads root manifest and explicitly accepts/passes optional SHA
build metadata if supported. Docker has no
.gitand cannot discover a commit implicitly. Host CI build and Compose build pass the same revision when CI requests metadata; the UI must still work without it. Keep runtime API URL injection distinct and unchanged.
Non-goals
No login/account persistence, custom navigation engine, runtime branding, tenant theme, second icon library, desktop-first dashboard, complex widget library, or new deployment pipeline.
Implementation guidance
Extend frontend/src/app/router.tsx, app/layout/AppLayout.tsx, app/providers.tsx, and existing
pages/, components/, vite-env.d.ts, vite.config.ts responsibilities. Keep appRoutes usable
with memory routers. Provider factories from AZ-001 isolate theme/query/preference tests. MUI sx
base values describe mobile, with larger breakpoint overrides. Use MUI's React Router link
integration instead of click-only navigation; decorative item icons need no duplicate label. CI
artifact names and API/OpenAPI behavior remain intact. Any new build metadata code must have focused
tests; no blanket coverage exclusions for the shell or registry.
Acceptance criteria
- Mobile drawer reserves no closed sidebar space and supports Escape, focus, touch and route closure; desktop drawer and resize transitions behave correctly.
- Home/Settings show localized labels/icons/current-page state; unknown/hidden routes work.
- Adding a sample ordinary page needs only component, declaration, locale keys and tests; demonstrate in documentation, remove any temporary sample page before completion.
- Brand/theme changes use one configuration; light/dark/system affect real surfaces.
- Version comes from root manifest in host/Compose builds; optional SHA is correct/absent.
- The real message workflow survives MUI/Tailwind migration and runtime API URL precedence.
Verification
pnpm quality
pnpm --filter @foodtruck-order/frontend test
pnpm --filter @foodtruck-order/frontend test:coverage
pnpm build
pnpm test:ci
pnpm validate:docker
Use isolated Compose validation if preserving development data. Add RTL tests for registry/menu, settings/theme, semantic current links and keyboard behavior; browser tests cover responsive layout, drawer focus and route/deep-link behavior. Introduce a Chromium mobile project (360×800, touch) alongside desktop in both existing Playwright configs, sharing spec behaviors and isolated state. AZ-011 extends reusable accessibility checks, not first mobile testing. Manually inspect 320px, 360×800, 768×1024, 1280×800, short height, 200% zoom, dark contrast and phone scrolling.
Documentation
Update architecture, techstack, development (the exact create/register/icon/translation/test page
workflow, root version release process), Docker (metadata versus runtime API config), testing and CI
(mobile projects and metadata propagation). Record significant frontend/styling decision in
docs/decisions/ and update current-state/handover with evidence.
Dependencies
AZ-001. Existing React Router, API/query/message workflow, host/Compose builds and Playwright.