pushword/page-scanner
Pushword Page Scanner helps you crawl and inspect your site’s pages, making it easy to surface broken links, missing content, and other page-level issues so you can keep your website clean, reliable, and user-friendly.
Architecture fit. Despite the package label "Laravel/PHP package," the repository is Pushword, a Symfony CMS, distributed as a monorepo of Symfony bundles (core + extensions) rather than a Composer library you require into an existing app. That distinction drives the whole evaluation: its integration surface is a Symfony application (kernel, bundles, Twig, EasyAdmin, Doctrine), not a Laravel service provider. The package name pushword/page-scanner does not match the repository description, so scope is unconfirmed — we must clarify whether we are evaluating a page-scanning capability or the entire CMS platform. Until then, plan against the full CMS.
Key architectural facts a TPM should have on record:
doctrine:schema:update --force. This is a deliberate design choice, not an oversight, and it has direct production implications (no versioned schema history, no clean rollback).AGENTS.md files document the seams.var/cache/pushword-pools, which intentionally survives deploys and is invalidated only via MarkdownParser::CACHE_VERSION (and SplitContent::TOC_CACHE_VERSION for TOCs). Static builds additionally skip unchanged pages, and both mechanisms depend on byte-deterministic renders.dist is what ships, so admin customization is a source-build-and-rebuild workflow, not a config change.--format=agent (compact single-line JSON) via AgentOutputTrait; docs ship downstream as vendor/pushword/docs/AGENTS.md. This is genuinely unusual and relevant if we intend to drive the CMS from automation.Integration feasibility. Under a Laravel stack, a direct integration is not feasible; EasyAdmin, Twig, Symfony routing/security, and Doctrine have no bridge to Laravel's Eloquent/Blade/HTTP kernel. Realistic options are: (a) run Pushword as a separate Symfony service and consume its output over HTTP or as a published static build, (b) treat it as a reference implementation for a content pipeline we build ourselves, or (c) only adopt it if the surrounding platform is Symfony. Within Symfony, integration is feasible and conventional: bundle registration, Doctrine connection, prebuilt front-end assets.
Technical risk.
schema:update --force in production means no migration ledger; changes are applied destructively against a live database.random()) silently breaks both the pool and the static build's skip-unchanged logic.composer stan, rector, test, deprecation ceilings (max[self]=0&max[direct]=0), and a mandatory post-change review with scoped commits. That is a disciplined repo, which materially offsets some ecosystem risk.Key questions.
page-scanner relative to the CMS — a sub-package, a feature, or a naming error? This changes effort by an order of magnitude.upgrade/<version>.md note per release)?--force acceptable to our DBAs?Stack fit. Treat Pushword as a content service, not a dependency. There are two viable shapes:
The satellite pattern is the recommendation for a Laravel shop; the Symfony-hosted pattern is correct only if Symfony is already present.
Migration path. There is no incremental adoption path from Laravel — this is greenfield deployment of a second runtime. Content migration is tractable because Pushword accepts content from Git as a first-class source, so existing Markdown can be brought in as files before any admin authoring begins. Media and redirects need mapping (the docs indicate redirects are row-based, which is a signal that URL continuity is handled explicitly and should be migrated deliberately).
Compatibility. Confirm PHP minor version, Symfony LTS line, and Doctrine DBAL version against our base image before committing. On the database side, choose PostgreSQL over the SQLite default if more than one editor or any concurrent write workload is expected; SQLite is acceptable only for a single-author, read-heavy site.
Sequencing.
page-scanner is; stand up the bundled dev app (packages/dev-app/, composer dev) and produce one page end-to-end.doctrine:schema:update --force against a Postgres clone with a schema change; confirm backup/restore and rollback procedure.dist. Budget it explicitly; do not assume CSS-level tweaks.Pin the upstream version and vendor the built assets; do not track main while the project is single-maintainer.
Maintenance. The absence of migrations is the largest recurring cost: every schema-affecting upgrade must be planned with a manual --force invocation, a pre-change snapshot, and an explicit rollback (restore, not down-migration). Upgrade notes are per-release under upgrade/, so the process is documented — but the burden is on us to execute it. The Markdown pool cache surviving deploys is operationally correct and also a trap: any change to rendered output requires bumping a constant, which means renderer changes are a coordinated deploy, not a hotfix. Cache clears are required after changes (composer console cache:clear) but deliberately do not reach the pool.
Support. With 30 stars and 0 dependents, there is effectively no third-party support market. Upstream is one maintainer; our team is the first line, and a fork is the contingency. Mitigate with a pinned fork in our org, an internal runbook, and a named owner. The upside is a permissive MIT license and a repo whose own quality gates (static analysis, Rector, deprecation ceilings, no-skip test policy) suggest the code will be readable and maintainable by a competent Symfony developer.
Scaling. The scale-out lever is static publishing, which is architecturally sound: the CMS is the write path, the CDN is the read path. Dynamic scaling of the admin/runtime is the constrained path — SQLite caps write concurrency, and the admin depends on prebuilt assets (Monaco is fetched on demand, editor bundles ship as committed dist). Plan for Postgres before multiple editors, and treat the admin as an internal tool that does not need to scale with public traffic.
Failure modes to instrument.
random() in a render path) makes the content hash miss every time, inflating build time rather than corrupting content — a slow, quiet failure. Alert on build artifact count anomalies.Resources/public/, so Monaco's package must build after), and EasyAdmin's form-theme precedence and hidden-panel Monaco mounting (0×0 measurement) are known failure shapes. Any admin change gets a rendered-HTML assertion, not a 200 check.--force run that partially applied.--format=agent; automation built on undocumented commands will break on output-format changes.Ramp-up. A developer strong in PHP but new to Symfony bundles needs roughly 1–2 weeks to be productive and 3–4 weeks to be safe in the admin/EditorJS layer. The shipped AGENTS.md files and per-package extension docs meaningfully shorten this — they are unusually good onboarding material and encode exactly the non-obvious seams (build-time tool registration, form-theme precedence, cache versioning, scoped-commit discipline) that would otherwise cost days. Budget separately for the front-end toolchain (TypeScript, Vite, committed dist), which is a distinct skill from the PHP side.
TPM recommendation. Do not adopt as a platform dependency on current evidence. Run the four-week spike-and-pilot above, behind a clean interface (static output or read API), with a pinned fork. The decision criterion is not code quality — which looks solid — but whether we can absorb single-maintainer risk plus the no-migrations operational model. If page-scanner turns out to be a narrow, separable capability, re-scope this evaluation around it; the cost profile could improve substantially.
How can I help you explore Laravel packages today?