Get started8 min read
Machine, Git and conventions
Everything you need to clone a project, run it, and ship code the team can review without friction.
Set up your machine
One version of each tool for the whole team: no more "works on my machine".
| Tool | How |
|---|---|
| PHP 8.4, Composer, Laravel installer | Official php.new script (Linux, WSL) or Laravel Herd (macOS, Windows). |
| Node.js 24 LTS | Through fnm or nvm, never the system Node. The project pins the version in .nvmrc. |
| PostgreSQL, Redis | Docker Compose ships with every API project (docker compose up -d), or DBngin on macOS. |
| Editor | VS Code or PhpStorm, with format on save enabled. |
| VS Code extensions | Laravel (official), PHP Intelephense, ESLint, Prettier, Tailwind CSS IntelliSense, i18n Ally (translation keys). |
# PHP 8.4 + Composer + Laravel installer (Linux / macOS / WSL)
/bin/bash -c "$(curl -fsSL https://php.new/install/linux/8.4)"
# Node.js 24 LTS via fnm
curl -fsSL https://fnm.vercel.app/install | bash
fnm install 24 && fnm default 24
# Check everything
php -v && composer -V && laravel --version && node -v && npm -vFirst run
Run these commands in order. If a test fails before your first change, tell your mentor: it's not yours to fix silently.
git clone git@github.com:lantorian/<project>-api.git && cd <project>-api
composer install
cp .env.example .env
php artisan key:generate
php artisan migrate --seed
composer run dev # server + queue + logs + vite, all at once
composer test # must be green before you touch anythinggit clone git@github.com:lantorian/<project>-web.git && cd <project>-web
npm ci # exact versions from package-lock.json
cp .env.example .env.local # ask a teammate for the values
npm run dev # http://localhost:3000/fr
npm run lint && npm run typecheck && npm testThe Git flow
One branch per ticket, small readable commits, a reviewed pull request before every merge. Nobody pushes straight to main.
- 1
Branch from an up-to-date main
Format:type/ticket-number-description, for examplefeat/142-invoice-export. - 2
Commit in small steps
One commit = one intention. Usegit add -pto review what you stage. - 3
Rebase before pushing
git rebase origin/mainkeeps history linear. Don't merge main into your branch. - 4
Open the PR
Conventional Commits title, a description with context, screenshots when the UI changes, and the checklist ticked. - 5
Address the review
Reply to every comment, push the fixes, then a reviewer merges with squash merge.
git switch main && git pull --rebase
git switch -c feat/142-invoice-export
# ...code, test, commit small steps
git add -p
git commit -m "feat(invoice): add csv export action"
# keep your branch up to date, then open the PR
git fetch origin && git rebase origin/main
git push -u origin feat/142-invoice-exportCommit messages
We follow Conventional Commits: type(scope): imperative description, in English, lowercase, no trailing period.
| Type | When to use it |
|---|---|
feat | New user-facing feature. |
fix | Bug fix. |
refactor | Code change with no behavior change. |
test | Adding or fixing tests only. |
docs | Documentation, README, comments. |
chore | Dependencies, configuration, tooling. |
perf | Measurable performance improvement. |
Avoid
wip
fix
update files
final version OKDo
feat(invoice): add csv export action
test(invoice): cover empty invoice list
fix(auth): refresh token before expiry
refactor(user): extract CreateUser actionNaming conventions
A name says what the thing does. When in doubt, copy what already exists in the project.
| Item | Rule | Example |
|---|---|---|
| PHP class | PascalCase, role suffix | CreateInvoiceAction |
| PHP method | camelCase, verb | markAsPaid() |
| SQL table | plural snake_case | invoice_lines |
| API URL | kebab-case, plural resources | /api/v1/invoice-lines |
| React component | PascalCase | InvoiceTable |
| Front-end file | kebab-case | invoice-table.tsx |
| React hook | use prefix | use-invoices.ts |
| Translation key | camelCase, grouped by screen | invoices.table.emptyTitle |
Quality tooling
The same commands run on your machine and in CI. Pint formats PHP, Larastan checks types, ESLint and Prettier handle TypeScript.
{
"scripts": {
"dev": "npx concurrently \"php artisan serve\" \"php artisan queue:listen\" \"php artisan pail\" \"npm run dev\"",
"lint": "pint --test",
"format": "pint",
"analyse": "phpstan analyse --memory-limit=1G",
"test": "pest --parallel",
"test:coverage": "pest --parallel --coverage --min=80",
"ci": ["@lint", "@analyse", "@test"]
}
}{
"scripts": {
"dev": "next dev",
"build": "next build",
"lint": "eslint .",
"format": "prettier --write .",
"typecheck": "tsc --noEmit",
"test": "vitest run",
"test:e2e": "playwright test",
"i18n:check": "node scripts/check-i18n.mjs"
}
}root = true
[*]
charset = utf-8
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
indent_style = space
indent_size = 2
[*.php]
indent_size = 4
[*.md]
trim_trailing_whitespace = falseAsking for help
Being stuck alone for a day costs more than a question. When you ask, include: what you're trying to do, what you tried, the full error message.