add project ai instructions

Document Attainly-specific TDD, worktree, Laravel, database, and future Vue conventions adapted from the youngstartup workflow.
This commit is contained in:
Yisroel Baum 2026-07-30 22:54:39 +03:00
parent 83ca2cf43c
commit a225433cec
Signed by: yisroelbaum
GPG key ID: 0FA60884F75520A9
4 changed files with 379 additions and 0 deletions

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

@ -0,0 +1,105 @@
# Backend context
Read `ai/shared.md` first. This file covers backend-specific rules.
## Project context
**Stack:** PHP 8.4, Laravel 13, Inertia Laravel, PHPUnit, Larastan, Composer.
**Location:** `backend/`.
The application is still close to the Laravel starter structure. Do not
introduce a domain architecture, repository layer, service layer, or other
abstraction before the codebase and requested behavior justify it. Match
existing Laravel conventions and inspect similar code before adding a new
pattern.
## Laravel patterns
- Keep controllers thin. Put reusable business behavior in an appropriately
named application or domain class once the behavior warrants extraction.
- Use dedicated request validation rather than validating substantial payloads
inline in controllers.
- Let unexpected exceptions reach Laravel's exception handler. Catch only
exceptions that can be handled meaningfully at the current boundary.
- Use Eloquent relationships and query scopes consistently rather than
duplicating query fragments.
- Avoid speculative interfaces and abstractions with only one trivial
implementation.
- Routes currently use Inertia, but the Vue client has not been scaffolded.
Do not add placeholder frontend assets as part of unrelated backend work.
## Tests
- Follow the existing PHPUnit organization under `tests/Unit/` and
`tests/Feature/`.
- Prefer `PHPUnit\Framework\TestCase` when a test only exercises plain PHP.
- Extend `Tests\TestCase` only when the test needs Laravel's container,
facades, database, routing, or HTTP kernel.
- HTTP feature tests extend `Tests\TestCase`.
- Use `RefreshDatabase` when a test reads or writes database state.
- Assert behavior at the appropriate seam:
- Unit tests cover isolated business behavior and edge cases.
- Feature tests cover routing, middleware, validation, persistence, and
response shape.
- Do not duplicate every business branch through the HTTP layer when unit
coverage already proves it. Feature tests should focus on wiring and the
public contract.
## Test database
- Development and runtime use PostgreSQL through the local Unix socket.
- PHPUnit intentionally uses SQLite `:memory:` as configured in
`phpunit.xml`.
- Feature tests are self-contained and do not require the process-compose
PostgreSQL service.
- Never point `RefreshDatabase` tests at the development PostgreSQL database.
- Keep mail set to the PHPUnit `array` transport unless a test explicitly
exercises a real mail integration.
## PHP rules
- Put imports at the top of the file. Do not use inline fully qualified class
names when a normal `use` statement is clearer.
- Do not use arrow functions. Use regular anonymous functions.
- Do not add default values to function or constructor parameters. Pass every
argument explicitly, including nullable arguments.
- Use descriptive names for classes, methods, parameters, and local
variables.
- Document exceptions with `@throws` when a caller is expected to handle
them.
## Seeders
- Keep `DatabaseSeeder` as the orchestrator.
- Split substantial seed data into one seeder per domain concept and invoke
them in dependency order.
- Do not add production repository or model APIs solely to make seeding
convenient.
- Use existing lookup methods for cross-seeder relationships. When a group of
records only makes sense together, keep them in one seeder and retain local
references.
## Migrations
- Attainly is not in production yet.
- While no production database exists, edit the original `create_*` migration
when changing a table instead of accumulating follow-up alter migrations.
- Keep one migration file per table during this pre-production phase.
- Rebuild the development database with:
```sh
php artisan migrate:fresh --seed
```
- Once a production database exists, replace this policy with additive,
forward-only migrations.
## Before completing backend work
- Run the focused test during development.
- Run `php artisan test` before completion.
- Run the Composer lint and static-analysis scripts when their dependencies
are available.
- Fix failures caused by the change. Report unrelated baseline failures
precisely rather than hiding them or expanding scope without authorization.

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

