aw-studio/fjord
Fjord is a Laravel package for building admin panels and internal tools. Define resources, fields, filters, and actions in PHP, then get a modern Inertia-powered UI for CRUD, authentication, and customization.
Litstack is a Laravel-based admin panel/CMS. v3.8.6 is a patch release with no install changes, so the entry path is the same as any 3.8.x install:
composer require litstack/litstack then run the installer (php artisan litstack:install) — this publishes config/litstack.php, migrations, and the admin assets.php artisan migrate, then create your first admin user (the installer/setup command prompts for credentials)./litstack (route prefix is configurable in config/litstack.php).Where to look first:
config/litstack.php — route prefix, middleware/auth guard, media disk, locale setup, and the cruds array where you register your admin modules.Litstack namespace (typically app/Litstack/…) — generated CRUD controllers live here and are the main extension point.media, pages/posts-style tables, and the settings/taxonomy tables.First use case: scaffold a "Pages" module with a title, slug, WYSIWYG body, and a hero image via a Media field, then render it on the frontend by resolving the model from its own route()-style method. That single flow exercises the three things you'll use daily: CRUD controllers, field definitions, and media handling.
CRUD module per content type. Each module is a controller extending Litstack's base CRUD controller, declaring $model, $name, and a fields() array. Keep field definitions declarative and let Litstack handle validation, ordering, and the Vue form UI. Reach for custom field types only after you've exhausted the built-ins (Text, Textarea, Wysiwyg, Media, Select, Checkbox, Relation/nested fields).
Translatable content. Define fields with the translatable flag and drive locales from config. The admin shows per-locale tabs; your frontend needs to read app()->getLocale() consistently, and you should decide early whether you fall back to the default locale or return 404s — the package doesn't pick that for you.
Media as first-class content. Attach media through Media fields and store foreign keys / pivot rows rather than raw paths, so the media library stays the source of truth. For anything that needs derived assets (thumbnails, crops), register conversions and queue them — don't generate derivatives synchronously in the request cycle.
Mixed media libraries are now safe. v3.8.6 fixes the case where any uploaded media was loaded as an image even when it wasn't. If your Media fields accept PDFs, SVG, video, or archives, thumbnails/previews in the admin now degrade gracefully instead of emitting broken <img> tags. This makes a single shared media library — with images and documents side by side — a viable pattern.
Frontend integration. Keep a thin rendering layer: resolve the entity by slug/locale, eager-load media and relations, and cache the resulting view data. Litstack gives you the content model; the routing/response strategy is yours, which is the right place to apply HTTP caching and static generation.
Settings and navigation are good candidates for a single "globals" CRUD rather than hardcoding them in config — the client can then edit them without a deploy.
php artisan optimize:clear) if you use custom media/field views — stale compiled Blade can mask the fix.Media fields that assumes ->url() is renderable inside <img>, guard it yourself with a mime check.config/filesystems.php, litstack.php's media disk, and your public symlink cause "file exists in admin, 404 on site" bugs that look like a package bug but are config.litstack middleware group still resolves an authenticated user — failures show up as redirect loops rather than an obvious error.How can I help you explore Laravel packages today?