Merge branch 'ai-folder'

This commit is contained in:
Yisroel Baum 2026-05-15 16:20:59 +03:00
commit e5a9262db6
Signed by: yisroelbaum
GPG key ID: 0FA60884F75520A9
3 changed files with 257 additions and 0 deletions

65
ai/backend-context.md Normal file
View file

@ -0,0 +1,65 @@
# Backend context
> Read `ai/shared.md` first. This file only covers backend-specific rules.
## Project Context
**Stack:** PHP 8.x, Slim 4, PHP-DI/Slim-Bridge, PHPUnit (dev), Composer.
Persistence: PostgreSQL.
**Architecture:** Domain-Driven Design. Code is organized by domain entity
under `backend/app/` (PSR-4 `App\\`) into Entities, DTOs, Repositories,
Use Cases, and Fakes (in-memory repos for tests). The entity list is
intentionally omitted here - update this section as entities land.
## Code patterns
- Look at similar entities for reference before writing anything new
- Entities: constructor with properties, getters
- DTOs: simple data containers for creation (e.g. `CreateSetDto`)
- Repositories: interfaces that define data access
- Do not write unit tests for concrete repository implementations
(e.g. `Postgres*Repository`). They are exercised by e2e tests.
Use cases are tested with fake repositories.
- Use cases: business logic with Request objects
- When throwing exceptions, add `@throws` docblock
- Fakes: in-memory implementations for testing
- Live under `tests/Fakes/`
- Find/lookup methods must return a new instance of the entity, not
the stored reference
- Tests: follow `tests/Unit/[Entity]/UseCases/` layout
- In `setUp`, only use fake repositories for entities under test -
construct dependency objects directly with `new` (e.g.
`new Set(...)`) instead of creating them through their fake
repositories
## PHP rules
- Imports: always put `use` statements at the top of the file, never use
inline imports (e.g. `\App\Foo\Bar::class`)
- Closures: never use arrow functions (`fn () =>`) - always use regular
anonymous functions (`function () { return ...; }`)
## Pre-commit
Run `phpcs` on worked-on directories before committing (phpcs ruleset
to be added to the repo; the Nix flake already provides
`php-codesniffer`). Run `./vendor/bin/phpunit tests` and confirm green.
## LLM anti-patterns
Constructs LLMs default to that this project forbids. Name the trap
explicitly so you catch yourself before writing it.
| Anti-pattern | Forbidden | Required |
|---|---|---|
| Arrow function | `fn ($x) => $x->getId()` | `function ($x) { return $x->getId(); }` |
| Inline FQCN type | `function f(): \Psr\Http\Message\ResponseInterface` | `use Psr\Http\Message\ResponseInterface;` then `function f(): ResponseInterface` |
| Inline `::class` | `Container::get(\App\Foo\Bar::class)` | `use App\Foo\Bar;` then `Container::get(Bar::class)` |
| Default param | `function f(int $count = 10)` | `function f(int $count)` |
| Default in fake | `public function create(Dto $dto, bool $strict = true)` | no default; every caller passes a value |
| Lookup returns stored ref | `return $this->items[$id] ?? null;` | rebuild a new instance with the stored fields |
| Short variable name | `$t`, `$n`, `$res`, `$req`, `$e` | `$text`, `$node`, `$response`, `$request`, `$exception` |
| Em dash | `// fetches user — by email` | `// fetches user - by email` |
When generating code, scan the diff for these patterns before writing it
to disk. If you catch one mid-write, rewrite that line.

70
ai/frontend-context.md Normal file
View file

