Open-Sourcing notACMS — The Complete Checklist
open-source,php,symfony,static-sitePart 5 of 5
This is part 5 of a series on preparing notACMS for open-source release. Part 4 covers the local override pattern. The original WordPress to Symfony series covers the migration itself.
I spent a month preparing my personal website's codebase for open-source release. Not because I expected thousands of contributors — but because going public forced me to write the docs, add the tests, fix the security issues, and make the architecture actually reusable. The code that's good enough to show strangers is better code than the code that isn't.
Here's the complete checklist.
Why Open-Source a Personal Project?
Accountability — code you'll show the world is better code. Documentation discipline — you write docs when strangers might read them. And the ultimate refactoring exercise: would you be proud to show this code?
notACMS is a Symfony-based static site generator with no database, no CMS, and no PHP involved in serving content, licensed under Apache 2.0. If someone else can use it, that validates the architecture.
The Audit: 9.5/10 Readiness Score
| Category | Score | Status |
|---|---|---|
| LICENSE (Apache 2.0) | 10/10 | ✅ |
| README | 10/10 | ✅ |
| Documentation (5 docs, 1,227 lines) | 10/10 | ✅ |
| Rector Config | 10/10 | ✅ |
| Code Quality Tools (CS Fixer, PHPStan, Rector, Twig lint) | 10/10 | ✅ |
| Contributing Guidelines | 10/10 | ✅ |
| Security Policy | 10/10 | ✅ |
| CI/CD Workflows | 10/10 | ✅ |
| Issue/PR Templates | 10/10 | ✅ |
| Tests (368 tests, ~80% coverage) | 8/10 | ✅ |
| Hardcoded Secrets (documented in .env) | 10/10 | ✅ |
| CHANGELOG | 10/10 | ✅ |
| Overall | 9.5/10 | Ready |
What Was Missing (and How I Fixed It)
GitHub Actions CI/CD — .github/workflows/ci.yml: PHP 8.5, composer install, validate, audit, Twig lint, Rector dry-run, CS Fixer, PHPStan, PHPUnit. Nothing ships unless all checks pass.
CONTRIBUTING.md — DDEV setup, code style standards, PR process, commit conventions. The barrier to contribution should be one command: ddev start.
SECURITY.md — Supported versions, vulnerability reporting (private disclosure), security update policy. Even for a one-person project, having a defined process matters.
CHANGELOG.md — Keep a Changelog 1.1.0 format, initial release entry. Future releases will track what changed.
Issue/PR templates — Bug report, feature request, PR guidelines. Good templates reduce the cognitive load for both the reporter and the maintainer.
CODEOWNERS — Code ownership tracking. It's one person, but it's good practice and signals that the project is maintained.
Test suite — 368 tests across Unit and Integration, covered in part 1 of this series.
Rector as Automated Refactoring
Rector uses withPreparedSets(codeQuality: true, codingStyle: true, deadCode: true, typeDeclarations: true, symfonyCodeQuality: true) plus withPhpSets(php85: true). Dry-run in CI, --fix in ddev code-fix. What it catches: redundant null checks, array simplification, modern PHP 8.5 syntax, dead code, type declarations. What it skips: ControllerMethodInjectionToConstructorRector — the ErrorController needs runtime values that can't be injected via constructor.
What I Skipped (and Why)
Code of Conduct — It's a one-person project. No community to govern. If that changes, this changes.
Third-party license notices — MIT dependencies don't require attribution in source. Maybe later if the project grows.
100% test coverage — The remaining ~20% is email sending, media copy paths, error controller __invoke. High complexity to trigger, low ROI. 80% covers all public APIs, main code paths, and edge cases.
The Deploy Pipeline
ddev code-check # Composer validate + audit, Twig lint, Rector, CS Fixer, PHPStan
ddev test # 368 tests, 490 assertions
./deploy.sh --prod
The quality gate: nothing ships unless all checks pass. The deploy script runs inside the production PHP container where the correct CPU architecture is known. After the build, nginx is already serving the new static files.
The Result: notACMS
A Symfony-based static site generator, Apache 2.0 licensed, with docs, tests, CI, and a local override pattern. Not a framework — a project template you can clone, customise via local/, and deploy. The entire codebase, content, and configuration fits in a single git repository. Backup is git push.
This series started with 368 tests, went through an AI code review, security fixes, and the local override pattern. After shipping, the next posts cover the build pipeline internals, building a production theme, and search with Pagefind. The original WordPress to Symfony series tells the story of how this codebase came to exist.