8.1 KiB
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.mdare future ideas, not authorized scope. - The Laravel backend exists under
backend/. - The standalone Vue frontend exists under
frontend/website/. - Keep the frontend independent from the backend. Do not add backend-driven rendering, asset delivery, or build integration unless the user explicitly asks for it.
- PostgreSQL is the development and runtime database.
- PHPUnit uses in-memory SQLite for isolated tests.
Process (TDD)
- Before editing any file, ensure you are working in a dedicated git
worktree, not the main checkout (
git statusandgit worktree list). If onmaster/mainor in the main working directory, create a worktree first (see Branching). - Write the test first.
- Run the test to confirm it fails for the expected reason.
- Commit the failing test. The test commit must precede the implementation commit, not merely appear earlier in the implementation diff.
- Implement the smallest change that makes the test pass.
- Run the test to confirm it passes.
- Commit the implementation.
- 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. For non-interactive use, start it detached and stop it when finished, as shown below.
-
Do not use
process-compose -t=falsefor a detached stack. It can leave an orphaned PostgreSQL process holding the data directory. -
Non-interactive agent shells do not automatically load direnv. Bare project commands can use missing tools, default ports, or paths from the main checkout.
-
Run project tooling that depends on the repository development environment through direnv. This includes PHP, Composer, Artisan, npm, tests, builds, database clients, and services.
-
Resolve the direnv target from the worktree containing the agent's current working directory. Never target the main checkout or a different worktree:
direnv exec "$(git rev-parse --show-toplevel)" <command> -
Git and environment-neutral read-only file inspection do not need the direnv wrapper.
-
Worktree stack examples:
direnv exec "$(git rev-parse --show-toplevel)" process-compose up -D direnv exec "$(git rev-parse --show-toplevel)" process-compose down -
Run backend commands from
backend/, or explicitly change into it in the command. The direnv target remains the worktree root. -
Run frontend commands from
frontend/website/. -
process-composedoes not start the frontend. Start it separately with the worktree's assigned port when needed:direnv exec "$(git rev-parse --show-toplevel)" \ npm run dev -- --port "$VITE_PORT" -
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:
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:
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/orfix/. -
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:
direnv allow <worktree> direnv exec <worktree> true -
Never symlink
backend/vendororfrontend/website/node_modulesfrom another checkout. Dependency paths and generated files must remain worktree-local. -
The shell hook installs backend dependencies but does not install frontend dependencies. From
frontend/website/, provision them with:direnv exec "$(git rev-parse --show-toplevel)" npm install
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/:direnv exec "$(git rev-parse --show-toplevel)" php artisan test -
Run the Composer checks defined by
backend/composer.json:direnv exec "$(git rev-parse --show-toplevel)" composer types:check direnv exec "$(git rev-parse --show-toplevel)" composer test -
Do not claim a green gate when a command fails. If the failure predates the change, report the precise baseline failure.
Frontend
-
Run these commands from
frontend/website/: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 -
The formatter and linters rewrite files. Review their changes before committing.
-
No frontend test runner is configured yet. Do not claim unit, component, or end-to-end test coverage until the relevant scripts exist and pass.
Environment and integration
-
For Nix or shell-hook changes, run:
direnv exec "$(git rev-parse --show-toplevel)" nix fmt direnv exec "$(git rev-parse --show-toplevel)" nix flake check -
For service configuration changes, run:
direnv exec "$(git rev-parse --show-toplevel)" \ 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.