@ -0,0 +1,70 @@
# Frontend context
> Read `ai/shared.md` first. This file only covers frontend-specific rules.
## Project Context
**Stack:** Vue 3 (beta) + Vite + TypeScript + Pinia + vue-router. Tooling:
oxlint, oxfmt, eslint. Cypress 15 for E2E (provided by the Nix devshell;
project-level config still to be wired up - see Testing below).
**Entry point:** `frontend/rabbi_gerzi/src/main.ts`; root component
`src/App.vue`; routes in `src/router/`; stores in `src/stores/`.
All frontend paths below are relative to `frontend/rabbi_gerzi/`.
## Code patterns
- Look at existing files for reference before writing anything
- **Components:** SFC `.vue` files using `<script setup lang="ts">` and
`<style scoped>`
- **Stores:** Pinia, one per domain area, under `src/stores/`
- **Routes:** declared in `src/router/index.ts`
- **Imports:** keep at the top of the file
- **Variable names:** explicit, descriptive (e.g. `element` not `el`)
- **Line width:** 80 columns, same as PHP
## Testing
- Cypress E2E only, at `frontend/rabbi_gerzi/cypress/e2e/*.cy.ts`
- Cypress is available via the Nix devshell; project-level config
(`cypress.config.ts`, `cypress/` folder) still needs to be wired up.
Add it when the first E2E test lands and remove this note.
- Tests must exercise the UI - drive via `cy.visit` / `cy.get`. Do not
use `cy.request` to set up state or assert; if seeding is needed, add
it via backend seed data.
- Role matching: log in as the role appropriate to the page under test
(e.g. admin spec uses admin login, user spec uses user login).
## Pre-commit
Run from `frontend/rabbi_gerzi/`:
- `npm run format` (oxfmt)
- `npm run lint` (oxlint + eslint)
- `npm run type-check` (vue-tsc)
All three must pass before committing.
## Note on commit granularity
A new view is often a `.vue` SFC plus a Pinia store plus a route entry -
commit them together as a single logical unit, per the "one logical
change per commit" rule in `shared.md`.
## LLM anti-patterns
Constructs LLMs default to that this project forbids on the frontend.
| Anti-pattern | Forbidden | Required |
|---|---|---|
| Short variable name | `t`, `n`, `res`, `req`, `e`, `el`, `ev` | `text`, `node`, `response`, `request`, `submitEvent`, `element`, `clickEvent` |
| Em dash in code/comments | `// loads sets — owner only` | `// loads sets - owner only` |
| Options API | `export default { data() { ... } }` | `<script setup lang="ts">` with composition API |
| `any` type | `const value: any = ...` | concrete type, or `unknown` with a narrowing guard |
| Default parameter value | `function load(limit: number = 10)` | `function load(limit: number)` - every call site passes it |
| Unscoped styles | `<style>` (leaks globally) | `<style scoped>` |
| `cy.request` in E2E | `cy.request('/api/...')` to set up state | drive via UI; seed via backend |
| Cypress login role mismatch | logging in as wrong role for the page | match the role to the page under test |
When generating code, scan the diff for these patterns before writing it
to disk.

122
ai/shared.md Normal file
View file

