nowo-tech / legal-kit-bundle
Operator-editable legal pages for Symfony: legal notice, privacy, terms and cookies per locale with a generic GDPR/LSSI seed in 7 languages, a placeholder gate for deploys, ops-seed portability, a DOM allowlist sanitiser and UiKit admin pages.
Package info
github.com/nowo-tech/LegalKitBundle
Type:symfony-bundle
pkg:composer/nowo-tech/legal-kit-bundle
Requires
- php: >=8.3 <8.6
- ext-dom: *
- ext-libxml: *
- doctrine/doctrine-bundle: ^2.10 || ^3.0
- doctrine/orm: ^3.3
- doctrine/persistence: ^3.0 || ^4.0
- nowo-tech/audit-kit-bundle: ^1.7
- nowo-tech/form-kit-bundle: ^2.12
- nowo-tech/ui-kit-bundle: ^2.4
- psr/event-dispatcher: ^1.0
- symfony/asset: ^7.4 || ^8.0
- symfony/config: ^7.4 || ^8.0
- symfony/console: ^7.4 || ^8.0
- symfony/dependency-injection: ^7.4 || ^8.0
- symfony/event-dispatcher: ^7.4 || ^8.0
- symfony/form: ^7.4 || ^8.0
- symfony/framework-bundle: ^7.4 || ^8.0
- symfony/http-foundation: ^7.4 || ^8.0
- symfony/http-kernel: ^7.4 || ^8.0
- symfony/routing: ^7.4 || ^8.0
- symfony/security-core: ^7.4 || ^8.0
- symfony/security-csrf: ^7.4 || ^8.0
- symfony/translation: ^7.4 || ^8.0
- symfony/translation-contracts: ^3.5
- symfony/twig-bundle: ^7.4 || ^8.0
- symfony/validator: ^7.4 || ^8.0
- twig/extra-bundle: ^3.12
- twig/string-extra: ^3.12
- twig/twig: ^3.12
Requires (Dev)
- friendsofphp/php-cs-fixer: ^3.64
- igor-php/igor-php: ^0.9.7
- nowo-tech/ckeditor5-editor-bundle: ^1.9
- nowo-tech/cookie-consent-bundle: ^1.17
- nowo-tech/outbound-url-guard-bundle: ^1.2
- nowo-tech/phpstan-frankenphp: ^1.1
- nowo-tech/seo-kit-bundle: ^1.14
- phpstan/phpstan: ^2.1
- phpstan/phpstan-doctrine: ^2.0
- phpstan/phpstan-phpunit: ^2.0
- phpstan/phpstan-symfony: ^2.0
- phpunit/phpunit: ^11.5
- rector/rector: ^2.0
- symfony/browser-kit: ^7.4 || ^8.0
- symfony/clock: ^7.4 || ^8.0
- symfony/css-selector: ^7.4 || ^8.0
- symfony/dom-crawler: ^7.4 || ^8.0
- symfony/security-bundle: ^7.4 || ^8.0
- symfony/yaml: ^7.4 || ^8.0
- vincentlanglet/twig-cs-fixer: ^3.0
Suggests
- nowo-tech/ckeditor5-editor-bundle: ^1.9 — CKEditor 5 body widget (editor.type: ckeditor5) and its strict sanitiser as the first pass
- nowo-tech/cookie-consent-bundle: ^1.17 — legal routes prepended to disabled_routes / render_routes, legal_privacy as the modal privacy_route fallback, %cookie_inventory% token from the consent inventory
- nowo-tech/outbound-url-guard-bundle: ^1.2 — drop private-network / metadata link and image targets from stored legal HTML
- nowo-tech/routing-kit-bundle: ^1.10 — locale-prefixed routing of the host (the bundle registers its own default-locale twins and redirects)
- nowo-tech/seo-kit-bundle: ^1.14 — sitemap provider listing every legal page in every locale
Provides
None
Conflicts
None
Replaces
None
This package is auto-updated.
Last update: 2026-10-20 07:18:58 UTC
README
⭐ Found this useful? Install from Packagist · Give it a star on GitHub so more developers can find it.
Legal Kit Bundle — operator-editable legal pages for Symfony: legal notice, privacy policy, terms and cookie notice
per locale, a generic GDPR / LSSI seed in 7 languages, a placeholder gate for deploys, ops-seed portability, a DOM
allowlist sanitiser and admin pages on the UiKit page contract. One package instead of a src/Shared/Legal copy in
every application.
📋 Compatible with Symfony 7.4+ and 8.0–8.1+ — PHP 8.3+ (Symfony 8.x requires PHP 8.4+).
This bundle is FrankenPHP worker mode friendly. See docs/FRANKENPHP-WORKER-AUDIT.md.
Features
- Four canonical pages (notice, privacy, terms, cookies) plus any extra slug, on stable routes
legal_<slug>(/{_locale}/legal/<path>); the default locale on the bare/legal/<path>(legal_<slug>_unlocalized, 301 from/{default}/…) or every locale prefixed (routing.default_locale_style: prefixed) - Operator editor (
ROLE_ADMIN): page × locale matrix with Built-in / Custom badges, last editor and placeholder hits; one tab per locale; CKEditor 5 or a plain textarea; restore the built-in text through the UiKit confirm dialog - Generic seed in 7 locales (en, es, de, nl, fr, it, pt) without any company identity (REQ-CC-011); hosts override keys, templates or register their own seed provider
- Placeholder gate:
nowo:legal-kit:check-placeholdersexits 1 while a published page still contains a seed marker or an unresolved%token%— run it in your deploy pipeline; the same hits in an Ops banner partial - Tokens resolved at render time only (
%brand%,%last_updated%,%cookie_inventory%, your own resolvers) — the editor keeps them - One strict sanitiser: DOM allowlist (no
style, no scripts / embeds / SVG, safe URL schemes,rel="noopener"), optional CKEditor strict first pass and OutboundUrlGuard (no private-network links), on every write and render - Ops-seed portability: export / normalise / apply
legal_documents[]in the host transaction,adapt-seedto build a fleet's identity from the seed,export/importcommands - Soft integrations: CookieConsent (no modal auto-open on legal pages, privacy link, inventory table), SeoKit (title, canonical, hreflang, sitemap), AuditKit (timestamps, blame, action log), RoutingKit twins
- Adopts existing tables: maps the
legal_documenttable of the apps it replaces as is — no data migration - FrankenPHP worker mode friendly; no JavaScript on public pages
Installation
composer require nowo-tech/legal-kit-bundle
// config/bundles.php (Flex does it for you) return [ Nowo\AuditKitBundle\NowoAuditKitBundle::class => ['all' => true], Nowo\UiKitBundle\NowoUiKitBundle::class => ['all' => true], Nowo\FormKitBundle\NowoFormKitBundle::class => ['all' => true], Nowo\LegalKitBundle\NowoLegalKitBundle::class => ['all' => true], ];
Create the table (bin/console doctrine:migrations:diff then migrate) — or keep yours if you adopt the bundle from
a legal copy; see docs/INSTALLATION.md.
Quick start
- Configure the locales and import the routes:
# config/packages/nowo_legal_kit.yaml nowo_legal_kit: locales: '%app.locales%' # or [en, es] default_locale: '%kernel.default_locale%' brand_name: 'Acme Cloud' # config/routes/nowo_legal_kit.yaml nowo_legal_kit: resource: . type: nowo_legal_kit
- Keep the public pages anonymous and the admin private:
# config/packages/security.yaml security: access_control: - { path: '^/(?:[a-z]{2}(?:_[A-Z]{2})?/)?legal/', roles: PUBLIC_ACCESS } - { path: ^/admin/legal, roles: ROLE_ADMIN }
- Put the legal links in your footer and the gate in your deploy:
{{ include('@NowoLegalKitBundle/_footer_nav.html.twig') }}
bin/console nowo:legal-kit:check-placeholders # exit 1 until every placeholder is replaced
Then open /admin/legal, replace the bracketed placeholders in every locale and have counsel review the text.
Requirements
- PHP
>=8.3 <8.6,ext-dom - Symfony 7.4, 8.0 and 8.1+ (FrameworkBundle, TwigBundle, Form, Validator, Security for the admin)
- Doctrine ORM 3 + DoctrineBundle;
nowo-tech/audit-kit-bundle^1.7 (user class configured),nowo-tech/ui-kit-bundle^2.4,nowo-tech/form-kit-bundle^2.12 - Optional:
nowo-tech/cookie-consent-bundle^1.17,nowo-tech/ckeditor5-editor-bundle^1.9,nowo-tech/outbound-url-guard-bundle^1.2,nowo-tech/seo-kit-bundle^1.14,nowo-tech/routing-kit-bundle^1.10
Version information
| Version | PHP | Symfony | Status |
|---|---|---|---|
| 1.x | 8.3 – 8.5 | 7.4, 8.0, 8.1+ | Supported (bug and security fixes) |
Configuration
Every key with its default is in docs/CONFIGURATION.md: page catalogue, URL style, seed fallback locale and materialise mode, editor, sanitiser allowlist, placeholder markers, cache headers, admin UI and security, integrations, console aliases and the table prefix.
Demo
A Symfony 8.1 demo runs on FrankenPHP (worker mode by default) with MySQL, CookieConsent and CKEditor 5:
make -C demo up
# Demo started at: http://localhost:8167
Sign in as admin / admin to edit the pages. See docs/DEMO-FRANKENPHP.md.
Playwright end-to-end tests and the README screenshots: make -C demo/symfony8 test-e2e and
make -C demo/symfony8 demo-screenshots.
Documentation
- Installation
- Configuration
- Usage
- Templates (UiKit page contract)
- Contributing
- Code of Conduct
- Changelog
- Upgrading
- Release
- Security
- Engram
- Spec-driven development
- GitHub Spec Kit
Additional documentation
- Architecture
- PSR evaluation
- Coverage policy
- Demo FrankenPHP
- FrankenPHP worker audit
- GitHub CI
- GitHub About
Tests and coverage
- Tests: PHPUnit (unit, integration, functional, page contract, schema adoption), Playwright (demo e2e)
- PHP: 100%
- TS/JS: N/A
- Python: N/A
PHP line coverage: 100% of includable src/ (gate ≥ 99%; strict gate make test-coverage-100).
make test
make test-coverage
make qa
License
MIT © 2026 Héctor Franco Aceituno / Nowo.tech


