Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Laravel Knowledge Base Laravel Package

jeffersongoncalves/laravel-knowledge-base

A Laravel package for adding a searchable knowledge base or help center to your app. Organize articles into categories, publish content, and help users find answers fast, with a ready-to-use structure for managing docs without leaving Laravel.

View on GitHub
Deep Wiki
Context7

Getting Started

  • Install with composer require jeffersongoncalves/laravel-knowledge-base, publish the config and migrations, then run php artisan migrate.
  • Look first at config/knowledge-base.php. In v2.1 the important keys are attachments.disk, attachments.route.enabled, attachments.route.prefix, attachments.route.middleware, attachments.route.signed_url_minutes, and attachments.route.cache_max_age.
  • Then read the package route registration and asset controller. The route is GET /knowledge-base/assets/{uuid}/{name} with name knowledge-base.assets.show; it resolves the asset, checks the owning article's visibility on every request, and either serves a public cacheable response or requires a valid signature.
  • Your first use case should be a public help-centre article with a screenshot:
    1. Create an article with public visibility.
    2. Upload the file to the configured attachments.disk.
    3. Store the returned asset UUID and original name.
    4. Render route('knowledge-base.assets.show', ['uuid' => $asset->uuid, 'name' => $asset->name]).
    5. Confirm the response is served through the package route, not /storage/..., and that Cache-Control reflects cache_max_age.
  • For an internal article, use the same asset record but render a signed URL. Test that a plain URL returns 404 and a valid signed URL works, then that the signed URL stops working after signed_url_minutes.
  • If you are upgrading from 2.0, run php artisan kb:move-assets --dry-run before anything else. Set attachments.disk to local or a private cloud disk, run the real move, then confirm old /storage/... URLs are gone if the content needs revocation.

Implementation Patterns

  • Centralise asset URL generation. Do not scatter route() and URL::temporarySignedRoute() calls through Blade templates. Put a small presenter, model accessor, or Blade component in front of it so visibility logic is in one place. If the package already exposes an accessor on the asset model, use that and wrap it rather than duplicating its rules.
  • Resolve assets at render time, not at save time. The biggest workflow trap is storing a signed asset URL inside article HTML or Markdown. A signed URL expires after signed_url_minutes; the article body then contains dead links. Store an asset reference such as kb-asset://{uuid}/{name}, a shortcode, or a relation ID, and resolve it to the correct public or signed URL when the article is rendered.
  • Keep public and internal rendering on the same path. A public article should get a plain, cacheable URL. Internal, draft, archived, and hidden articles should get a signed URL. If you build your own URL helper, branch on the article visibility, not on the current user, because the route performs its own visibility check and returns 404 for non-public articles without a valid signature.
  • Configure route middleware intentionally. attachments.route.middleware applies to the whole asset route. Adding auth protects every asset, including public article images, which may be undesirable for a public knowledge base. If you need both public and internal assets, leave the route open and rely on visibility plus signatures; use your own authorisation only for the admin upload and article-edit flows.
  • Use a private disk, including S3. Set attachments.disk to local or a private S3-compatible disk. The package route proxies the file, so Storage::url() is not the correct public API. For S3, do not make the bucket public; let the route serve the bytes or redirect according to the package implementation.
  • Treat CDN caching as part of the security model. Public article assets are intended to be cacheable for cache_max_age seconds. If an article later becomes internal, browser and CDN copies can still be served until that TTL expires. Lower cache_max_age on sites where visibility changes are common, and wire a CDN purge into the article visibility-change workflow.
  • Plan the 2.0 to 2.1 migration as a storage migration. Publish the config, set the private disk, run kb:move-assets --dry-run, review the file list, take a storage backup, then run the real command. After moving, verify that the old public disk no longer serves the files at /storage/...; otherwise you have the new route and the old public URL both working, which defeats the revocation improvement.
  • Test with fake disks. Use Storage::fake(config('knowledge-base.attachments.disk')) in feature tests. Assert route status codes, Cache-Control headers for public assets, 404s for unsigned internal assets, successful signed requests, and expiry using $this->travel() past signed_url_minutes.
  • Use kb:move-assets in deploy runbooks, not ad hoc. For large libraries, run the dry run in staging, capture counts, run during low traffic, and verify a sample of public and internal article assets afterwards. If your infrastructure uses multiple app servers, make sure the target disk is shared or remote before moving.

