Skip to content

Commit 9a4bc8a

Browse files
authored
Merge pull request #606 from Perdolique/update-packages
Add catalog navigation and update dev tools
2 parents 1354e49 + 643c107 commit 9a4bc8a

38 files changed

Lines changed: 1652 additions & 1212 deletions
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
---
2+
name: equipment-backend
3+
description: Equipment and catalog backend conventions for the Perd project. Use this skill whenever the task touches `server/api`, `server/utils/validation`, `server/database/schema.ts`, Drizzle write paths, equipment reference data, contributions logging, or equipment API tests, even if the user does not explicitly mention the backend skill.
4+
---
5+
6+
# Equipment Backend Conventions
7+
8+
Use this skill for equipment and catalog backend work. Keep the implementation narrow, predictable, and shaped by current product needs instead of speculative abstractions.
9+
10+
## Scope
11+
12+
Apply these rules when working on:
13+
14+
- `server/api/equipment/**`
15+
- `server/utils/validation/**`
16+
- `server/database/schema.ts`
17+
- Drizzle queries and write paths that touch equipment catalog data
18+
- Equipment-related Vitest API handler tests
19+
20+
Do not use this skill for generic Vue or styling work. Use the dedicated frontend skill for `.vue` files.
21+
22+
## Data model expectations
23+
24+
- Keep the EAV model intact: `category_properties` defines available properties, `item_property_values` stores actual item values.
25+
- Keep groups and categories independent. Do not add a foreign key between them unless the product plan explicitly changes.
26+
- Treat items as flat catalog rows. Size and similar distinctions belong in properties, not a variant system.
27+
- Keep UUID v7 for user-facing entities and serial IDs for reference data.
28+
- Keep reference-data slugs canonical and lowercase.
29+
- Keep `equipment_items` foreign keys to brand/category non-cascading with `restrict`.
30+
- Keep all schema sections in `server/database/schema.ts`.
31+
32+
## Route and validation conventions
33+
34+
- Public read routes for reference data use `slug` in route params.
35+
- Admin mutation routes for reference data use stable `id` params because `slug` is editable content.
36+
- Category-property admin routes stay nested under category ID routes so handlers can verify parent ownership from the route chain.
37+
- Validate every request input through the shared Valibot helpers:
38+
- `readValidatedBody` for request bodies
39+
- `getValidatedRouterParams` for route params
40+
- `getValidatedQuery` for query strings
41+
- Keep schemas and validator helpers in `server/utils/validation/schemas.ts`. Handlers should consume parsed values, not manually re-validate raw input.
42+
43+
## Write-path and query-shape rules
44+
45+
- Any admin catalog write that both mutates reference data and logs `contributions` must be atomic. Use a transaction-capable write path rather than separate `dbHttp` calls.
46+
- `contributions.targetId` stores the changed entity primary key as a string so it can hold either serial IDs or UUIDs.
47+
- Public detail endpoints stay narrow. Return the entity needed for that route and fetch related collections with separate endpoints only when there is a concrete consumer.
48+
- For shared `returning(...)` fragments, prefer small server-only base-record helpers over global endpoint models.
49+
- When only one row is needed once, destructure directly from the awaited query result: `const [row] = await ...`.
50+
- If deleting an enum option would orphan existing enum item values, return `409`.
51+
- Protected `/api/*` routes keep mixed unauthenticated behavior: browser navigations redirect to login, programmatic requests still receive `401`.
52+
53+
## Testing expectations
54+
55+
- Cover API handlers in Vitest with mocks for `event`, `dbHttp`, auth helpers, and validated-input helpers as needed.
56+
- Do not rely on seeded database state or fixed catalog row counts in required tests.
57+
- Keep browser-level coverage in Playwright as smoke coverage, not the primary API contract layer.
58+
- Put shared test helpers in the repo root, such as `test-utils/`, instead of runtime source trees.
59+
- Prefer `vi.mock(import(...))` so mocks stay aligned with the project lint rules.
60+
- Avoid file-level lint disables in tests unless there is a documented tool mismatch and no cleaner local fix.
61+
62+
## Skill maintenance
63+
64+
If this skill starts to sprawl, move detailed reference material into `references/` files instead of bloating this `SKILL.md`.
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
---
2+
name: planning-docs
3+
description: Planning and documentation conventions for the Perd project. Use this skill whenever the task touches files in `plan/`, roadmap structure, completed-work notes, architecture documentation, or asks to split work into implementation iterations, even if the user does not explicitly mention planning.
4+
---
5+
6+
# Planning And Documentation Conventions
7+
8+
Use this skill for roadmap maintenance and planning docs. The goal is to keep the plan tree small, current, and implementation-oriented instead of turning it into a vague backlog dump.
9+
10+
## Scope
11+
12+
Apply these rules when working on:
13+
14+
- `plan/**`
15+
- roadmap summaries and task decomposition
16+
- completed-work summaries
17+
- architecture notes that change how future work should be implemented
18+
19+
Do not use this skill for backend endpoint code unless the task also changes roadmap or documentation artifacts.
20+
21+
## Roadmap model
22+
23+
- Treat `plan/` as the global product roadmap, not a sprint board or personal todo list.
24+
- Keep `plan/PLAN.md` short and use it as an index to detailed plan files.
25+
- Large efforts should be split into sequential iteration files when that helps implementation stay concrete.
26+
- Move completed work summaries to `plan/completed.md` instead of leaving stale execution detail inside roadmap specs.
27+
28+
## Iteration design
29+
30+
- Prefer the smallest completed iteration that removes one blocker or delivers one coherent slice.
31+
- Do not add speculative implementation detail, abstractions, or future phases that the current iteration does not need.
32+
- For new API iterations, every join must be justified by a returned field or an applied filter in that iteration.
33+
- Do not add extra detail endpoints or broader detail payloads unless the current iteration already has a concrete consumer.
34+
- Treat response examples in plan files as the upper bound for that iteration's payload. Do not silently extend them.
35+
36+
## Update rules
37+
38+
- When roadmap files are renamed or moved, update links in `plan/PLAN.md` and any overview files immediately.
39+
- If a task changes architecture, route conventions, data-model expectations, or test strategy, update the relevant planning or documentation files in the same change.
40+
- Keep completed notes short and factual. Save detailed implementation guidance for the active roadmap files that still matter.
41+
42+
## Writing style
43+
44+
- Write plans so another engineer can implement them without guessing the intended slice.
45+
- Prefer concrete behavior and current constraints over generic platform-speak.
46+
- Remove stale guidance instead of appending contradictory notes on top of it.

