nowo-tech / manual-kit-bundle
In-app product manual for Symfony from your docs/manual Markdown: one source for GitHub and the app, translations per locale with stable anchors and stale-translation checks, admin-only chapters and blocks that fail closed, figures with a lightbox, search tags and an optional SearchKit provider.
Package info
github.com/nowo-tech/ManualKitBundle
Type:symfony-bundle
pkg:composer/nowo-tech/manual-kit-bundle
Requires
- php: >=8.4 <8.6
- league/commonmark: ^2.6
- symfony/cache-contracts: ^3.5
- symfony/config: ^7.4 || ^8.0
- symfony/console: ^7.4 || ^8.0
- symfony/dependency-injection: ^7.4 || ^8.0
- symfony/framework-bundle: ^7.4 || ^8.0
- symfony/html-sanitizer: ^7.4 || ^8.0
- symfony/http-client-contracts: ^3.5
- symfony/http-foundation: ^7.4 || ^8.0
- symfony/http-kernel: ^7.4 || ^8.0
- symfony/mime: ^7.4 || ^8.0
- symfony/routing: ^7.4 || ^8.0
- symfony/security-core: ^7.4 || ^8.0
- symfony/string: ^7.4 || ^8.0
- symfony/translation-contracts: ^3.5
- symfony/twig-bundle: ^7.4 || ^8.0
- symfony/yaml: ^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/phpstan-frankenphp: ^1.1
- nowo-tech/search-kit-bundle: ^1.1
- phpstan/phpstan: ^2.1
- phpstan/phpstan-phpunit: ^2.0
- phpstan/phpstan-symfony: ^2.0
- phpunit/phpunit: ^10.5 || ^11.5
- rector/rector: ^2.0
- symfony/browser-kit: ^7.4 || ^8.0
- symfony/css-selector: ^7.4 || ^8.0
- symfony/http-client: ^7.4 || ^8.0
- symfony/security-bundle: ^7.4 || ^8.0
- symfony/translation: ^7.4 || ^8.0
- vincentlanglet/twig-cs-fixer: ^3.0
Suggests
- nowo-tech/search-kit-bundle: ^1.1 — a Manual group in the global header search (chapters and sections by title and tags)
- symfony/http-client: nowo:manual:translate with DeepL or LibreTranslate (machine translation of the chapters)
- symfony/ux-icons: Render the manifest `icon` of each chapter in your own chapter template
Provides
None
Conflicts
None
Replaces
None
README
⭐ Found this useful? Install from Packagist · Give it a star on GitHub so more developers can find it.
Manual Kit Bundle — an in-app product manual for Symfony built from your docs/manual Markdown: one source that
GitHub renders as it is and the application serves inside its own layout, translated per locale with stable anchors,
admin-only chapters and blocks that fail closed, figures with a lightbox, search tags and an optional
SearchKit provider.
📋 Compatible with Symfony 7.4+ and 8.0–8.1+ — PHP 8.4+.
This bundle is FrankenPHP worker mode friendly. See docs/FRANKENPHP-WORKER-AUDIT.md.
Features
- One source for GitHub and the app:
docs/manual/*.mdin reading order frommanifest.yaml; links between chapters (02-dashboard.md#filters) become in-app routes, links to other repository docs open the published copy (docs_url), GitHub-style.mdURLs redirect to the chapter - Translations per locale:
docs/manual/es/02-dashboard.mdnext to the source; a chapter without a translation is served from the source with a not translated yet notice;<!-- translation-of: <hash> -->marks a translation outdated as soon as its source changes - Stable anchors:
<a id="filters"></a>gives a heading the same id in every language, so the application's links (manual_href('manual/02-dashboard.md#filters')) survive translated titles - Audiences that fail closed:
audience: adminchapters answer 404 to members (no existence oracle);<!-- audience: admin -->blocks are dropped for members,audience: githubblocks never show in the app, and an unclosed or misspelt marker hides the rest of the chapter - Figures: images become figures with their title as caption, intrinsic width / height, lazy loading, phone screenshots sized down, several images of one paragraph side by side, and an opt-in Stimulus lightbox
- Search:
tagsin the manifest and<!-- tags: … -->under a heading feed the SearchKit "Manual" group (chapters and sections the viewer may read, in their locale) - Translation checks for CI:
nowo:manual:check --strictfails on outdated translations and missing stable anchors;nowo:manual:stamp es 02-dashboardrecords that a translation matches its source again - Sanitised and cached: CommonMark + GFM through the Symfony HTML sanitiser, cached per chapter, audience, locale and file version; images served with a sandboxing CSP
- Overridable templates and CSS custom properties (
--nowo-manual-*); 7 locales (en, es, de, fr, it, nl, pt)
Installation
composer require nowo-tech/manual-kit-bundle
// config/bundles.php return [ Nowo\ManualKitBundle\NowoManualKitBundle::class => ['all' => true], ];
Quick start
- Import the routes and publish the stylesheet (
bin/console assets:install):
# config/routes/nowo_manual_kit.yaml nowo_manual_kit: resource: '@NowoManualKitBundle/Resources/config/routes.php' prefix: /manual trailing_slash_on_root: false # the home is /manual, not /manual/
- Write the manual (the defaults read
docs/manual):
# docs/manual/manifest.yaml chapters: - { slug: README } - { slug: 01-getting-started, group: using, tags: [start, onboarding] } - { slug: 02-administration, group: administration, audience: admin }
<!-- docs/manual/01-getting-started.md --> # Getting started <a id="first-steps"></a> ## First steps <!-- tags: sign in, login --> 
- Frame it in your layout and link to it:
# config/packages/nowo_manual_kit.yaml nowo_manual_kit: layout: 'base.html.twig' # blocks: title, stylesheets, body docs_url: 'https://github.com/acme/app/blob/main/docs/'
<a href="{{ manual_href('manual/01-getting-started.md#first-steps') }}">Help</a>
Full guide: docs/INSTALLATION.md · options: docs/CONFIGURATION.md · writing and translating the manual, templates, lightbox, search, commands: docs/USAGE.md.
Requirements
- PHP
>=8.4 <8.6 - Symfony 7.4, 8.0, and 8.1+
- FrameworkBundle, TwigBundle, SecurityBundle (security-core), HtmlSanitizer, Yaml,
league/commonmark^2.6 - Optional:
nowo-tech/search-kit-bundle^1.1 (Manual group in the header search),@hotwired/stimulusin the application (figure lightbox)
Version information
| Version | PHP | Symfony | Status |
|---|---|---|---|
| 1.x | 8.4 – 8.5 | 7.4, 8.0, 8.1+ | Supported (bug and security fixes) |
Demo
A Symfony 8.1 demo runs on FrankenPHP (worker mode by default); it needs no database:
make -C demo up
# Demo started at: http://localhost:8177
Sign in as demo / demo (member) or admin / admin, open Manual, zoom the figure and switch to Español.
See demo/README.md and docs/DEMO-FRANKENPHP.md.
Playwright end-to-end tests: make -C demo/symfony8 test-e2e (see docs/CONTRIBUTING.md).
Documentation
- Installation
- Configuration
- Usage
- Contributing
- Code of Conduct
- Changelog
- Upgrading
- Release
- Security
- Engram
- Spec-driven development
- GitHub Spec Kit
Additional documentation
- Templates
- Architecture
- PSR evaluation
- Coverage policy
- Demo FrankenPHP
- FrankenPHP worker audit
- GitHub CI
- GitHub About
Tests and coverage
- Tests: PHPUnit (unit, integration, functional), Vitest (the Stimulus peer), Playwright (demo e2e)
- PHP: 100%
- TS/JS: 100%
- Python: N/A
PHP line coverage: 100% of includable src/ (gate ≥ 99%). TypeScript: Vitest thresholds 100% statements /
branches / functions / lines on src/Resources/assets/stimulus-peers (make gate ≥ 90%).
make test
make test-coverage
make test-ts
make qa
License
MIT © 2026 Héctor Franco Aceituno / Nowo.tech
