Contributing Guide
July 26, 2026 · View on GitHub
Thank you for considering a contribution to Canvas.
If you're fixing docs, translations, bugs, or features, please open a pull request and keep it focused on one change.
Before you start
- Use PHP 8.3+ and a Laravel major supported by the package (see
composer.jsonand CI). - CI runs JavaScript checks on Node 22 — match that locally when possible.
- Read
readme.mdfor install basics. - Host contracts, clean-break install, and the support matrix live in
UPGRADE.md. - Search for existing patterns before adding a new layer or abstraction.
- Translations go under
resources/lang(see Language catalog below). - Follow the Code of Conduct.
- Security vulnerabilities: report privately per
SECURITY.md— do not open public issues for vulns.
Local Laravel app
If you want to work locally, use a Laravel app with a sibling Canvas checkout:
-
From the root of your Laravel app, add the local Canvas checkout as a Composer path repository:
composer config repositories.canvas '{"type": "path", "url": "../canvas"}' --file composer.json -
Require Canvas and finish the install:
composer require austintoddj/canvas @dev php artisan canvas:install -
To avoid re-publishing frontend assets every time you make a change, symlink the Canvas package build output into your Laravel app instead:
rm -rf public/vendor/canvas ln -s "$(cd .. && pwd)/canvas/resources/dist" public/vendor/canvasPackage builds land in
resources/dist(includingassets,manifest.json, and thecanvas.hotfile from the Vite dev server). Hosts still serve them frompublic/vendor/canvasafter publish or this symlink. -
From the Canvas package directory, start the Vite dev server:
npm install npm run devCanvas uses Laravel's Vite integration: the package writes builds to
resources/dist, while production base URLs stay/vendor/canvas/...so they match the host publish path. Runningnpm run devstarts the dev server and writesresources/dist/canvas.hot— that file tells Canvas to serve assets from the dev server rather than the production build. For a production-style build, runnpm run buildinstead. -
Adjust
/canvasif your folder layout is different.
Before opening a pull request
- Run
npm run typecheck,npm run lint, andnpm test - Run
npm run buildand commit updated assets inresources/dist— hosts serve published package assets; CI does not rebuild dist for them - Run
composer pint(orcomposer pint:testto check without fixing) - Run
composer lint(PHPStan) - Run
composer test:cito match the PHP matrix locally - Optional:
composer test:install-smoke(real Laravel host install),composer test:database(driver group; setDB_CONNECTION=mysql|pgsqlagainst a local server), andnpm run e2e:prepare && npm run e2e(Playwright specs intests/e2e/)
Once you've made your changes, create a pull request from your fork to the develop branch of the project repository. For large majors, work may land on a version branch (e.g. v7) first; open PRs against the branch maintainers are merging, defaulting to develop unless the issue or PR says otherwise.
Language catalog
UI copy lives under resources/lang. A feature that introduces or changes UI strings is not complete until the full catalog is updated.
| Rule | Detail |
|---|---|
| Source of truth | resources/lang/en/app.php |
| Every other locale | Same key set as en — no missing keys, no extra keys |
| New / updated keys | Add or update the key in every resources/lang/{locale}/app.php with a real translation for that language — not a copy of the English string |
| Allowed English overlap | Only true cognates, loanwords, brands, or identical short words (e.g. SEO, URL, API, Unsplash, Canvas, Avatar, OK) |
| Removed / renamed keys | Apply in every locale file in the same change |
| Proof | composer test -- --filter=LocalizationTest must pass (key parity). Also spot-check that new strings are not English clones in non-en files |
Do not leave English placeholders or “translate later” TODOs for other locales.
Before a release
- Run the full quality gate:
composer pint:test,composer lint,composer test:ci,npm run typecheck,npm run lint,npm test, andnpm run buildwhen SPA assets change - Regenerate coverage once with
composer test:coverage(ortest:coverage:html; floor is 98%) and do not claim percentages without a fresh run - Prefer CI install-smoke + Playwright e2e for host confidence; still smoke the admin SPA manually when UI paths are hard to automate: media upload/delete → roles → integrations
- Finish the language catalog for any UI copy changes — key parity alone is not enough