@ -0,0 +1,90 @@
# Frontend context
Read `ai/shared.md` first. This file covers frontend-specific rules.
## Current state
The Vue frontend has not been scaffolded yet. The backend has Inertia Laravel
installed and an Inertia route, but there is no `package.json`, Vue source
tree, Vite configuration, or frontend test setup.
- Do not create the frontend unless the user explicitly asks.
- Do not invent a frontend directory, package manager, dependency version, or
command before the scaffold establishes it.
- When the frontend is created, update this file with its actual paths,
package versions, scripts, and testing tools.
## Vue conventions
Apply these rules once a Vue 3 frontend exists:
- Use the Composition API and `<script setup lang="ts">`.
- Use PascalCase component filenames.
- Keep page, component, composable, and store responsibilities distinct.
- Prefer small components with explicit props and emitted events.
- Keep component styles scoped unless the scaffold establishes a deliberate
global styling system.
- Follow the routing and page conventions established by the chosen Inertia
or Vue Router scaffold. Do not mix the two approaches without an explicit
architectural reason.
- Inspect similar files before introducing a new component, composable, store,
or data-access pattern.
## TypeScript
- Enable and preserve strict mode.
- Do not use `any`. Model unknown external values as `unknown` and narrow or
validate them.
- Derive types from runtime schemas when a schema library is adopted. Do not
maintain a hand-written type that can drift from its validation 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.
- Add a path alias only when it is configured consistently in Vite,
TypeScript, tests, and Cypress.
## State and API access
- Use the state-management approach chosen by the scaffold consistently.
- Keep server data fetching and transformation at an API/store boundary, not
scattered through 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.
## Testing
Use layered tests once the frontend test setup exists:
- Unit tests cover pure transformations, composables, store logic, computed
values, and formatting.
- Component tests cover rendering, events, form behavior, and conditional UI.
- Cypress tests cover routing, multi-page flows, and request wiring.
- Prefer the cheapest layer that proves the behavior.
- Import test functions explicitly rather than relying on globals unless the
scaffold deliberately configures globals.
- Build test data with small typed builders instead of repeated bare object
literals.
## Frontend/backend test boundary
- Mock backend requests in frontend tests.
- A frontend test should verify how the UI consumes a response and which
request it sends, not retest Laravel's business rules.
- Test backend persistence, validation, authentication, and mail behavior in
PHPUnit.
- Keep mocked response bodies typed against the frontend's exported API or
store types.
- When runtime schemas exist, parse mock-builder output through the same
schema so drift fails at the test boundary.
## Before completing frontend work
- Run the formatter, linter, type checker, unit tests, and Cypress scripts
defined by the frontend's `package.json`.
- Do not substitute a hand-picked subset for the repository's eventual full
frontend gate.
- If the frontend cannot run because the scaffold or a required service is
absent, report the precise environmental or baseline failure.

177
ai/shared.md Normal file
View file

