Contributing

Contributing

Contributions to externa-core should match the existing Laravel + Inertia React stack, keep enums as the source of truth for permissions/field types/roles, and leave tests green.

Work in the externa-core repository. Operators on Packagist / Docker prod paths can skip contributor hooks.

Local git hooks (Lefthook)

After npm ci (or npx lefthook install), clones get:

HookChecks
pre-commitPint (--dirty), ESLint + Prettier on staged frontend files
commit-msgcommitlint Conventional Commits
pre-pushpint --test + eslintnot full Pest / browser

GitHub Actions remains the source of truth. Skip locally with LEFTHOOK=0 or git commit --no-verify (emergency only). See repo CONTRIBUTING.md.

Tooling

PHP — Pint

Laravel Pint formats PHP. Composer scripts:

composer lint          # pint --parallel
composer lint:check    # pint --parallel --test

composer test runs lint:check before Pest.

Frontend — ESLint & Prettier

From externa-core:

npm run lint           # eslint . --fix
npm run lint:check     # eslint .
npm run format         # prettier --write resources/
npm run format:check   # prettier --check resources/
npm run types:check    # tsc --noEmit

CI-style gate:

composer ci:check

(runs npm lint/format/types checks + composer test).

Wayfinder

Laravel Wayfinder + @laravel/vite-plugin-wayfinder generates typed route/action helpers under resources/js during Vite build/dev.

  • Prefer Wayfinder helpers over hard-coded URL strings in React.
  • After adding/renaming named routes, run Vite (npm run dev or build) so generated clients refresh.
  • Do not hand-edit generated route trees as a long-term source of truth.

Pest

Feature and browser tests use Pest 4. See Testing for layout and how to run suites.

composer test
# or focused:
php artisan test --filter=SomeTestName

Coding conventions

Enums are the source of truth

ConcernEnumSync / mirror
PermissionsApp\Enums\PermissionEnumphp artisan permissions:sync → DB + resources/js/enums/permission-enum.ts
Roles (built-in names)App\Enums\RoleEnumSeeded in RoleSeeder
Field typesApp\Enums\FieldTypeEnumValidation, normalizer, UI catalog, AI instructions
File kindsApp\Enums\FileTypeEnumFile manager / storage helpers

Do not invent permission or field-type strings in controllers or React without updating the enum first. Extension recipes: Extending Externa.

Actions & Services

  • app/Services/ — domain orchestration used by controllers, jobs, and AI tools (FileService, Authorization\EffectivePermissionResolver, Collections services, …).
  • app/Actions/ — single-purpose actions (Fortify actions live under app/Actions/Fortify). Prefer a small Action class when a use-case is reused or would bloat a controller.
  • Controllers stay thin: Form Requests validate/authorize; Services/Actions mutate state; Jobs handle async work.

HTTP & auth

  • Admin/files/AI routes: enforce permissions with middleware or Form Requests (AuthorizesWithPermission / EffectivePermissionResolver).
  • Collections HTTP currently relies on UI + AI checks — if you harden that, document it and add tests (Collections API).
  • AI tools must use ChecksAiPermissions for mutating/domain operations.

Frontend

  • Pages under resources/js/pages/… matching Inertia names.
  • Gate UI with useCan() + PermissionEnum from the generated TS enum.
  • Follow existing shadcn/Radix + Tailwind patterns; avoid one-off design systems.

Jobs & schedule

New async work should use the queue (not dispatchSync in request paths for heavy I/O). If you add a scheduled command, register it in routes/console.php and document it under Operations.

Graphify knowledge graph

This monorepo maintains a graphify index under graphify-out/ at the Externa workspace root.

After you change code (PHP/TS that affects architecture or APIs):

cd /path/to/Externa
graphify update .

Use graphify query "…" when exploring relationships before large refactors. Skip graphify update for docs-only or pure config-comment edits that do not change behaviour.

Dependency audits (CI)

PRs and pushes to develop / main run .github/workflows/audit.yml:

CheckCommandPolicy (beta.3)
Composercomposer audit --locked --ignore-severity=low --ignore-severity=mediumBlocking on high/critical
npm (runtime)npm audit --omit=dev --audit-level=highBlocking on high/critical

DevDependencies are not audited in the blocking job. Do not run npm audit fix --force in CI or as a blind local fix.

Reading failures

  1. Open the failed audit job log; note package + advisory ID / CVE.
  2. Prefer upgrading within the current major (composer update pkg / npm update pkg) and re-run locally.
  3. False positives / accepted risk: document in the PR with justification. Composer: temporary --ignore entries only with a tracked follow-up. npm: avoid .npmrc force; prefer upgrading or switching package.
  4. Path to GA (#24): keep audits blocking (no continue-on-error).

See also Security checklist · repo SECURITY.md.

Dependabot

.github/dependabot.yml opens weekly PRs (Monday) for Composer, npm, and GitHub Actions. Minor/patch updates are grouped per ecosystem; open-PR limits keep noise down. Majors arrive as separate PRs.

Reviewing a Dependabot PR

  1. Confirm CI green (lint, tests, audit jobs).
  2. Skim release notes / changelog for breaking changes — do not merge major bumps blind.
  3. Prefer one ecosystem group merge at a time; re-run audits locally if unsure.
  4. After merge, note notable upgrades in CHANGELOG.md when cutting a release (see Release process / #22).

PR expectations

  1. Pint / ESLint / Prettier / tsc clean.
  2. Pest coverage for new behaviour (see Testing).
  3. Enum + permissions:sync when permissions change; commit regenerated TS enum.
  4. Note public route or config contract changes in the PR so product docs can be updated.
  5. graphify update . when the code graph should reflect your changes.
  6. Dependency audit CI green (or justified ignore with follow-up).

Releases

Maintainers cutting a version: Releasing & versions (CHANGELOG, semver, GitHub Release template). Prefer noting user-facing changes in CHANGELOG.md Unreleased while the PR is open.

Previous
GA readiness