austintoddj/canvas
Canvas is a minimal, elegant publishing platform for Laravel. It adds a distraction-free writing dashboard with posts, tags, and media management, so developers can launch a fast, self-hosted blog or publication without wrestling with a heavyweight CMS.
What the package is. Canvas (austintoddj/canvas) is a batteries-included publishing platform for Laravel — an embedded application rather than a thin library. It ships its own admin UI, routes, controllers, Eloquent models, migrations (prefixed canvas_), config, and publishable views/assets. That single fact drives most of the TPM-relevant conclusions below: adopting Canvas is closer to hosting a small product inside your application than to adding a dependency.
Architecture fit.
Post::forPublicSlug()) that the stock front-end controller must call. If you have published the UI, you own a copy of that controller and are responsible for keeping it in step with the package's contract. That is a small but real expansion of the surface you own.Integration feasibility. High for a greenfield site or an additive /blog section. Medium for retrofitting into an app that already stores content or already owns root-level slug routes. The two recurring friction points are (1) authentication/authorization — Canvas has its own admin access expectations and needs to be reconciled with the host app's user model and admin gate, and (2) route ownership — the package registers front-end routes that can collide with existing slug or catch-all patterns. A third has now been added: (3) controller drift — if you published the UI, the package's slug-resolution fix does not reach you until you either re-publish (destructively) or hand-patch CanvasUiController::show().
Technical risk. Low-to-moderate on code; the dominant residual risk remains bus-factor. This is a single-maintainer package. Mitigate by forking to an internal namespace, pinning versions, and treating the public publishing surface as a bounded context with a thin internal interface so it can be replaced. The slug defects that made 7.2.3 a behavioral patch are now substantively closed by 7.2.5, but the delivery mechanism for the fix (republish-or-patch) introduces a deployment hazard that is arguably more dangerous than the bug it fixes, because it fails silently.
Assessment of v7.2.5 (cumulative from 7.2.3). We are evaluating 7.2.5 against an assessment written for 7.2.3; 7.2.4 is unreviewed — obtaining its changelog is a precondition for scheduling, not a nice-to-have. The trajectory is two consecutive patch releases on the slug subsystem:
post-{uuid}, and left collision behavior opaque — the top residual risk in the prior assessment.Post::forPublicSlug($slug) scope.Both halves are behavior changes in the public URL contract, and neither is a schema or signature break. Concretely:
canvas:ui --force, or hand-edit show(). Teams that run the first two upgrade commands and stop will believe they are patched and are not. This is the single most likely failure mode of this release and it produces no error, no log line, and no failing test.canvas:ui --force is the exact hazard flagged earlier, now on the critical path. It overwrites every locally customized admin view. The mitigation is unchanged (snapshot, publish, diff) but it moves from prudent hygiene to a mandatory gate.Post::forPublicSlug() to the package means your published controller now has a required dependency on a package method that did not exist three patches ago. Anyone who pinned at 7.2.3 and hand-edited show() should not cherry-pick the scope call without the version bump.Key questions.
canvas_posts ourselves? What is the recommended remediation (manual rename) and does it emit a redirect?published_at, created_at, or id, and what happens when the earliest match is later unpublished or deleted — does the URL fall through to the next duplicate?canvas:ui --force overwrite in 7.2.5, and is --force required or prompted?Stack fit. Canvas assumes a conventional Laravel app: standard Eloquent, standard migrations, blade/asset publishing, and an admin surface gated behind the host's auth. It fits cleanly where the host app is a single-tenant Laravel monolith and content is a secondary concern. It fits awkwardly in multi-tenant SaaS (per-tenant blogs require forking or a custom driver), in API-only/headless deployments (you would consume the models but discard the UI — though Post::forPublicSlug() is now a portable piece of that model layer if you go headless), and in apps with strict design-system governance (you inherit its front-end until you own the views).
Migration path.
composer.json (7.2.5), not a floating constraint, given single-maintainer risk.CanvasUiController. This gates the entire upgrade procedure. If yes, the upgrade has four steps, not three.composer update austintoddj/canvas → canvas:migrate → canvas:publish. Capture the schema diff and the publish diff.resources/views/vendor/canvas (or equivalent) before canvas:ui --force, re-publish, then diff. Prefer the surgical alternative — patching show() to call Post::forPublicSlug($slug) — if your admin UI has local customizations you intend to keep.Compatibility. 7.2.5 is not a pure drop-in from 7.2.3 in the operational sense, even though the API surface is additive. Two reasons: the front-end resolution semantics change (duplicate slugs now resolve to the earliest published post rather than whatever the previous lookup returned), and the published-UI path requires an action the first two upgrade commands do not perform. It remains a hard break from 6.x and earlier — validate against the documented Laravel/PHP support matrix before scheduling.
Sequencing.
composer update austintoddj/canvas → canvas:migrate → canvas:publish, with view/config backups taken first.canvas_posts for slugs with more than one row and decide, per cluster, which post should own the URL. Anything you leave alone becomes unreachable at its canonical path after the deploy. Record the decision; do not discover it from a reader complaint.canvas:ui --force against a snapshot, or the forPublicSlug patch — and verify by diff that no unrelated customization was reverted.post- slug assumptions in tests, sitemaps, redirects, and analytics segments (carried over from 7.2.3, still outstanding).Maintenance. Low ongoing code maintenance, moderate ownership maintenance. You are responsible for published views, config drift, and any local patches — and 7.2.5 sharpens this: if the UI is published, you now also own a controller that must be kept in step with a package-internal scope. Budget a recurring review of upstream releases; two consecutive patches have now changed user-visible URL behavior, which is a reminder that semver "patch" does not mean "invisible." The fork-and-track decision should be made at adoption, not at the first blocking upstream change.
Support. Community-supported open source; no vendor SLA. Internal support load concentrates on the admin UI (where editors file tickets) and on upgrades that touch published assets. Two new ticket categories to expect after this release: "my post URL opens a different article" (duplicate-slug residue) and "the collision fix isn't working" (published UI not updated). Designate one engineer as the package owner so upgrades are not orphaned.
Scaling. Two separate concerns. Traffic scaling is a normal Laravel problem — the package adds queries, not architecture; caching and CDN strategy sit in your layer. One note: Post::forPublicSlug() resolves duplicates by ordering candidates, so ensure the column it orders on is indexed at realistic post volumes. Content scaling is where Canvas's own limits surface: large post volumes, many tags/topics, and search all degrade toward needing your own indexing strategy. Neither is urgent at typical blog volumes.
Failure modes.
CanvasUiController::show() on the old lookup; duplicate slugs continue to resolve incorrectly with no error, log, or failing test. Highest-probability failure mode of this release.canvas:ui --force overwriting local admin customizations → cosmetic breakage or reverted admin UI work; caught by diffing against a snapshot taken immediately before.Ramp-up. Engineers familiar with Laravel need roughly a day to be productive in the package's conventions and another day or two to be confident in the publish/override model — and this release adds a specific competence: knowing that "published" means "you now maintain a forked controller." Content editors need a short walkthrough plus, for this release, an explicit note that duplicate titles will acquire a numeric suffix on creation, that they can still edit the slug, and that a small number of older posts may now resolve to a different article. Plan the editor communication alongside the deploy rather than after it.
How can I help you explore Laravel packages today?