Attainly/ai/frontend-context.md

121 lines
5.3 KiB
Markdown

# Frontend context
Read `ai/shared.md` first. This file covers frontend-specific rules.
## Project context
**Stack:** Vue 3.5, TypeScript 6, Vite 8, Vue Router 5, Pinia 4, Zod 4,
Cypress 15, npm.
**Location:** `frontend/website/`.
The frontend is a standalone application. Keep its source, dependencies,
development server, and production build independent from the backend unless
the user explicitly requests integration.
The application currently has route-level views, reusable authentication
components, a Pinia authentication store, Zod schemas, API URL handling, and
Cypress end-to-end specs. The main entry points are:
- `src/App.vue` for the root component.
- `src/main.ts` for app creation, Pinia, the router, and global styles.
- `src/router/index.ts` for routes and authentication guards.
- `src/stores/` for Pinia stores and API boundaries.
- `src/views/` and `src/components/` for route and reusable UI.
- `@` as the `src/` alias in Vite and TypeScript.
## Package management and commands
Use npm and keep `package-lock.json` committed. Run commands from
`frontend/website/`.
Install dependencies in a fresh checkout or worktree:
```sh
direnv exec "$(git rev-parse --show-toplevel)" npm install
```
`npm run format` and `npm run lint` rewrite files. Their `format:check` and
`lint:check` counterparts are non-mutating completion checks. `npm run build`
runs type checking and the production build; generated `dist/` output is
ignored.
`process-compose` starts the frontend as part of the complete development
stack. The frontend is directly accessible on `VITE_PORT`; Caddy serves the
backend and does not proxy the frontend.
## Vue conventions
- Use the Composition API and `<script setup lang="ts">`.
- Use PascalCase component and view filenames.
- Put reusable components under `src/components/`.
- Put route-level views under `src/views/` and register them in
`src/router/index.ts`.
- Keep page, component, composable, and store responsibilities distinct.
- Prefer small components with explicit props and emitted events.
- Use setup-style Pinia stores named `useXxxStore`.
- Keep application-wide resets and base styles in `src/styles/main.css`.
Keep component and view styles scoped and match established Attainly visual
patterns.
- Inspect similar files before introducing a component, composable, store,
route, or data-access pattern.
## TypeScript and runtime validation
- Preserve strict TypeScript and `noUncheckedIndexedAccess`.
- Do not use `any`. Model unknown external values as `unknown`, then parse or
narrow them.
- Zod schemas are the source of truth for runtime payloads. Define a schema
and derive its TypeScript type with `z.infer` instead of maintaining a
parallel hand-written interface.
- Parse every backend response at the store or API boundary before placing it
in application state.
- Keep read and write schemas separate when their shapes differ.
- Validate user-submitted forms with a Zod object schema when the form has
meaningful validation rules. Surface field errors from the schema rather
than maintaining parallel regular expressions and error logic.
- Keep request and response schemas and types near the API or store boundary
that owns them.
- Keep the `@` alias aligned across Vite, TypeScript, and future test tooling.
## State and API access
- Use Pinia for shared client state. Keep component-local state in components.
- Keep requests, response parsing, and response transformation at an API or
store boundary, not in presentation components.
- Represent loading, empty, success, validation-error, and unexpected-error
states explicitly.
- Do not cast unchecked JSON to an application interface.
- Send cookie-backed API requests with the established credentials behavior.
## Testing
- Cypress is configured under `cypress/` and runs through `npm run test:e2e`
or `just frontend-cypress-run`.
- Prefer the cheapest test seam that proves the behavior. Cypress covers
routing, browser forms, authentication flows, request wiring, and responsive
behavior.
- Mock backend calls in frontend-focused Cypress tests. Use the worktree
backend only for a deliberately end-to-end integration scenario.
- Assert both the request contract and the rendered response behavior when a
spec intercepts an API call.
- Keep mock payloads synchronized with exported store types and Zod schemas.
Add typed builders when payloads repeat across specs, and parse builder
output through the exported schema when practical.
- Authentication requests are mockable like every other frontend boundary.
Backend persistence, cookie creation, middleware, and mail behavior belong
in PHPUnit tests.
- No Vitest unit or component suite is configured. Do not claim that coverage.
If new pure logic or component behavior cannot be proved economically with
Cypress, establish the smallest appropriate Vitest setup test-first.
## Frontend workflow
- Run the focused Cypress spec while developing when browser behavior changes.
- Run `npm run format` and `npm run lint` before committing frontend changes,
then review every rewrite.
- Use the focused `just frontend-*` recipes for development feedback.
- The shared `just test-all` command is the required completion gate. Focused
frontend checks never replace it.
- Do not claim a green gate when a command fails. Report baseline or
environmental failures precisely.