Thank you for your interest in contributing to the TYPO3 LLM extension!
- PHP 8.2+
- DDEV for local development
- Composer
- Node.js 20+ (for E2E tests)
# Clone the repository
git clone https://github.com/netresearch/t3x-nr-llm.git
cd t3x-nr-llm
# Start DDEV
ddev start
# Install dependencies
ddev composer install
# Run tests
ddev exec ".Build/bin/phpunit -c Build/phpunit.xml"Before submitting a PR, ensure all checks pass:
# Code style, PHPStan, unit, integration and fuzzy tests.
# Rector and the functional tests are not part of this script — CI runs those
# too, so run them individually before pushing.
ddev exec "composer ci"
# Or run individually:
ddev exec ".Build/bin/php-cs-fixer fix --config=.php-cs-fixer.dist.php --dry-run"
ddev exec ".Build/bin/phpstan analyse -c Build/phpstan/phpstan.neon"
ddev exec ".Build/bin/phpunit -c Build/phpunit.xml"
ddev exec ".Build/bin/rector process --config=Build/rector/rector.php --dry-run"Every class-level docblock carries @api, @api Extension point: … or
@internal (ADR-127, Documentation/Api/Stability.rst). New classes pick a
marker at creation time. @api means the semver promise covers it — every
type in its method signatures must be @api too. Extension-point interfaces
must not gain a new abstract member within a major version. Everything else
is @internal.
The rendered @api surface — constructors included — is frozen in
Tests/Unit/Api/api-surface.txt. The snapshot test classifies its own
failure: additive (a new class, method, property, constant or enum case)
means regenerate the file and note it under ### Added; breaking
(anything removed or changed, a widened constructor included) means stop and
decide.
Removing or narrowing something @api follows
Documentation/Api/Deprecation.rst: deprecate in a minor, keep it working
through one further minor line, remove in the next major, and add the
migration row the inventory test requires. Which TYPO3 and PHP versions the
promise is made on is Documentation/Api/SupportMatrix.rst, and it is
asserted against composer.json, ext_emconf.php and the CI matrix.
All contributions MUST include appropriate tests.
| Change Type | Required Tests |
|---|---|
| New feature | Unit tests + Integration tests |
| Bug fix | Regression test (proves the fix) |
| Refactoring | Existing tests must pass |
| New provider | Unit tests + Integration tests |
| API changes | Update affected tests |
# Unit tests
composer ci:test:php:unit
# Integration tests
composer ci:test:php:integration
# Functional tests (requires DDEV)
ddev exec "composer ci:test:php:functional"
# Fuzzy/Property-based tests
composer ci:test:php:fuzzy
# Mutation tests (code quality)
composer ci:test:php:mutation
# E2E tests (requires DDEV + Playwright)
npm run test:e2e- New code should have reasonable test coverage
- Critical paths (security, API calls) require high coverage
- Run
composer test -- --coverage-html=coverageto view coverage report
- Never commit secrets (API keys, passwords, tokens)
- Escape all output - use
htmlspecialchars()for HTML, Fluid auto-escaping - Validate all input - use DTOs with type-safe extraction
- Use parameterized queries - Extbase Query or QueryBuilder
- Report vulnerabilities privately via GitHub Security Advisories
See SECURITY.md for vulnerability reporting.
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Make your changes
- Write/update tests (required)
- Ensure all tests pass
- Commit using conventional commits
- Push and open a Pull Request
- Tests added/updated
- All CI checks pass
- Documentation updated (if applicable)
-
CHANGELOG.mdentry added under## [Unreleased] - ADR added under
Documentation/Adr/if the public surface changed - No secrets committed
- Follows existing code style
Every change that a consumer or an integrator can notice gets a CHANGELOG.md
entry under ## [Unreleased], in the Keep a Changelog section that fits
(Added / Changed / Deprecated / Removed / Fixed / Security).
Version bumps belong to the release commit, never to a feature PR.
A change to the public surface also gets an Architecture Decision Record under
Documentation/Adr/, named Adr<N><Description>.rst — take the next free
number and follow the format of an existing one. Add the file name to the
toctree at the bottom of Documentation/Adr/Index.rst as well; that toctree
is explicit, so an unregistered ADR renders as an orphan page nothing links to.
Public surface means anything
a consumer builds against: an interface, a DI-tagged extension point, a database
table, a TCA field, an Extension Configuration key, a console command, or the
behaviour of any of them. Recording why matters more than recording what; the
diff already shows what.
We use conventional commits:
feat:New featuresfix:Bug fixesdocs:Documentation changesrefactor:Code refactoringtest:Test changeschore:Maintenance taskssecurity:Security fixes
- Create a new class extending
AbstractProvider - Implement required methods
- Add unit tests in
Tests/Unit/Provider/ - Add integration tests in
Tests/Integration/Provider/ - Update documentation in
Documentation/ - Add to TCA adapter type options
All PRs require review by a code owner before merging. Reviews focus on:
- Code quality and maintainability
- Test coverage and quality
- Security considerations
- Documentation completeness
Open an issue or start a discussion!
All commits must be cryptographically signed and carry a DCO sign-off: git commit -S --signoff. The require-signed-commits ruleset on the default branch enforces the signature (the "Verified" badge on GitHub); the DCO check enforces the Signed-off-by trailer — these are two different things and both are required. Quickest setup is SSH signing: register your SSH key as a signing key on your GitHub account, then git config --global gpg.format ssh && git config --global user.signingkey ~/.ssh/<key>.pub.