What's new in v0.1.0

v0.1.0 May 20, 2026

First tracked release. Early beta. Earlier history not recorded — see git log for changes prior to release-tracker adoption.

Filament DAM — Documentation

Filament DAM — Enterprise Digital Asset Management for Filament

Latest Version PHP Version Filament Laravel Tailwind Tests License

A comprehensive Digital Asset Management plugin for Filament v4 and v5 and Laravel 12, built as a premium layer on top of codenzia/filament-media. It competes with enterprise DAM platforms like Pimcore, Bynder, and MediaINFO while staying 100% native to the Filament ecosystem — no iframes, no service-proxy hacks, no external control planes.

Why this exists. Most "DAM" Filament plugins stop at uploads + folders. Real DAM begins where that ends: renditions per channel, brand portals for stakeholders, rights tracking with expiry alerts, smart collections that keep themselves current, AI enrichment, duplicate hunting, analytics, and first-class distribution. This package delivers all of that behind a handful of pages and services you can lean on from day one.

Try it live: A working integration is included in the Codenzia plugins demo at /admin/demo/dam.


Table of Contents


Highlights

  • Enterprise feature parity — renditions, portals, rights, smart collections, analytics, AI enrichment.
  • Filament v4 and v5 native^4.0 || ^5.0 in one codebase; property types and namespaces follow the v4/v5 conventions documented in Codenzia's engineering standards.
  • Tailwind v4 CSS-first@theme and @source driven stylesheet, no tailwind.config.js, compiled via PostCSS + esbuild into resources/dist/.
  • SDUI / Schemas-first — all layout built with Filament\Schemas\Components; Actions extend Filament\Actions\Action.
  • Feature-flagged — every module toggles via config/filament-dam.php, so you pay only for what you enable.
  • Public surfaces — brand portals, share links, embed routes, oEmbed JSON endpoint, and on-demand rendition delivery ship out-of-the-box.
  • No raw SQL — Eloquent models, relationships, and scopes throughout, with typed returns.
  • Tested with Pest v3 — enum behaviour, model scopes, service logic, focal geometry, smart-collection queries, and duplicate hashing are covered.

Feature Matrix

Category Capabilities
Renditions Auto-generate variants (WebP, AVIF, JPEG, PNG) per output profile with configurable dimensions, quality, and transformation pipeline.
Focal Points User-defined focal-point cropping that preserves the area of interest across any target aspect ratio.
Brand Portals Branded, public-facing asset galleries with password protection, expiry dates, per-portal colors, logo, and custom CTA.
Share Links Expirable, password-protectable download links with max-downloads caps and audit logs.
Rights Management License templates (Royalty Free, Rights Managed, Creative Commons, Editorial, Internal, Custom), per-asset rights, territory enforcement, expiry alerts.
Smart Collections Saved-search collections that auto-resolve to matching assets (type, tags, metadata, size, date).
AI Enrichment Tag suggestions, descriptions, alt text via Anthropic Claude or OpenAI GPT-4o.
Duplicate Detection Perceptual aHash (Hamming distance) + byte-for-byte file-hash for exact matches.
Color Extraction k-means dominant palette per image.
Metadata Extraction EXIF + IPTC + GPS → structured JSON column.
Usage Tracking Polymorphic where-is-this-used tracker with orphan detection.
Embeds Tokenised iframe embed + oEmbed JSON endpoint for external distribution.
Analytics Storage, uploads, downloads, top assets, license expiry — surfaced via widgets and a service API.
CDN Ready Point config.cdn.url at your CDN; rendition URLs and delivery service rewrite automatically.
Feature Flags Every module can be disabled individually.

Requirements

Dependency Version Notes
PHP ^8.3 Strict typing + promoted constructor properties.
Laravel ^12.0 Resolved via orchestra/testbench for tests.
Filament ^4.0 || ^5.0 Dual support — same package, both majors.
codenzia/filament-media ^0.1 || dev-main Upload, folders, tags, versions, search.
intervention/image ^3.11 Rendition + transformation pipeline.
spatie/laravel-package-tools ^1.17 Install command, asset publishing.
ext-gd required Image resize, k-means palette, aHash.

Optional peers (unlocked when installed):

  • laravel/scout — full-text search with Meilisearch or Typesense.
  • league/flysystem-aws-s3-v3 — S3 storage for renditions and originals.
  • codenzia/filament-workflow — approval workflows for publishing assets.

Installation