.agents/skills/vue-components/SKILL.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ description: Vue component conventions and patterns for the Perd project. Use wh
99

1010
Use the standard order: `<template>`, `<script>`, `<style>`.
1111

12+
If a UI has a small, fixed number of known elements and all labels, props, and targets are already known, write those elements directly in the template. Do not introduce arrays, `v-for`, config objects, or extra computed state just to make static markup look generic. Use config-driven rendering only when the structure is genuinely dynamic or repeated enough to justify abstraction.
13+
1214
Type exports that other components need go in a separate non-setup script block above the setup block:
1315

1416
```vue
@@ -121,6 +123,17 @@ useEventListener(dialogRef, 'close', () => {
121123
document.addEventListener('pointerdown', handler)
122124
```
123125

126+
## Accessibility
127+
128+
All UI must be accessible and meet at least **WCAG 2.1 AA**. Treat this as a project requirement, not a nice-to-have.
129+
130+
- Prefer semantic HTML over `div` / `span` plus manual `role` attributes when a native element already provides the correct behavior.
131+
- All interactive elements must be keyboard accessible and have a visible focus state.
132+
- Icon-only buttons, form inputs, and custom controls must have an accessible name via `aria-label`, `aria-labelledby`, or an associated `label`.
133+
- Decorative elements should be hidden from assistive technology with `aria-hidden="true"`. Informative images must have a meaningful `alt`.
134+
- Do not rely on color alone to communicate meaning, state, or validation errors.
135+
- If a custom control is necessary, it must match the native equivalent's keyboard, focus, and ARIA behavior.
136+
124137
## Styling
125138

