Contributing to Arqel
Welcome! Arqel is an MIT open-source framework maintained by the community. This guide explains in detail how to start contributing, from the first git clone to the first approved PR.
Executive summary in the root
CONTRIBUTING.md. This document expands with more context, examples, and gotchas.
Why contribute
Arqel exists to make Laravel + React admin panels as productive as Filament and Nova, but with a modern stack (React 19.2, Inertia 3, strict TypeScript, Radix UI). Each contribution:
- Speeds up the Laravel ecosystem by offering a first-class alternative to Filament/Nova
- Reduces tech debt in projects that depend on admin panels
- Builds reputation — authors are credited in release notes and can become maintainers
- Lots to learn — the repo combines modern PHP, React 19.2, Inertia, monorepo, CI matrix, splitsh, and framework design patterns
The size of the contribution doesn't matter: typo fix, new Field, full vertical — everything is welcome as long as it follows the standards in this document.
Before you start
Read, in order:
README.md— project overview.CLAUDE.md— operational conventions (language, stack, commits).PLANNING/00-index.md— plan structure.PLANNING/03-adrs.md— 18 canonical ADRs. Don't contradict without an RFC.CODE_OF_CONDUCT.md.
If your contribution is a large new feature, open a discussion first in GitHub Discussions or an issue with the rfc label. This avoids rework.
Prerequisites
| Tool | Minimum version | Notes |
|---|---|---|
| PHP | 8.3 | Tested on 8.3 and 8.4. PHPStan level max. |
| Composer | 2.x | — |
| Node | 20.9 LTS | v22 recommended (.nvmrc). |
| pnpm | 10+ | corepack enable pnpm. |
| Git | 2.30+ | For --signoff and worktrees. |
Required PHP extensions: mbstring, intl, pdo_mysql, pdo_pgsql, redis, zip, bcmath.
Full setup (step by step)
1. Fork + clone
# On GitHub: arqel-dev/arqel → Fork
git clone https://github.com/<your-user>/arqel.git
cd arqel
git remote add upstream https://github.com/arqel-dev/arqel.git2. Select Node version
nvm use # reads .nvmrc
corepack enable pnpm3. Install dependencies
./scripts/init.shThe script:
composer installat the root and in eachpackages/*that has acomposer.json.pnpm installat the root (workspaces).- Sets up Husky hooks (
commit-msg,pre-commit). - Runs smoke tests to validate the setup works.
4. Verify the setup
pnpm run lint # Biome on JS/TS
pnpm run typecheck # tsc --noEmit on each workspace
pnpm run test # Vitest
vendor/bin/pint --test # Pint without applying
vendor/bin/phpstan analyse # Level max
vendor/bin/pest # Pest 3If any command fails before you make changes, open an issue — the setup should be clean on main.
PR workflow
1. Create a branch
Naming convention: <type>/<scope>-<short-description>.
git checkout -b feat/fields-add-color-picker
git checkout -b fix/table-pagination-edge-case
git checkout -b docs/guide-update-realtime-sectionValid types (aligned with Conventional Commits): feat, fix, docs, refactor, perf, test, chore, ci, build, style.
2. Implement the change
- Tests first when possible (Pest for PHP, Vitest for JS).
- Maintain coverage: ≥90% for core PHP packages, ≥80% for core JS.
- Update the package's
SKILL.mdif the public API changes. - Update
apps/docs/if there's a user-visible change.
3. Run the local checklist
pnpm test:all # lint + typecheck + tests, all of it
vendor/bin/pint # apply Pint
vendor/bin/phpstan analyse # level max
vendor/bin/pest --coverage # with coverage4. Commit with Conventional Commits + DCO
DCO sign-off is required — without it the PR is rejected by the bot.
git commit --signoff -m "feat(fields): add ColorField with preset palette
Implements FIELDS-042 from PLANNING/08-fase-1-mvp.md.
- Supports custom palette via the palette prop
- Clickable preview opens BasePicker
- Test coverage: 95%
"Format:
<type>(<scope>): <description>
[optional body explaining the "why"]
[footer with ticket reference: Implements FOO-001]Common scopes: package name (core, fields, table, marketplace, ai, realtime, ui, react, docs, ci).
5. Sync with upstream
git fetch upstream
git rebase upstream/masterUse rebase, not merge — keeps history linear.
6. Open the PR
- Title in Conventional Commits format.
- Fill in the
.github/PULL_REQUEST_TEMPLATE.mdtemplate. - Check "Allow edits from maintainers".
- Link the related issue or ticket.
- If there's UI, attach screenshots or GIFs.
7. Code review
- At least 1 maintainer must approve.
- CI must pass (PHP × Laravel matrix, lint, typecheck).
- Resolve all comments before merge.
- If the PR sits >7 days, comment pinging maintainers.
8. Merge
Maintainers squash merge to keep history clean. The final message follows the PR title.
Style guide
PHP
declare(strict_types=1);in every file.- Classes
finalby default. Useabstractorextendsonly when extensibility is design intent. - Use Laravel-native features (Policy, FormRequest, Eloquent, Gate) before reinventing.
- Respect
pint.json(Laravel preset + project tweaks). - PHPStan level max — no
mixedwithout need.
TypeScript / React
strict: true+noUncheckedIndexedAccess: true(already intsconfig.base.json).- Functional components always. No class components.
- Hooks:
useprefix, React rules in strict mode. - Types exported in
@arqel-dev/types. Never duplicate across packages. - ESLint via Biome (
biome.json).
Inertia-only (ADR-001)
The only PHP↔React bridge is Inertia 3. Do not add TanStack Query, SWR, Axios, fetch wrappers for Resource CRUD. Inertia props are the default state.
Documentation
- English (US/standard). Native English idioms welcome.
- Code in English (class names, variables, inline comments).
- Complete and runnable examples whenever possible.
How to add a new package
- Drop the structure into
packages/<name>/(PHP) orpackages-js/<name>/(JS). - Add
composer.jsonorpackage.jsonfollowing the pattern of existing packages. - Create
SKILL.mdwith the canonical structure (PLANNING/00-index.md§5):- Purpose, Key Contracts, Conventions, Examples, Anti-patterns, Related.
- Add tests (
tests/PHP +*.test.tsJS). - Update:
pnpm-workspace.yaml(if JS).- Root
composer.jsonrepositories(if PHP, path repo). apps/docs/.vitepress/config.tsif visible in the docs..github/labeler.ymladding a rule for the new package.CODEOWNERSadding the appropriate line.
- Open a PR with the
new-packagelabel.
How to propose a new ticket in PLANNING
Tickets live in PLANNING/08-*.md (Phase 1) through PLANNING/11-*.md (Phase 4). To propose:
- Open an issue with the
proposal-ticketlabel describing: context, problem, API proposal, acceptance criteria. - Discussion in Discussions or in the issue.
- After approval, a maintainer adds the ticket to the correct file following the template:
### [PACKAGE-###] Title
**Type:** feat • **Priority:** P0-P3 • **Estimate:** XS-XL • **Layer:** php|react|shared|infra|docs • **Depends on:** [OTHER-TICKET]
**Context** (why it exists)
**Technical description** (what to do + example code)
**Acceptance criteria** (checkboxes)
**Implementation notes** (gotchas)Run diagnostics before the PR
Two useful commands (available after Phase 1):
php artisan arqel:doctor # Checks versions, configs, panel integrity
php artisan arqel:audit # Audits Resources/Fields against ADRsAttach the output to the PR if the change touches integration between packages.
Where to discuss before the PR
- GitHub Discussions — questions, informal RFCs, brainstorming.
- Issues with
rfclabel — formal RFCs for API changes. - Discord (link in README when available) — quick chat.
Common gotchas
- Forgotten DCO: rebase with
git rebase --signoff -i HEAD~Nto retroactively add sign-offs. - PHPStan max failing on new code: PHPStan is now strict; validate with
vendor/bin/phpstan analysebefore pushing. - Biome complaining on untouched files: run
pnpm run lint:fixonly on your files with--files-ignore-unknown=trueor explicitly. - Composer path repos not updating: run
composer update arqel/*at the root to pull local changes. - Husky not running hooks: confirm setup ran
pnpm run prepare(installs hooks). - PostgreSQL matrix tests failing locally: CI uses a dedicated service; locally prefer MySQL or run
docker compose up postgresif there's acompose.yml.
Recognition
Contributors are listed automatically via all-contributors (will be enabled before v1.0). Active maintainers gain triage and merge access after 5+ approved PRs or an explicit invitation.
Support and questions
- Bug or unexpected behavior: issue with the
bug_reporttemplate. - Usage question: Discussions or the
questiontemplate. - Security vulnerability: DO NOT open a public issue — follow
SECURITY.md.
Thanks for contributing to Arqel!