Run the install command (interactive — publishes config + migrations):

…or do it manually:

Register the plugin on your Filament panel provider:

There are two registration modes depending on which media-file model your app uses.

Mode 1 — Layered (default, recommended)

Your app uses Codenzia\FilamentMedia\Models\MediaFile. Register both plugins:

Plugin IDs are unique (filament-media / filament-dam) so they coexist in the same panel. To toggle the basic media manager and settings pages, use FilamentMediaPlugin::make()->showMediaManager(false) / ->showSettings(false).

Mode 2 — DAM-as-unified (opt-in)

Your app uses Codenzia\FilamentDam\Models\MediaFile (DAM's own model — has saved searches, store panel, batch import). Do not register FilamentMediaPlugin — opt in to DAM owning the media-manager UI:

Use this mode when you reference Codenzia\FilamentDam\Models\MediaFile directly in your application code. Registering FilamentMediaPlugin alongside in this mode would cause both plugins to fight for the /admin/media route.

Show toggles

Every show* method on FilamentDamPlugin takes a boolean — pass false to hide the corresponding panel page without touching your config. Defaults:

Toggle Default Currently registers Notes
showSettings() on DamSettings page DAM Settings (separate from Media Settings)
showSmartCollections() on DamSmartCollectionResource Gated on smart_collections feature
showSubscriptionPlans() on DamSubscriptionPlanResource + UserSubscriptions page Gated on subscriptions feature
showMediaManager() off Pages\Media (when opted in) Mode-2 opt-in
showMediaSettings() off Pages\MediaSettings (when opted in) Mode-2 opt-in
showDashboard() on (no-op, reserved) Toggle exists for forward-compat; page not yet wired
showAssetBrowser() on (no-op, reserved) Toggle exists for forward-compat; page not yet wired
showPortals() on (no-op, reserved) Will gate BrandPortals page once wired
showLicenses() on (no-op, reserved) Will gate LicenseManager page once wired
showProfiles() on (no-op, reserved) Will gate OutputProfiles page once wired

The asset-detail page (/admin/view-asset) is always registered when the plugin is loaded — no toggle needed since it has no nav entry and is reached only via direct link. Widgets (ExpiringLicensesWidget, SubscriptionStatsWidget, StorageSpaceChartWidget, TopAssetsWidget, UploadTrendsWidget, SubscriptionsWidget) register automatically when their respective features (rights_management, subscriptions, analytics) are enabled in DAM's feature config.


Quick Start

That's the 30-second tour. Read on for the modules you actually want.


Configuration

All configuration lives in config/filament-dam.php. The headline knobs:

Feature Flags

Toggle any module without touching code:

AI

Tip. To use Claude 4.6 / 4.7, just update providers.anthropic.model. The provider abstraction inside AutoTaggerService doesn't care which specific model you point it at.

Renditions

CDN

Notifications

Route Prefixes

Every public surface's URL prefix and middleware are configurable:

Default Output Profiles (seeded)

Navigation


Architecture

The split is deliberate: teams that only need a media manager stay lean with filament-media; teams that need a full DAM add filament-dam on top without rewriting their upload pipeline.


Database Schema

Fourteen tables ship with this package, plus six columns added to media_files.

Table Purpose
dam_profiles Output profile definitions (Thumbnail, Social Media, Website Hero, …).
dam_renditions Generated variants per file + profile (path, size, mime, dimensions).
dam_focal_points User-defined focal points (x, y in 0.0–1.0).
dam_portals Brand portal configurations (name, slug, brand color, logo, password, expiry).
dam_portal_assets Portal ↔ media file pivot with ordering.
dam_share_links Shareable download tokens (password, max downloads, expiry).
dam_download_logs Download tracking / audit (IP, UA, link, file).
dam_licenses License template definitions (type, attribution, territories).
dam_asset_rights Per-asset license assignments (cost, photographer, agency, expiry).
dam_usage_records Polymorphic where-is-this-used tracking.
dam_smart_collections Saved search criteria (pinned, notify-on-match).
dam_embeds Embed / oEmbed configurations per file.
dam_enrichment_jobs AI processing status queue.
dam_analytics_events Generic event tracking.

Columns added to media_files:

Column Type Purpose
dam_status string draft / in_review / approved / published / archived / rejected.
color_palette json Dominant colors extracted via k-means.
perceptual_hash string aHash for duplicate detection.
ai_description text AI-generated long description.
ai_tags json AI-suggested tags (pre-apply).
exif_data json Structured EXIF + IPTC + GPS.

Modules

Renditions & Output Profiles

Define output profiles (channels) once, generate renditions on demand or eagerly.

Transformation Pipeline

Any profile can chain transformations — each step maps to the TransformationType enum:

Supported transformations: resize, crop, focal_crop, watermark, format_convert, quality, blur, sharpen, grayscale, rotate, flip, brightness, contrast. Each exposes requiredParams() and affectsDimensions() so you can build editor UI against the enum.

On-demand delivery URL

Renders (or serves the cached copy of) the requested rendition, honouring the cdn.url override when set.


Focal Point Cropping

Give editors the ability to declare "this is the important area" — the crop pipeline honours it for every target aspect ratio.

A lightweight Alpine component (damFocalPicker) ships in resources/js/filament-dam.js for click-to-set focal-point UIs — see Front-end Build (Tailwind v4) for how to bundle it.


Brand Portals

Curated, public, branded galleries — the modern "Google Drive link" for brand assets.

Portals respect expires_at, optional password, and per-portal download allowance. All visits can be surfaced through the analytics module.


Share Links

Trackable, expirable, password-protectable file links — purpose-built for client previews, contractor handoff, and one-time review cycles.

Downloads are throttled (throttle:30,1) and logged in dam_download_logs — every byte out of the door is auditable.


Rights & License Management

Treat licensing as a first-class citizen, not a metadata field.

Each LicenseType declares whether it requiresExpiry() or requiresAttribution(), so form validation and UI hints stay in sync with licensing reality.


Smart Collections

Saved-filter collections that always reflect the current library state.

Pinned collections bubble to the top of the panel nav; notify_on_match lets downstream listeners react (e.g. Slack when a new product hero hits the library).


AI Enrichment

Claude or GPT-4o, behind one abstraction.

Batch from the CLI:

Config.ai.auto_enrich_on_upload + enrichment_tasks let you fire metadata / color / hash extraction automatically when files land.


Duplicate Detection

Both exact and perceptual.

duplicates.threshold in config sets the default Hamming distance (5 = visually similar, 0 = identical).


Color Extraction

k-means dominant palette — handy for design systems, product-page color matching, and visual search.

Palettes live on media_files.color_palette (JSON) once extracted.


Metadata Extraction

Full EXIF, IPTC, and GPS — no manual parsing.


Usage Tracking

Polymorphic "where is this used" tracking — indispensable for cleanup and impact analysis.

The HasDamAssets trait wires deleting automatically, so tracked usage is cleared when a host model is deleted.


Embeds & oEmbed

Embeddable iframes + oEmbed JSON for consumption by external editors (Notion, Ghost, Contentful, etc.).


Analytics

Each of these feeds one of the shipped widgets.


Eloquent Trait — HasDamAssets

Drop the HasDamAssets trait on any model that owns assets. It extends HasMediaFiles with DAM-specific helpers:

The trait registers a deleting hook that removes usage records automatically, so no stale "this is used by Product 42" rows after deletes.


Artisan Commands

Command Description Recommended Schedule
dam:generate-renditions Generate renditions for media files (by profile / file, or bulk). Queue on upload or run nightly.
dam:enrich Run AI enrichment + metadata / color / hash extraction. On-demand or backfill.
dam:check-expiry Notify about expiring licenses, share links, and portals. Daily.
dam:cleanup Delete expired share links and trim old analytics events. Weekly.

Suggested routes/console.php:


Events

Event Fired When
RenditionGenerated A new rendition is saved to disk.
AssetStatusChanged Asset status transitions (draft → in_review → approved → published → archived / rejected).
AssetEnriched AI enrichment completes for a file.
AssetShared A share link is created.
AssetDownloaded A share link or direct download fires.
LicenseExpiring A license crosses one of the configured expiry_thresholds.

Enumerations

Every enum implements the Filament contracts (HasLabel, HasColor, HasIcon where meaningful) so you can reference them from forms, tables, and infolists without hard-coding strings or colors.

Enum Cases Notable Methods
AssetStatus Draft, InReview, Approved, Published, Archived, Rejected allowedTransitions(), canTransitionTo()
LicenseType RoyaltyFree, RightsManaged, CreativeCommons, Editorial, Internal, Custom requiresExpiry(), requiresAttribution()
TransformationType 13 cases (Resize, Crop, FocalCrop, Watermark, FormatConvert, Quality, Blur, Sharpen, Grayscale, Rotate, Flip, Brightness, Contrast) requiredParams(), affectsDimensions()
RenditionFormat Webp, Avif, Jpeg, Png Format metadata (mime, extension).

API / Routes

Public Routes

Method URL Description
GET /dam/portal/{slug} View a brand portal.
POST /dam/portal/{slug}/auth Submit portal password.
GET /dam/share/{token} View a shared file.
POST /dam/share/{token}/auth Submit share-link password.
GET /dam/share/{token}/download Download shared file (throttled 30/min).
GET /dam/embed/{token} Embed iframe view.
GET /dam/embed/{token}/oembed oEmbed JSON endpoint.
GET /dam/rendition/{fileId}/{profileSlug} On-demand rendition (throttled 60/min).

All prefixes (dam/portal, dam/share, dam/embed) and middleware stacks are configurable in config/filament-dam.php.


Panel Pages

Page Purpose Feature Flag
DamDashboard At-a-glance tiles linking to every module. — (core)
AssetBrowser Filterable grid of every asset (search, status filter, type filter, tag filter). — (core)
BrandPortals CRUD + share UI for brand portals. portals
LicenseManager Licenses, per-asset rights, expiry monitoring. rights_management
SmartCollections Criteria builder + live match counts. smart_collections
OutputProfiles Profile CRUD + transformation pipeline editor. renditions
DamSettings Feature flags, AI, CDN — all editable via the panel. — (core)

Each page is a standalone Filament\Pages\Page subclass with a Livewire-driven schema, so you can extend or replace any of them in your app-level panel.


Widgets

Widget Type Description Feature Flag
UploadTrendsWidget Line Chart 30-day upload trend. analytics
TopAssetsWidget Table Most downloaded assets. analytics
ExpiringLicensesWidget Stats Overview Expired and expiring license counts. rights_management

Widgets self-register via the plugin when the relevant feature flag is on.


Front-end Build (Tailwind v4)

This package uses Tailwind v4's CSS-first configuration — no tailwind.config.js anywhere.

Build commands

Under the hood:

  • build:stylesnpx tailwindcss -i resources/css/filament-dam.css -o resources/dist/filament-dam.css --postcss --minify
  • build:scriptsnode bin/build.js (esbuild bundle, IIFE, ES2020, tree-shaken, minified)
  • PostCSS@tailwindcss/postcss plugin (see postcss.config.cjs)

How assets are wired

When resources/dist/filament-dam.css (or .js) exists, FilamentDamServiceProvider::registerFilamentAssets() registers them with Filament's asset system — they'll be injected into every panel that loads this plugin. If the files don't exist yet (e.g. fresh install without a build), the provider silently skips registration — everything else still works.

Theme tokens

The stylesheet exposes a small set of tokens under @theme:

Override them in your app's theme.css to re-skin DAM surfaces without forking the package.


Filament v4 vs v5 Compatibility

This package ships with one codebase that satisfies Filament v4 and v5. Key compatibility rules (applied everywhere):

  • Property types follow the v4/v5 union form — string|\BackedEnum|null $navigationIcon, string|\UnitEnum|null $navigationGroup.
  • Pages use non-static protected string $view (v4/v5 broke static).
  • Layout / Sections / RichEditor live under Filament\Schemas\Components\*, Actions under Filament\Actions\Action.
  • Tables use ->recordActions(…) instead of the removed ->actions(…), and ->schema(…) instead of ->form(…).
  • No bulkActions() / toolbarActions() / BulkActionGroup / DeleteBulkAction — those classes no longer exist in v5.
  • Placeholder::make() replaced with TextEntry::make()->state().
  • Form fields hide labels via ->hiddenLabel() (NOT on filters/summarizers — they keep ->label('')).
  • callable $set in afterStateUpdated(…) replaced with Filament\Schemas\Components\Utilities\Set $set.
  • The unique() validation rule includes ignoreRecord: true by default in v5 — we don't re-specify it.
  • Filament\Support\Icons\Heroicon enum is used for icons, not raw strings.

See Codenzia's engineering standards (CLAUDE.md) for the full v3 → v4/v5 migration delta.


Extending

Custom AI Provider

Custom Transformation

Extend TransformationPipeline and register your subclass as a singleton — every RenditionService::generate() call goes through it.

Custom Notification Recipients

Custom Rendition Storage

Swap the rendition disk in config/filament-dam.php (renditions.disk / renditions.path) — point it at S3 for CDN-backed delivery and set cdn.url to rewrite public URLs.


Performance Notes

  • Renditions are lazy by default. Flip renditions.eager to true when upload latency is less important than first-view latency.
  • Rendition URLs are cached. Once generated, the file path is resolved from dam_renditions without re-running the pipeline.
  • Analytics queries use simple aggregates against indexed columns — no N+1 joins, safe to call from dashboard widgets on every page load.
  • Smart collections resolve against the media_files table with eager-loaded tags. Large libraries benefit from MySQL FULLTEXT / Meilisearch via laravel/scout.
  • Duplicate detection stores perceptual_hash on each file; library-wide scans are O(n²) on the hash column only — for >100k files, run scanAll(limit: …) in batches.
  • CDN rewrites happen in DistributionService — no runtime branching at the blade layer, so template caching stays effective.

Security Considerations

  • Share tokens are 40-char random strings. Treat them as bearer credentials — don't paste them in ticket systems without scoping.
  • Portal & share passwords are hashed with bcrypt via Illuminate\Support\Facades\Hash.
  • Download endpoint is rate-limited to 30/min per IP (throttle:30,1).
  • On-demand rendition endpoint is rate-limited to 60/min per IP.
  • Public routes mount under web middleware by default — CSRF-protected for POST, session-backed for password entry.
  • No env() in runtime code. API keys live in config/filament-dam.php and are referenced via config('filament-dam.ai.providers.…').
  • Authorization hooks. Panel actions use ->authorize('ability') — wire them to your Gate / Policy layer per module (see each page class).

Testing

The suite uses Pest v3 and currently covers:

  • All enum methods, transitions, and derived metadata.
  • Model relationships, casts, and scopes (portals, share links, rights, smart collections, embeds, analytics events).
  • Service business logic (rendition generation, share expiry, rights checks, focal-point math, smart-collection resolution, k-means color extraction, aHash computation).
  • Route registration and middleware wiring.
  • Filament page smoke tests (Livewire::test(PageClass)).

When adding a model or service, generate a smoke test beside it — the tests/Unit/Models/ and tests/Unit/Services/ directories show the expected shape.


Troubleshooting

"Class Filament\Actions\Action not found" — you're on Filament v3. This package targets v4/v5; upgrade or pin to an older tag.

Renditions return 404 — run php artisan storage:link and verify renditions.disk / renditions.path both exist on that disk.

AI enrichment returns empty arraysai_enrichment feature flag is off by default. Enable it in config/filament-dam.php and set an API key under ai.providers.<provider>.api_key.

EXIF / IPTC comes back emptyext-gd is required; ext-exif is recommended. Confirm both with php -m.

Perceptual-hash mismatches — remember the threshold is Hamming distance on the aHash bitstring. 0 = identical, ≤ 5 = visually similar, > 10 = probably unrelated. Tune duplicates.threshold for your library.

Filament v5 panel doesn't show DAM nav — make sure your panel's navigation()->registerNavigationGroups() doesn't override the DAM group that this plugin registers. The plugin adds pages via $panel->pages(); groups are inferred from navigation.group.

Compiled CSS / JS not loading in admin — run npm install && npm run build once. The service provider only registers Css::make() / Js::make() when the dist files exist.


Roadmap

  • Approval-workflow integration with codenzia/filament-workflow (draft → review → publish gates).
  • Per-portal analytics (visit counts, asset heatmaps).
  • Variant A/B testing for renditions.
  • Vector-embedding search (bring-your-own-provider).
  • Bulk rights assignment + CSV import.
  • Livewire-native focal-point editor page (the Alpine helper is already shipped).

Vote / request items via GitHub Issues.


Contributing

Contributions are welcome — issues, ideas, and PRs.

Local setup:

Before opening a PR:

Follow the project-level CLAUDE.md engineering standards — strict typing, promoted constructor properties, Filament Schemas / Actions, Tailwind v4, no raw SQL, no env() outside config.


Changelog

See CHANGELOG.md for the release history.


Credits


License

Dual licensed under the MIT License (for OSI-approved open-source projects) and a commercial license (for proprietary / SaaS / closed-source use).

See LICENSE.md for the full terms and commercial-licensing contact details.


Built with pride by Codenzia for the Filament ecosystem.

Powered by Codenzia
✓ Thanks! We read every message.