126139
### CSS Modules Only
@@ -176,6 +189,14 @@ The project targets modern browsers only. Use these freely:
176189
- **`@layer`** for CSS organization (reset, colors, spacings, sizes, transitions, typography)
177190
- **CSS custom properties** for all design tokens (`--spacing-*`, `--color-*`, `--font-size-*`, etc.)
178191

192+
Prefer native CSS features that are already part of the supported browser baseline over legacy compatibility workarounds.
193+
194+
### Responsive Rules
195+
196+
Use `@container` for component-level responsive layout changes that should react to the space actually available inside the component.
197+
198+
Keep `@media` for viewport- and environment-level behavior such as app shell breakpoints, fullscreen page treatments, overlays, and user preference queries like `prefers-color-scheme`.
199+
179200
### Media Queries
180201

181202
Use the modern range syntax:

AGENTS.md

Lines changed: 27 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -6,86 +6,40 @@
66
- Drizzle ORM
77
- Neon PostgreSQL
88

9-
## Equipment architecture
9+
## Core project invariants
1010

11-
### Data model
11+
- Equipment properties use an EAV model: `category_properties` defines available fields, `item_property_values` stores per-item values.
12+
- Groups and categories are separate reference entities with no FK between them. Do not invent one unless the product plan explicitly changes.
13+
- Items are flat. Size and similar distinctions are category properties, not a variant subsystem.
14+
- User-facing catalog entities use UUID v7 where the product already depends on stable public IDs. Reference data uses serial IDs.
15+
- Reference-data slugs are canonical lowercase URL tokens using only `a-z`, `0-9`, and single hyphens.
16+
- Reference-data `name` values stay English display strings. Slugs are the durable keys for URLs and future i18n lookups.
17+
- `equipment_items` brand/category foreign keys must stay non-cascading (`restrict`), so deleting reference data cannot silently remove catalog or inventory records.
18+
- Public reference-data read routes use `slug`; admin mutations use stable `id` params.
19+
- All tables live in `server/database/schema.ts`, organized by Auth, Equipment catalog, and User data sections.
1220

13-
- **EAV (Entity-Attribute-Value)** for item properties: `category_properties` defines what properties a category has, `item_property_values` stores actual values per item. This enables dynamic filters and item comparison without schema migrations.
14-
- **Two-level categorization**: Groups (functional area: Sleep, Shelter, Cooking) and Categories (specific type: Sleeping Bags, Sleeping Pads) are independent entities with no FK relationship. Connection can be added later when navigation patterns become clear.
15-
- **Items are flat** — each size/variant is a separate item. Size is a category property, not a separate variant system.
21+
## Local skills
1622

17-
### Database conventions
23+
Before any task, check whether a local skill matches the domain and follow it.
1824

19-
- **UUID v7** as PK for all user-facing entities (items, user_equipment, contributions).
20-
- **Serial** PK for reference data (groups, categories, properties, brands).
21-
- **Slugs** on reference data only (groups, categories, brands) — used for URLs and as future i18n translation keys. Items use UUID in URLs.
22-
- **Reference data slugs are canonical lowercase URL tokens** using only `a-z`, `0-9`, and single hyphens between segments.
23-
- **`name`** columns on reference data are English display values. When i18n is added, `slug` maps to a translation key, `name` becomes the fallback.
24-
- **Brand/category FKs from `equipment_items` must not cascade on delete**: use `restrict` so deleting reference data cannot silently remove catalog items, item property values, or user inventories.
25+
- `vue-components` for `.vue` component structure, styling, props/emits, and SSR-safe frontend patterns.
26+
- `equipment-backend` for equipment/catalog backend work in `server/api`, validation schemas, Drizzle write paths, schema changes, and equipment API tests.
27+
- `planning-docs` for roadmap files in `plan/`, completed work notes, architecture docs, and iteration planning tasks.
2528

