<!-- BEGIN:nextjs-agent-rules -->

# This is NOT the Next.js you know

This version has breaking changes — APIs, conventions, and file structure may all differ from your training data. Read the relevant guide in `node_modules/next/dist/docs/` (resolved from this file's directory; in monorepos the `next` package may not be visible from the repo root) before writing any code. Heed deprecation notices.

This block is written and re-added by `next dev` — verify at `node_modules/next/dist/server/lib/generate-agent-files.js`. Removing it from a diff only re-creates the uncommitted change; committing it with your work keeps the tree clean.

<!-- END:nextjs-agent-rules -->

# TIAR CSMS rewrite — development guidelines

These instructions apply throughout this project. Act as a senior software engineer: prioritize correctness, readable code, maintainability, and appropriate performance. Inspect the relevant implementation before changing it.

## Product goals and current scope

- Preserve the existing dashboard's appearance and behavior. `../tiar-dashboard` is the visual and interaction reference; this application's current implementation includes later user-approved changes such as Tiar branding and offline maps.
- Preserve layout, navigation, typography, spacing, colors, table density, forms, dialogs, charts, responsive behavior, and loading/empty/error states. Do not redesign a screen as part of a refactor.
- Work incrementally on the requested feature. Current dashboard scope is `/`, `/locations`, `/locations/[id]`, `/chargepoints`, `/chargepoints/[id]`, `/sessions`, and `/sessions/[id]`, plus sign-in and password screens. Do not migrate other page families without a requirement.
- Authentication is already connected to the CSMS API when configured. Operational records and device actions still use typed mocks/local previews. Do not extend backend integration unless the task requests it.
- Maps intentionally use an offline preview. Do not add a Google Maps dependency or key requirement without an explicit change in scope.
- Read `README.md` for setup and preview behavior, and `AUTHENTICATION.md` before changing auth. The original UI-only brief is historical; preserve the subsequently integrated auth flow.

## Engineering principles

- **KISS:** choose the simplest implementation that satisfies the actual requirement. Prefer obvious code over clever code.
- **YAGNI:** implement what is needed now. Avoid speculative features, dependencies, providers, state stores, repository layers, factories, or generic component registries.
- **DRY with restraint:** extract meaningful reuse, not every repeated line or `<div>`. Share a helper only when it makes responsibilities clearer.
- Keep UI, data access, domain logic, formatting, and state appropriately separated. Use small focused functions and meaningful names.
- Preserve project conventions. Keep changes scoped; explain any behavior change and its tradeoff.
- Add comments for non-obvious decisions, not descriptions of straightforward code. Handle errors explicitly; avoid silently swallowing exceptions.
- Before adding a dependency, identify the concrete problem it solves better than the existing framework or libraries. Keep the lockfile consistent with dependency changes.

## Stack and code organization

The project uses Next.js App Router, React, strict TypeScript, Tailwind CSS v4, customized shadcn/Radix primitives, Lucide, and ApexCharts. Check `package.json` and the lockfile for installed versions; use the bundled Next.js documentation above for version-specific APIs.

| Location | Responsibility |
| --- | --- |
| `src/app/(auth)` | Sign-in, password setup, and password reset routes and guards |
| `src/app/(dashboard)` | Dashboard layout, pages, and route states |
| `src/app/api/auth` | Thin same-origin auth Route Handler wrappers |
| `src/features/<feature>` | Domain types, fixtures, queries, and feature components |
| `src/components/ui` | Shared accessible UI primitives |
| `src/components/shared` | Reused dashboard concepts such as filters, pagination, panels, and map previews |
| `src/components/layout` | Shell, navigation, branding, and theme controls |
| `src/lib/auth` | Auth contracts, upstream transport, cookies, and server session validation |
| `src/lib` | Shared formatting, URL queries, exports, and `cn()` |
| `src/mocks` | Temporary draft validation and preview storage |
| `src/app/globals.css`, `public`, `src/app/fonts` | Design tokens, styles, existing assets, and local fonts |
| `tests` | Deterministic behavior and auth contract tests |

Keep domain code near its feature. Keep route files focused on composing data and presentation. Avoid empty architectural folders, unnecessary barrel exports, and giant page components. Use the `@/` alias for application imports; preserve explicit `.ts` imports where the Node test setup requires them.

## Next.js and React

- Default to Server Components for pages, layouts, data preparation, and noninteractive presentation. Add `"use client"` only for state, event handlers, browser APIs, or client-only libraries.
- Keep client boundaries as small as practical. An interactive child does not require making its page a Client Component. Pass Server Component content through client shells when appropriate.
- Choose rendering intentionally: static content can be prerendered; authenticated, tenant-specific, or request-specific content needs request-time behavior. Do not apply `force-dynamic`, disable SSR, or add cache directives everywhere.
- Follow this Next.js version's async request APIs: await `params`, `searchParams`, and cookie access where required. Use `next/link`, framework navigation, metadata, and route-level loading/error/not-found conventions appropriately.
- Fetch server data in Server Components or focused server helpers. Server Components should call those helpers directly instead of making an HTTP round trip to their own Route Handlers.
- Keep secrets, cookie access, and upstream auth logic out of client imports. Pass only serializable, necessary, safe data to Client Components.
- Make caching deliberate. Never share session or tenant-private responses across users. Auth requests remain uncached; request-scoped session deduplication is distinct from persistent caching.
- Run independent server work concurrently when useful, while preserving auth checks and real dependencies. Use meaningful Suspense/loading boundaries instead of empty placeholders.
- Derive values from props/state during render when possible. Use effects for synchronization with external systems; do not use them for routine derived state or server data fetching. Clean up listeners and timers.
- Use stable record keys. Avoid redundant state, hydration mismatches, and blanket hydration-warning suppression. Add memoization only for a demonstrated cost.
- Retain `next/font/local` for Outfit and reuse existing assets. Use `next/image` when appropriate, with correct dimensions/sizes and loading priorities.
- Keep ApexCharts behind its existing client-only dynamic boundary. Load PDF/Excel export libraries when requested. Do not disable server rendering for the whole page to accommodate a heavy widget.

## Data, types, and state

- Preserve strict TypeScript, `noUnusedLocals`, and `noUnusedParameters`. Avoid `any`, unsafe assertions, and unnecessary generic type systems. Validate unknown API payloads before using them.
- Keep domain types and large fixtures outside page components. Presentation should consume typed props, so a future server fetch can replace fixture loading without rebuilding the UI.
- Do not add a speculative API client or service framework. Extend the existing small boundary when an actual endpoint is integrated.
- Use URL/search parameters for bookmarkable search, filters, tabs, sorting, page, and page size. Validate and bound them using existing query helpers; preserve unrelated parameters when updating one control.
- Use local state for temporary dialogs, selection, and form inputs. Context is for genuinely shared UI concerns; do not introduce Redux/Zustand by default.
- Preview drafts may use the existing tab-scoped `sessionStorage` implementation. Treat stored records as untrusted input and keep preview storage separate from real server persistence.
- Keep filtering, sorting, pagination, validation, and formatting helpers deterministic. When real datasets are introduced, use backend pagination/filtering rather than loading entire datasets into the browser.

## Authentication and API safety

- Extend the existing flow through `src/features/auth`, `/api/auth/*`, and `src/lib/auth`. Preserve origin checks, input/content-type validation, header allowlists, timeouts, safe errors, and cookie handling.
- Keep `CSMS_API_BASE_URL`, `CSMS_FORWARDED_HOST`, and `CSMS_APP_NAME` server-only. Do not expose them as `NEXT_PUBLIC_*` settings or accept arbitrary upstream hosts, tenant headers, or bearer tokens from browser input.
- An unset API base URL currently enables the local UI preview. Never silently fall back to preview success after an API error; verify the intended API configuration for deployments.
- Use the backend role values directly in the frontend sign-in flow:

  | Label | Role value |
  | --- | --- |
  | Admin | `admin` |
  | Operator | `operator` |
  | Site Manager | `site_manager` |

- Login sends the selected role unchanged as `role`, and OTP sends it unchanged as `role_name`. The authenticated role comes from JWT `roles[0]`, not the legacy `role` object. Account tenant display uses `tenant_code`; do not substitute it for backend organization identifiers.
- JWT decoding is not signature verification. Preserve backend session validation via `/v1/admin/users/me`. UI navigation is not authorization; protected handlers/actions must validate their own access.
- Access and refresh tokens remain in HttpOnly, SameSite cookies, Secure in production. Never return tokens to client JavaScript or persist tokens/passwords in browser storage. Never log credentials, OTPs, reset tokens, or raw auth responses.
- Public auth actions are `login`, `otp`, `verify`, `reset`, and `reset-password`; they do not forward an access bearer. `set-password`, `change-password`, `refresh`, and upstream `logout` require access tokens. Keep the shared endpoint policy authoritative.
- Reset completion uses the email-link token and returns to sign-in after clearing the session. Initial password setup is a separate authenticated flow. There is no registration/onboarding wizard or `/check-email` integration in current scope.
- Preserve refresh rotation, renewal deduplication, and terminal/transient failure handling. Logout must clear local cookies even when upstream logout fails. Do not disable security checks to make tests pass.
- The backend owns password policy, OTP creation/expiry, and reset-token validation. Validate local inputs and show actionable, safe errors without exposing backend internals.
- Keep live verification limits explicit. Inbox-dependent OTP/reset success and setup-required accounts need appropriate test input; do not claim those flows passed without evidence. Live tests that change credentials or send emails must be within the requested test scope.

## Styling, interaction, and accessibility

- Use centralized semantic tokens in `globals.css`: for example, `bg-primary text-primary-foreground`, sidebar tokens, chart variables, and the existing `--auth-action` token. Do not scatter tenant brand colors through components.
- Keep the current light/dark defaults, Tiar logos, Outfit typography, dimensions, border radii, shadows, and spacing. Add tokens only for an actual use; a tenant theme provider is not required yet.
- Use Tailwind consistently and `cn()` for conditional classes. Keep necessary custom CSS purposeful and centralized. Avoid scattered inline styles, duplicated long class strings, and additional styling systems without a reason.
- Customize existing shadcn/Radix primitives to match the reference. New defaults must not alter dashboard appearance. Reuse accessible dialogs, menus, selects, and sheets rather than rebuilding their behavior.
- Preserve keyboard operation, focus visibility/restoration, labels, validation messages, semantic tables, button elements, and useful chart text alternatives. Use ARIA only where needed.
- Keep simple forms and tables simple. Add React Hook Form/Zod or TanStack Table only when actual complexity justifies them. Preserve current chart types, dimensions, and interactions.
- Verify desktop, tablet, and mobile behavior for changed UI: sidebar, overflowing tables, filters, cards, forms, dialogs, and charts. Compare rendered output with the reference when practical; JSX/CSS inspection alone does not prove visual fidelity.

## Verification and cleanup

Use Node.js 22.18 or newer. Project commands are:

```bash
npm ci
npm run dev -- --port 3001
npm test
npm run lint
npm run typecheck
npm run build
```

- Add/update deterministic tests for changed behavior, including edge cases and failure paths. Current tests use Node's built-in runner and TypeScript support; do not introduce a test framework without a concrete need.
- Mock upstream transport in automated auth tests. Keep live API/inbox tests separate, avoid credentials in fixtures, and do not make automated tests depend on network availability.
- For code changes, run relevant tests, lint, typecheck, and a production build. For UI changes, also check rendered interactions and responsive states. Documentation-only changes need content/link checks; report precisely which checks ran.
- Investigate failures rather than weakening checks. `npm run typecheck` regenerates Next route types, which matters after route removal. If using a build fallback such as `--webpack`, report it explicitly.
- Remove code/assets/dependencies only after checking imports, dynamic references, route conventions, CSS variables, browser storage, and tests. Keep still-used mock features and internal primitive helpers. Do not delete tests unless obsolete; explain why.
- Keep `README.md` and `AUTHENTICATION.md` aligned with behavior changes. Preserve the generated Next.js guidance block at the top of this file.
- Before large changes, summarize the approach. Afterward, report what changed, verification results, and material limitations. Never claim live or visual verification that was not performed.