Gotchas and Tips

  • Old public URLs survive the upgrade by default. The release notes are explicit: existing assets keep working through the new route, but files still on the public disk remain reachable at their old /storage/... URL. If an article is internal, that old URL bypasses the visibility check. Move the files and remove public access if revocation matters.
  • Cached HTML can outlive a visibility change. A page cached by a CDN, full-page cache, or browser may contain a public asset URL after the article becomes internal. The route will enforce the new visibility when hit directly, but the cached URL may still be served from cache for up to cache_max_age. Set a low TTL for sensitive content and purge on visibility changes.
  • Signed URLs in stored content expire. Do not persist URL::temporarySignedRoute() output in article bodies, database columns used for rendering later, or sitemap files. Store the asset identifier and sign at request time.
  • attachments.route.enabled = false is not a safe "do nothing" upgrade. It preserves 2.0 behaviour, which means public disk URLs. That is fine only if you intentionally want public assets. If you set attachments.disk to a private disk while disabling the route, your assets will not be reachable through the package and will not be publicly reachable either.
  • Changing the route prefix breaks every stored asset URL. attachments.route.prefix changes the path but not the route name. If you change it after launch, previously rendered HTML, CDN caches, and external links to assets will 404. Clear route and config caches after changing it.
  • Route middleware is coarse-grained. Adding auth to attachments.route.middleware means anonymous readers cannot load images in public articles. If you need mixed public/internal access, keep the asset route open and put authorisation on the article and upload endpoints instead.
  • Do not trust the {name} route segment for filesystem access. The UUID should resolve the asset; the name segment is for display, download filenames, and URL readability. Sanitise and encode names with spaces or non-ASCII characters, and never concatenate {name} into a disk path.
  • kb:move-assets needs the correct disk configured first. Run it after publishing config and setting attachments.disk. Confirm whether your version moves or copies files; if it copies, delete the originals from the public disk manually and verify the old URLs return 404.
  • Use the dry run and check for collisions. Asset names may collide across articles. The UUID should keep storage paths unique, but review the dry-run output for overwrites, missing files, or records whose disk path does not match the expected package convention.
  • Multi-server deployments with local disk will break. A file uploaded on one app server will 404 when the asset route is handled by another. Use S3 or a shared volume, or route asset requests consistently.
  • Route and config caching matter. After changing attachments.route.*, run php artisan config:clear and php artisan route:clear; after deployment, re-cache. With Octane, reload workers so config changes take effect.
  • Do not use Storage::url() for private assets. It will produce a path that either does not exist or bypasses the package route. Always generate the package route or a signed package route.
  • Test revocation explicitly. A useful regression test is: create a public article asset, request it unsigned and expect 200; change the article to internal; request the same unsigned URL and expect 404; request a valid signed URL and expect 200; travel past signed_url_minutes and expect 404. That test catches most misconfigurations in this release.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console
pnscripts/filament-broadquill-lite
pnscripts/laravel-sentfold-lite
vleap/mx-sdk-laravel-internal
twidpay/utils
htetmyathlaing/scout-elasticsearch-driver
artisan-toolbox/front-awesome
ls/client-assistant
users-au/laravel-client
cgv/localized-resource
noith/settings
kda/laravel-package
kda/filament-dynamic-navigation
bypersoft/signbox
pairus/product-data
fayne/laravel-filament-cms-core
nodisrupt/laravel-agent
sierratecnologia/media-manager