26-
### API conventions
29+
## Workflow rules
2730

28-
- **Public read routes for reference data use `slug`** in detail URLs (`/api/equipment/brands/[slug]`, `/api/equipment/categories/[slug]`).
29-
- **Admin mutation routes for reference data use `id`** in route params (`PATCH`/`DELETE`), because `slug` is editable content and must not be the stable mutation key.
30-
- **Admin category property mutations stay nested under category `id` routes** (`/api/equipment/categories/[categoryId]/properties/...`) so parent ownership is explicit and property/enum-option handlers can verify the full route chain.
31-
- **All API request inputs use Valibot schemas through h3 validated helpers**: `readValidatedBody` for request bodies, `getValidatedRouterParams` for route params, and `getValidatedQuery` for query strings. Schemas and validator functions live in `server/utils/validation/schemas.ts`; handlers should consume parsed values instead of manually validating raw input.
32-
- **Catalog admin writes that both mutate reference data and log `contributions` must be atomic**: run them through a transaction-capable write path, not separate `dbHttp` calls.
33-
- **Single-result query arrays should be destructured directly from the awaited query** when only the first row is needed once (`const [row] = await ...`); keep an intermediate array only when the full result set, row count, or repeated reuse matters.
34-
- **Public read detail endpoints stay narrow**: return the entity needed for that route, and fetch related collections with separate read endpoints when a page needs them. Do not expand detail payloads just to save a future frontend request.
35-
- **Shared catalog `returning(...)` shapes use reusable base records, not global endpoint models**: extract common `id`/`name`/`slug` selections into server-only helpers when reused, but keep each endpoint free to return a different response shape later if needed.
36-
- **Deleting an enum option that is already used by existing item property values must return `409`**: enum item values are currently stored by slug text, so option deletes need an application-level guard against orphaned enum values.
37-
- **Protected `/api/*` routes keep mixed auth behavior by caller type**: unauthenticated browser document navigations redirect to `/login?redirectTo=...`, while programmatic API requests (`fetch`/XHR) still receive `401`.
31+
- Files imported by standalone Node or `tsx` scripts, including `tools/*.ts`, migrations, seeds, and their transitive dependencies, must not rely on Nuxt-only aliases like `~/` or `@@/`. If they use `#shared/*` or `#server/*`, keep those aliases backed by `package.json#imports`.
32+
- After any architecture, route-convention, data-model, or test-strategy change, update the relevant docs in the same change. This can include `AGENTS.md`, `plan/PLAN.md`, `plan/completed.md`, or the detailed roadmap file that changed.
3833

39-
### Testing conventions
34+
## Verification matrix
4035

41-
- **API handlers are tested in Vitest with mocks** for `event`, `dbHttp`, and auth/body helpers. Required API coverage must not depend on shared database state.
42-
- **Playwright is reserved for browser/UI smoke** and must not be the primary layer for API contract coverage.
43-
- **Deterministic tests over seeded assumptions**: avoid checks that depend on fixed counts or specific catalog rows in a real database.
44-
- **Shared test helpers live at the repo root** (for example `test-utils/`), not inside `server/` or `app/`, so runtime source trees stay free of test-only utilities. Import them through root aliases like `~~/` or `@@/`, not deep relative paths.
45-
- **Avoid file-level lint disables in tests** when a clean test helper, typed wrapper, or test-specific lint override can solve the problem. Use inline/file disables only as a last resort for a documented tool mismatch.
46-
- **Prefer `vi.mock(import(...))` in Vitest** so test mocks stay aligned with the project skill and `vitest/prefer-import-in-mock`. If a test needs leniency, prefer narrow `oxlint` test overrides like `max-lines` or `import/no-relative-parent-imports`, not disabling mock-style rules.
36+
After any code modification, run the checks that match the files you touched.
4737

