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.
composer require jeffersongoncalves/laravel-knowledge-base, publish the config and migrations, then run php artisan migrate.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.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.attachments.disk.route('knowledge-base.assets.show', ['uuid' => $asset->uuid, 'name' => $asset->name])./storage/..., and that Cache-Control reflects cache_max_age.signed_url_minutes.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.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.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.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.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.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.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.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.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.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.cache_max_age. Set a low TTL for sensitive content and purge on visibility changes.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.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.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.{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.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.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.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.signed_url_minutes and expect 404. That test catches most misconfigurations in this release.How can I help you explore Laravel packages today?