align ai workflow rules
This commit is contained in:
parent
4241f5ba29
commit
efb932903b
3 changed files with 205 additions and 220 deletions
|
|
@ -4,7 +4,8 @@ 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, npm.
|
||||
**Stack:** Vue 3.5, TypeScript 6, Vite 8, Vue Router 5, Pinia 4, Zod 4,
|
||||
Cypress 15, npm.
|
||||
|
||||
**Location:** `frontend/website/`.
|
||||
|
||||
|
|
@ -12,18 +13,16 @@ 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 scaffold uses:
|
||||
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` as the root component.
|
||||
- `src/main.ts` to create the app and install the router and Pinia.
|
||||
- `src/router/index.ts` for routes.
|
||||
- `src/stores/` for Pinia stores.
|
||||
- `@` as an alias for `src/` in both Vite and TypeScript.
|
||||
|
||||
There are no views, shared components, API layer, or configured test suite
|
||||
yet. Cypress is installed as a frontend development dependency, but there is
|
||||
no Cypress configuration or npm test script. Do not invent an architecture
|
||||
before requested behavior establishes one.
|
||||
- `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
|
||||
|
||||
|
|
@ -36,32 +35,14 @@ Install dependencies in a fresh checkout or worktree:
|
|||
direnv exec "$(git rev-parse --show-toplevel)" npm install
|
||||
```
|
||||
|
||||
To start only the development server on the port assigned by the shell hook:
|
||||
`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.
|
||||
|
||||
```sh
|
||||
direnv exec "$(git rev-parse --show-toplevel)" \
|
||||
npm run dev -- \
|
||||
--host 127.0.0.1 \
|
||||
--port "$VITE_PORT" \
|
||||
--strictPort
|
||||
```
|
||||
|
||||
`process-compose` starts the frontend as part of the full development stack.
|
||||
The frontend remains directly accessible on `VITE_PORT`; Caddy does not proxy
|
||||
it.
|
||||
|
||||
The available validation commands are:
|
||||
|
||||
```sh
|
||||
direnv exec "$(git rev-parse --show-toplevel)" npm run format
|
||||
direnv exec "$(git rev-parse --show-toplevel)" npm run lint
|
||||
direnv exec "$(git rev-parse --show-toplevel)" npm run type-check
|
||||
direnv exec "$(git rev-parse --show-toplevel)" npm run build
|
||||
```
|
||||
|
||||
`npm run format` and `npm run lint` rewrite files. Review the resulting diff.
|
||||
`npm run build` runs type checking and the production build. Build output
|
||||
under `dist/` is generated and 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
|
||||
|
||||
|
|
@ -72,58 +53,69 @@ under `dist/` is generated and ignored.
|
|||
`src/router/index.ts`.
|
||||
- Keep page, component, composable, and store responsibilities distinct.
|
||||
- Prefer small components with explicit props and emitted events.
|
||||
- Keep component styles scoped until the project adopts a deliberate global
|
||||
styling system.
|
||||
- Use setup-style Pinia stores named `useXxxStore`.
|
||||
- Inspect similar files before introducing a new component, composable,
|
||||
store, or data-access pattern.
|
||||
- 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
|
||||
## TypeScript and runtime validation
|
||||
|
||||
- Preserve the strict TypeScript configuration and
|
||||
`noUncheckedIndexedAccess`.
|
||||
- Do not use `any`. Model unknown external values as `unknown`, then narrow or
|
||||
validate them.
|
||||
- Derive types from runtime schemas if the project adopts a schema library.
|
||||
Do not maintain a hand-written type that can drift from its schema.
|
||||
- Validate payloads at trust boundaries, especially backend responses and
|
||||
user-submitted forms.
|
||||
- Keep request and response types close to the API or store boundary that
|
||||
owns them.
|
||||
- Keep the `@` alias aligned across Vite, TypeScript, and any future test
|
||||
configuration.
|
||||
- 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 server requests and response transformation at an API or store
|
||||
boundary, not scattered through presentation 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 directly to an application interface.
|
||||
- Keep read and write payload types separate when their shapes differ.
|
||||
- Do not cast unchecked JSON to an application interface.
|
||||
- Send cookie-backed API requests with the established credentials behavior.
|
||||
|
||||
## Testing
|
||||
|
||||
Cypress is installed, but no frontend test configuration or test script
|
||||
exists yet.
|
||||
- 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.
|
||||
|
||||
- Do not invent test commands or claim frontend tests passed.
|
||||
- New frontend behavior must still follow the shared test-first workflow.
|
||||
Establish the smallest appropriate test setup before implementing behavior
|
||||
that needs it.
|
||||
- Unit tests should cover pure transformations, composables, and store logic.
|
||||
- Component tests should cover rendering, events, form behavior, and
|
||||
conditional UI.
|
||||
- End-to-end tests should cover routing, multi-page flows, and request wiring.
|
||||
- Prefer the cheapest layer that proves the behavior.
|
||||
- Mock backend requests in frontend tests. Do not retest backend persistence,
|
||||
validation, authentication, or mail behavior through the frontend.
|
||||
## Frontend workflow
|
||||
|
||||
## Before completing frontend work
|
||||
|
||||
- Run the focused test while developing once test tooling exists.
|
||||
- Run the formatter, linter, type checker, production build, and every
|
||||
configured test script affected by the change.
|
||||
- Do not claim a green gate when a command fails. Report a baseline or
|
||||
environmental failure precisely.
|
||||
- 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.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue