traineratwot/filament-openstreetmap
Add a free OpenStreetMap field to Filament forms with Leaflet-powered maps. Pick points visually and save as WKT or arrays, with easy Composer install and publishable assets.
Architecture fit. The package is a thin, well-scoped addition to the Filament form layer rather than a platform: a single form component (MapInput), a value object (Point), an Eloquent cast (PointCast), and a PointFormat enum with 11 output formats. It owns no tables, no service provider logic beyond asset publishing, and no server-side rendering — the map is Leaflet + Alpine in a Blade partial with wire:ignore and $wire.entangle(). That means it slots into the existing Filament resource/forms architecture without touching our domain model or persistence conventions, and it is trivially removable. For a back-office "drop a pin" requirement (store/asset/site/venue coordinates), this is the correct shape of dependency: it replaces roughly the fiddly Leaflet-plus-Livewire-state plumbing we would otherwise build and maintain.
Integration feasibility. Low effort on the happy path: composer require, one vendor:publish --tag=filament-openstreetmap-assets step to place Leaflet under public/vendor/filament-openstreetmap/leaflet/, a nullable string or json column, a cast declaration, and a MapInput::make('point')->saveFormat(PointFormat::WKT) in the resource schema. No npm/Vite pipeline changes, no API key procurement, no per-request billing. The Point value object is independently usable (Point::fromValue() auto-detects formats, distanceTo() returns meters), so it can be reused for import/backfill scripts and non-Filament code paths even if we later swap the UI.
Technical risk. The risk is concentrated in maturity and correctness, not in architecture:
Point stores (lat, lng), but GeoJSON and WKT are (lng, lat). Combined with fromValue() auto-detecting format from string patterns, ambiguous inputs like "37.6173,55.7558" are a live data-integrity hazard. This must be covered by our own round-trip tests before any bulk import.laravel-test/ Laravel 12 + Filament 5 app. No documented CI. We inherit all verification responsibility.$wire.entangle() returning {initialValue, _x_interceptor} rather than a raw value). This is exactly the kind of implementation detail that breaks silently on Filament/Livewire upgrades.Key questions to resolve before commitment:
composer.json constraints pin — PHP upper bound, filament/filament (^3 only, or ^3|^4|^5), Livewire range? The README says ">=3" while the bundled test app is Filament 5; I want that verified against our installed version.title escaped before being rendered in a Leaflet popup, or is it raw HTML? Marker titles sourced from user data would be an injection surface.MapInput enforce requiredness and partial-coordinate validation (lat without lng), and what does it submit on a null/cleared value?en, ru only) overridable via published lang files without forking?PointCast round-tripping across all 11 formats?Stack fit. This is a Filament-only play. If the admin surface is Filament v3+ on Laravel 10/11/12, PHP 8+, it fits cleanly. If any coordinate capture happens in a non-Filament surface (API ingestion, mobile app, console import), only the Point value object carries over — the MapInput does not. It is a single-point picker: no polygons, routes, geofences, or drawing tools, and no built-in address autocomplete beyond the Nominatim search bar. If the requirement is "customer-facing store locator with address search," scope that separately; this package supplies the back-office seed data for it, not the locator itself.
Migration path. Treat adoption as vendoring a component, not taking a dependency:
matanayadev/laravel-eloquent-spatial and PostGIS later; plain lat,lng string is the lowest-commitment choice. Document the coordinate order in the column comment and in the model.Point::fromValue() in a one-off artisan command with a dry-run mode and a rejected-rows report — never trust auto-detection blind.composer.json, commit the published Leaflet assets (or publish deterministically in CI) so deploys are reproducible and don't depend on a writable-during-deploy public/ directory.Compatibility. Validate against our exact Filament/Livewire/PHP matrix in a throwaway branch, not against the package's own test app. Check for collisions in public/vendor/ with other packages, and confirm the @assets block is compatible with our CSP if we enforce one (OSM tile domains and Nominatim must be allowlisted). If we run Filament 4/5, the entangle-based Blade code is the first thing to re-verify.
Sequencing.
Maintenance. This becomes our code the moment it ships. Budget a named owner and roughly 2–4 days per quarter in steady state: patching the vendored Leaflet copy (it is frozen at publish time and will not update itself), re-validating the Alpine/entangle template on every Filament or Livewire upgrade, and re-verifying the asset-publish step. Add PHPStan and PHPUnit coverage ourselves at adoption time — the upstream has neither, so our CI is the only gate. The upstream major-version history (a hard 2.0 break) means upgrades are deliberate, tested events, never a composer update side effect.
Support. There is no vendor, no SLA, and effectively no community — 28 stars and zero dependents means no Stack Overflow corpus and no one else's bug reports to learn from. Support is our on-call and our runbook. Document the two known gotchas prominently for the team: the (lat, lng) internal vs. (lng, lat) WKT/GeoJSON convention, and the Livewire Proxy unwrapping in the Blade template.
Scaling. Read/write load is negligible: one string or JSON column, one row per record, no server-side map rendering. The scaling ceiling is entirely external — OSM tile requests are client-side and governed by the tile usage policy (fine for tens of internal users, not for anonymous high traffic), and Nominatim is capped around one request per second with explicit prohibitions on bulk use. If geocoding becomes a real workflow rather than a convenience, either self-host Nominatim, put a caching proxy in front of it, or swap in a paid geocoder — and budget that decision separately. Spatial querying at scale (radius searches over large tables) requires the matanayadev/laravel-eloquent-spatial bridge plus a geometry column and spatial index; plan the column type with that in mind now, because migrating later is a data migration, not a config change.
Failure modes and mitigations.
Ramp-up. Developer onboarding is roughly half a day for the happy path given the README quality, plus the gotchas above. Ops requires exactly one new pipeline step (vendor:publish with that tag, or a committed-assets strategy) and confirmation that the web user can read the published directory. End users need no training beyond "click the map or type coordinates," but they do need to be told the map is a convenience and the coordinate value is the source of truth. Legal/licensing is a small but real gate: OSM data is ODbL and requires visible attribution, and the package is MIT — both are fine, both should be on the sign-off list rather than discovered post-launch.
How can I help you explore Laravel packages today?