@ -0,0 +1,177 @@
# Shared rules
Rules that apply to both backend and frontend work in this repository.
Stack-specific guides (`backend-context.md`, `frontend-context.md`) extend
these rules.
## Project state
- Attainly is in early development.
- Attainly helps users break hierarchical goals into scheduled assignments,
complete daily work, and track progress toward a target date.
- Schedule recalculation must preserve completed work while redistributing
unfinished assignments across the remaining dates.
- Planned features in `README.md` are future ideas, not authorized scope.
- The Laravel backend exists under `backend/`.
- The Vue frontend has not been scaffolded yet. Do not create it unless the
user explicitly asks for that work.
- PostgreSQL is the development and runtime database.
- PHPUnit uses in-memory SQLite for isolated tests.
## Process (TDD)
0. Before editing any file, ensure you are working in a dedicated git
worktree, not the main checkout (`git status` and `git worktree list`).
If on `master`/`main` or in the main working directory, create a worktree
first (see Branching).
1. Write the test first.
2. Run the test to confirm it fails for the expected reason.
3. Commit the failing test. The test commit must precede the implementation
commit, not merely appear earlier in the implementation diff.
4. Implement the smallest change that makes the test pass.
5. Run the test to confirm it passes.
6. Commit the implementation.
7. Repeat for each new behavior.
Use judgment for changes that cannot meaningfully be test-driven, such as
documentation-only edits or declarative environment configuration. Validate
those changes with the most relevant parser, formatter, dry run, or check.
## Running processes
- The main checkout owns the canonical stack on the default ports. Assume it
is the user's stack. Do not start, restart, or stop it unless the user asks.
- A worktree owns its own isolated stack. The flake shell hook assigns a
deterministic port offset and creates worktree-local PostgreSQL state.
- Start a worktree stack from its root with `process-compose up`. For
non-interactive use, run `process-compose up -D` and stop it with
`process-compose down`.
- Do not use `process-compose -t=false` for a detached stack. It can leave an
orphaned PostgreSQL process holding the data directory.
- Non-interactive agent shells do not automatically load direnv. A bare
`process-compose`, `php artisan`, or database command from a worktree can
silently use default ports and target the main checkout.
- Prefix worktree stack and database commands with `direnv exec <worktree>`.
Examples:
```sh
direnv exec <worktree> process-compose up -D
direnv exec <worktree> process-compose down
direnv exec <worktree> php artisan migrate:fresh --seed
```
- Run backend commands from `backend/`, or explicitly change into it in the
command.
- When a normally valid check fails because a required service is down,
surface the environmental failure. Do not skip the check or silently switch
to a different database or service.
- PHPUnit is self-contained and uses in-memory SQLite. It does not require the
PostgreSQL stack unless a future test is explicitly designed as a real
PostgreSQL integration test.
## Code style
- Keep lines at or below 80 columns where practical. Do not split short,
readable lines unnecessarily.
- Use explicit, descriptive variable names. Do not use single-letter or
unexplained abbreviated names.
- Explore the codebase and inspect similar files before implementing a new
pattern.
- Never use em dashes in code, comments, or docblocks. Use hyphens.
- Always use braced control-statement bodies, including early returns:
```ts
if (identifier === null) {
return null
}
```
## Git commit style
- Use present-tense, imperative subjects: `add`, `create`, `wire`, `fix`,
`test`.
- Keep subjects lowercase and short, normally three to six words.
- Match patterns in the existing git history.
- Do not add AI or tool coauthor trailers.
- Add a body when the subject cannot explain non-obvious motivation or
multi-file coordination.
- Wrap bodies at approximately 72 columns and separate them from the subject
with a blank line.
## Git commits
- Commit tests before implementation.
- Keep one logical change per commit. A logical change may span multiple
files.
- Commit each meaningful step rather than batching unrelated work.
- Do not include drive-by formatter or linter changes. Restore them or land
them as a separate formatting commit.
- If a check fails on untouched code, do not bundle an unrelated fix. Report
the pre-existing failure or handle it as its own explicitly scoped change.
## Branching
- Never implement features directly in the main checkout or on
`master`/`main`.
- Use a dedicated worktree under
`<repo-root>/.worktrees/<branch>`.
- Create it with:
```sh
git worktree add \
"$(git rev-parse --show-toplevel)/.worktrees/<branch>" \
-b <branch>
```
- Use descriptive kebab-case branch names, optionally prefixed with a type
such as `feature/` or `fix/`.
- Keep worktree names short, preferably no more than about 20 characters.
PostgreSQL Unix socket paths are limited in length.
- Provision a fresh worktree through direnv:
```sh
direnv allow <worktree>
direnv exec <worktree> true
```
- Never symlink `backend/vendor` or a future frontend's `node_modules` from
another checkout. Dependency paths and generated autoloaders must remain
worktree-local.
Do not push anything. Make commits as the TDD workflow requires.
## Before completing a change
Run the smallest relevant checks while iterating, then run every repository
gate affected by the change.
### Backend
- Run tests from `backend/` with `php artisan test`.
- Run the Composer checks defined by `backend/composer.json` when their
dependencies are available:
```sh
composer lint:check
composer types:check
composer test
```
- Do not claim a green gate when a command fails. If the failure predates the
change, report the precise baseline failure.
### Frontend
- The frontend does not exist yet. Once scaffolded, use the scripts defined in
its `package.json` for formatting, linting, type checking, unit tests, and
end-to-end tests.
- Update `ai/frontend-context.md` when the actual scaffold, package manager,
and commands are known.
### Environment and integration
- For Nix or shell-hook changes, run `nix fmt` and `nix flake check`.
- For service configuration changes, run `process-compose --dry-run`.
- When a change affects runtime wiring, start the worktree's stack and verify
the relevant endpoint or service against that worktree.
- If you started the stack only for validation, stop it before finishing.