128 lines
5.8 KiB
Markdown
128 lines
5.8 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.
|
|
- Display user-authored set level kinds verbatim. Do not capitalize, replace
|
|
separators, pluralize, or apply `text-transform` to a kind value; pluralize
|
|
surrounding interface words such as "assignment" instead.
|
|
- 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`.
|
|
- Every Cypress spec must appear in exactly one `frontend_specs_*` group in
|
|
the root `justfile`. The completion gate runs those groups concurrently,
|
|
and its `cypress-spec-coverage` job rejects ungrouped, duplicate, or missing
|
|
specs. Keep `frontend-cypress-run` for whole-suite iteration.
|
|
- 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.
|