@ -0,0 +1,122 @@
# Shared rules
Rules that apply to both backend and frontend work in this repo. Stack-specific
guides (`backend-context.md`, `frontend-context.md`) extend these.
## Process (TDD)
0. Before editing any file, ensure you are on a feature branch
(`git status` to confirm). If on master/main, create a branch
first.
1. Write the test first
2. Run the test to confirm it fails
3. Commit the failing test (the "tests committed first" rule in
action - the test commit precedes the implementation commit, not
merely the implementation lines)
4. Implement the code to make the test pass
5. Run the test to confirm it passes
6. Commit the implementation
7. Repeat for each new behavior
## Code style
- Lines should not exceed 80 columns, but should use up to 80 columns when
possible - do not split lines unnecessarily. Applies to PHP, TypeScript,
and Vue SFCs.
- Variable names: use explicit, descriptive names - never single-letter or
abbreviated variables (e.g. `$text` not `$t`, `node` not `n`)
- Method/function/constructor parameters: do not use default values - every
call site must pass every argument explicitly. This eliminates a class of
bugs where an unintended default silently slips through (e.g. an
`isAdmin=false` or an empty `passwordHash`). Apply the same rule in tests
and fakes - if a helper accepts a value, every caller must supply it.
- First, explore the codebase to understand existing patterns - look at similar
files for reference before writing anything
- Never use em dashes (—) in code, comments, or docblocks - use hyphens (-)
instead
## Git commit style
- Present tense, imperative mood (add, create, wire, fix, test)
- Lowercase
- Short (3-6 words)
- Match patterns found in git history
- Do not add any section mentioning claude as a coauthor
- Add a commit body when the subject alone cannot convey the change - e.g.
non-obvious motivation, multi-file coordination, or notable complexity
- Body: wrap at ~72 columns, separated from subject by a blank line, explain
the why and any non-obvious what
- Skip the body for trivial or self-explanatory commits
## Git commits
- Tests should be committed first, before implementation
- One logical change per commit - a commit may span multiple files when they
form a single logical unit (e.g. a use case with its request and exception,
or a Vue SFC with its Pinia store and route entry)
- Keep commits focused: not one file per commit, not unrelated work batched
- Make commits frequent - commit each meaningful logical step as you go
- Commits are for reviewing and documenting the development of code
- When the formatter or linter modifies files outside your intended
change, either `git restore` them or land them as a separate
`format <area>` / `lint <area>` commit - never bundle drive-by
formatter churn into a feature commit
- If pre-commit lint fails on code you did not touch, do not bundle
the fix - either land the unrelated fix as its own commit first, or
note the pre-existing failure and proceed
## Branching
- Use kebab-case (e.g. `set-page`, `element-tree`, `media-upload`)
- Use descriptive feature names
- Or use type/description: `feature/set-page`, `fix/bug-name`
- NEVER work directly on master/main - always create and work on a branch
Do not push anything. Make commits as you go.
## Pre-commit checklist
Before EVERY commit (no exceptions), verify each item. Treat this as
mechanical, not aspirational - a "yes" to all is required.
**Branch + scope:**
- [ ] On a feature branch (not master/main).
- [ ] This commit is one logical change. If it spans unrelated changes,
stop and split it.
- [ ] Tests for new behavior were committed BEFORE this implementation
(or this commit IS the failing-test commit).
**Code rules** (see `backend-context.md` PHP rules,
`frontend-context.md` Vue/TS rules):
- [ ] No arrow functions in PHP (`fn () =>`).
- [ ] No inline FQCNs in type hints, return types, or `::class`
references (`\App\Foo\Bar` -> hoist to `use App\Foo\Bar;`).
- [ ] No default parameter values on methods/functions/constructors
(PHP or TS).
- [ ] Find/lookup repository methods return new instances, not stored
references.
- [ ] No em dashes (use hyphens).
- [ ] Variable names are explicit (no `$t`, `n`, `res`, `req`, `e`, etc.).
- [ ] No `any` in TypeScript - use concrete types or `unknown` with a
narrowing guard.
- [ ] Vue SFCs use `<script setup lang="ts">` and `<style scoped>`.
**Mechanical checks (backend, when PHP changed):**
- [ ] `phpcs <touched dirs>` reports clean (config to be added; flake
provides `php-codesniffer`).
- [ ] `./vendor/bin/phpunit tests` is green.
**Mechanical checks (frontend, when frontend changed; run from
`frontend/rabbi_gerzi/`):**
- [ ] `npm run format` (oxfmt) reports clean (or any fixes are
committed).
- [ ] `npm run lint` (oxlint + eslint) passes.
- [ ] `npm run type-check` (vue-tsc) passes.
**Commit metadata:**
- [ ] Subject is lowercase, imperative, 3-6 words.
- [ ] No claude/AI coauthor lines.
- [ ] Body present iff the subject alone cannot convey the change.
If any item fails, fix it before committing - do not bundle the fix
into a future commit.