48-
### Content management
38+
- If Markdown files changed: `pnpm run lint:markdown`
39+
- If TypeScript or Vue code changed: `pnpm run test:typecheck`
40+
- If TypeScript or Vue code changed: `pnpm run test:unit:agent`
41+
- If TypeScript or Vue code changed: `pnpm run lint:oxlint`
42+
- If TypeScript or Vue code changed: `pnpm run build`
43+
- If TypeScript or Vue code changed: `pnpm run test:e2e:ci`
4944

50-
- **Contributions table** logs every write operation (create/update/delete) with userId, action, targetId, and optional metadata. `targetId` stores the changed entity's primary key as a string, so it can hold either a serial ID or a UUID. Used for future gamification.
51-
- **Item status**: `approved` by default for admin-created items. Future user submissions will default to `pending`.
52-
- MVP: only admins can manage the equipment catalog. Users browse and add items to their inventory.
53-
54-
### Schema file
55-
56-
All tables live in a single `server/database/schema.ts` file, organized by sections: Auth, Equipment catalog, User data.
57-
58-
## Workflow
59-
60-
Before performing any task, action, or code modification, event small one, check if there are existing skills that cover the domain of your task and follow their instructions.
61-
62-
- Files imported by standalone Node/`tsx` scripts (for example migration, seed, and other `tools/*.ts` entry points, plus their transitive dependencies) must not rely on Nuxt-only aliases like `~/` or `@@/`. If such files use `#shared/*` or `#server/*`, keep those aliases backed by `package.json#imports`, because plain script execution does not get Nuxt alias resolution automatically.
63-
64-
After any code modification, always run:
65-
66-
- If Markdown files are modified:
67-
- `pnpm run lint:markdown` for markdown linting
68-
- If TypeScript or Vue code is modified:
69-
- `pnpm run test:typecheck` - to ensure type safety
70-
- `pnpm run test:unit:agent` for unit tests
71-
- `pnpm run lint:oxlint` for linting
72-
- `pnpm run build` to ensure the project builds successfully
73-
- `pnpm run test:e2e:ci` for E2E tests (auto-starts dev server)
74-
75-
All tasks above can be run in parallel.
76-
77-
If any architectural decisions were made during the task (new patterns, conventions, data model changes), update relevant sections of this file. Remove or revise entries that are no longer accurate.
78-
If a task changes architecture, route conventions, or test strategy, update `AGENTS.md` and relevant roadmap/completed docs in the same change automatically.
79-
80-
## Planning conventions
81-
82-
The `plan/` directory is the **global product roadmap**, not a per-sprint task list. It describes the full scope of planned product features and their implementation order.
83-
84-
- Prefer the **smallest possible completed iteration** that removes one blocker or delivers one coherent slice. Smaller iterations reduce implementation mistakes and make progress easier to verify.
85-
- For new API iterations, every join must be justified by a field returned in the current response or by a filter applied in the current endpoint. Do not preload relations "just in case".
86-
- Do not add extra detail payload or extra detail endpoints unless the current iteration already has a concrete consumer for them.
87-
- Response examples in plan files are the **upper bound** for payload in that iteration. Do not silently extend them without updating the plan and the consumer need.
88-
- `plan/PLAN.md` is the roadmap index — keep it short, link to detailed plan files.
89-
- Large iterations must be split into sequential task files (e.g. `plan/admin-management/01-foundations.md`).
90-
- Completed work goes to `plan/completed.md` as short summaries, not detailed specs.
91-
- When plan files are renamed or moved, update links in `plan/PLAN.md` and overview files immediately.
45+
All applicable commands may be run in parallel.

0 commit comments

Comments
 (0)