Changelog
All notable changes to Filament Address Pro will be documented in this file.
The format follows Keep a Changelog, and this project adheres to Semantic Versioning.
[1.0.75-beta] - 2026-06-02
Fixed
- Docs: USER-GUIDE.md broken links. The README overview link was labelled "README" (which 404s on the docs site) — changed to "Overview". A relative link to
../config/addresses.phppointed at the raw config file rather than the configuration guide — changed toCONFIGURATION-GUIDE.md.
[1.0.74-beta] - 2026-06-02
Added
- Docs: USER-GUIDE.md added to the docs site. The file was incorrectly excluded as an internal document; it is a 1,152-line user-facing guide and now appears in the docs site sidebar under the Filament Address Pro group after Getting Started.
[1.0.73-beta] - 2026-06-02
Fixed
- Docs: VitePress URL casing. Reverted to uppercase URL destinations — VitePress only rewrites
.md-extension links; bare relative links pass through as-is, so destination paths must match source filename case exactly. - Docs: GitHub-compatible anchor slugify. VitePress default collapses
&to a single hyphen, but the docs' manually authored tables of contents use the GitHub style (double hyphen). A customslugifyfunction now matches the existing anchors.
[1.0.71-beta] - 2026-06-01
Added
- VitePress documentation site live.
docs.viewflex.net/filament-address-pro/is now live on Cloudflare Pages, built from the package repomainbranch. Includes all 19 published docs with uppercase URL paths (matching source filenames) and local full-text search. A "View Docs" button has been added to the viewflex marketing page hero.
[1.0.70-beta] - 2026-05-31
Added
- morphMap support in import and export. The importer now resolves morphMap aliases to class names via
Relation::getMorphedModel()before the entity whitelist check and::find()call — apps that register short aliases (e.g.'user' => User::class) work transparently. The exporter always emits the resolved class name in theentity_typecolumn so exported CSVs round-trip correctly regardless of whether the target instance has the same morphMap configuration. No change required for apps that do not use morphMap.
[1.0.69-beta] - 2026-05-31
Added
- Export: subdivision ID fields for round-trip imports. Both export dialogs (Export Results and Export Addresses) now offer
administrative_area_id,locality_id, anddependent_locality_idas selectable fields, labelled "for re-import". These are the stable subdivision ULIDs from the package's seed data — identical across all instances of the same package version. Including them in an export makes re-importing that CSV lossless: subdivision matching is exact rather than fuzzy. Not selected by default.
Improved
Import:
addressable_type/addressable_idaccepted as column name aliases. The standalone importer now recognizesaddressable_typeandaddressable_id(the underlying model column names) as aliases forentity_typeandentity_id. A CSV exported directly from the package can be re-imported without any column renaming.Import: ULID-first subdivision matching. When
administrative_area_id,locality_id, ordependent_locality_idcolumns are present in the import file, the importer validates the ULID against the reference data and uses it directly — skipping fuzzy text matching for that level. If the ULID is not found (e.g. after a version upgrade that reorganized the subdivision data), the import falls back to fuzzy matching on the text column automatically. Combined with the new export fields, this makes export → re-import a fully lossless round-trip.Export dialog field ordering. Subdivision fields now appear in order of decreasing geographic scope: State/Province → City → District → IDs, in both export dialogs.
IMPORT-EXPORT.md overhauled. Added: round-trip import workflow;
firstOrCreate/lookup-by-email building block example with a decision table for choosing standalone vs. building blocks;addressable_*column aliases; subdivision ID columns. Fixed:dependent_localitywas absent from the example CSV, field normalization examples, building block code samples, and the Export section (which listed incorrect field names and was missing several fields). Updated last-modified date.
[1.0.68-beta] - 2026-05-28
Fixed
Venue-name-in-line-1 pattern (variant): non-numeric venue names with a different geocoded street. The original guard only detected the pattern when
geocodedLine1 === originalLine2(e.g. Palais des Congrès). A second variant now fires whengeocodedLine1 ≠ originalLine1,originalLine1has no leading digit (confirming it is a venue/establishment name rather than a correctable street), andoriginalLine2is non-empty. Example: "Wembley Arena / Arena Square" where Google geocodes to "Engineers Way". Both original lines are preserved and_venue_name_patternis set soapplyVerification()suppresses spurious standardization changes. 2 new tests.GB (and similar): verification provider returns county/historic-county (L2) instead of nation-level subdivision (L1). Smarty International returns counties such as "Middlesex" or "Somerset" for GB addresses, but GB's
administrative_area_levelis 1 (England / Scotland / Wales / Northern Ireland).applyVerification()now checks both the provider value and the geocoded value against the country's L1 subdivision options viafuzzyMatchSubdivision; if the geocoded value matches L1 and the provider value does not, the geocoded state is preserved. CN and other countries where neither value matches are unaffected. 1 new test.APPROXIMATE geocoding: wrong street proposed as standardized address_line_1. Google's APPROXIMATE location type resolves only to postal-code area, not street level; the returned
routecomponent may be a nearby street unrelated to the address (e.g. "Magdalene Street" for "4 Pennine Way, Glastonbury BA6 9EH").processFromAddress()now restores the originaladdress_line_1whenlocation_typeis APPROXIMATE and the geocoded street differs from the input. 2 new tests.KR/POI: Korean-only address_line_1 when Google Places omits street_address.
processFromPlace()now parses the first comma-segment offormatted_addresswhenstreet_addressis empty and that segment starts with a digit (e.g. "110 Buljeong-ro" from "110 Buljeong-ro, Bundang-gu, Seongnam-si, Gyeonggi-do, South Korea"). This avoids falling back to the place name, which is often in the local script only (e.g. "분당도서관").has_street_addressis updated accordingly soneeds_reviewis not raised unnecessarily. 2 new tests.KR/POI: district (gu) not populated when reverse geocode omits sublocality.
processFromPlace()now recoversdependent_localityfromformatted_addresswhen the reverse geocode returns no sublocality components. The segment immediately before the city informatted_addressis used as the district candidate (e.g. "Bundang-gu" from "…, Bundang-gu, Seongnam-si, …"). The form's fuzzy-matcher then resolves this to the correct DB subdivision. Applies to any country with a three-level"STREET, DISTRICT, CITY, …"formatted_address structure. 2 new tests.
[1.0.65-beta] - 2026-05-27
Fixed
- Smarty widget: disabled section still appeared in status message subhead. When
us_enabledorinternational_enabledis false, the subhead (e.g. "Healthy: 1,000 US · 857 Intl remaining.") was still including the hidden section. Both thenoneandhealthybranches now respect theshowflag. 2 new tests.
[1.0.64-beta] - 2026-05-27
Fixed
- CN/JP/KR autocomplete: street number dropped when Places API omits
street_numbercomponent. The address search field now captures the raw autocomplete input at selection time and recovers the leading street number (bare digit orNo.NNNprefix format) whenaddressComponentslacks astreet_numberentry. This handles both"107 Suzhou Rd"and"No.1088 Qianshan Rd"formats. - CN/JP/KR autocomplete: city and district not matched when geocoder omits
administrative_area_level_1. Google's geocoder sometimes returns a city without a province/state for CJK addresses. AddedCountryService::inferStateFromCity()which fuzzy-matches the city against all locality-level subdivisions for the country and walks up the hierarchy to infer the parent state. Both the verify-button and autocomplete paths in the address form now use this fallback, allowing Hefei Shi → Anhui and similar mappings to resolve correctly.
[1.0.63-beta] - 2026-05-24
Fixed
- CI test failures after street-number sanity check. The
smartySuccessResponse()test helper used a genericaddress1: "1 Test Street"response for all countries. After the new sanity check, tests that sent multi-digit street numbers (GB"10 Downing Street", CA"123 Main St", IL"Ranak St 19") failed because the mock response didn't contain the original number. UpdatedsmartySuccessResponse()to accept an optionaladdress1parameter; routing tests now pass a matching value.
[1.0.62-beta] - 2026-05-24
Fixed
- Smarty International: garbled address1 response shown in standardization dialog. When Smarty's International API returns an
address1that does not contain the street number from the original input (e.g."Street Hilton"for input"205 HaYarkon Street"), the response is treated as a verification failure rather than offered as a standardized suggestion. The check applies only to multi-digit street numbers (≥ 2 digits) to avoid false positives from single-digit numbers which can match as substrings.
[1.0.61-beta] - 2026-05-24
Fixed
- Smarty International: establishment name appended to address_line_1. Smarty's International Street API sometimes packs a truncated establishment/premise name onto the end of
address1(e.g."115 Hayarkon Street Sheraton Grand") whileaddress2holds the full name ("Sheraton Grand Tel Aviv"). The standardization dialog would show the hotel name in both fields. Fixed by detecting word-boundary overlap between the tail ofaddress_line_1and the head ofaddress2(or thepremisecomponent whenaddress2was cleared by the existing locality filter). A minimum overlap of 2 words is required to avoid false positives from single-word coincidences.
[1.0.60-beta] - 2026-05-24
Fixed
- Verification badge popover not closing on scroll when page has a fixed header. The scroll-close listener was registered on
window, which only fires when the viewport itself scrolls. On pages with a fixed header and a scrollable inner content area, scroll events fire on the inner container — not onwindow. Changed todocument.addEventListener('scroll', ..., true)(capture phase), which intercepts scroll events from any element in the document tree.
[1.0.59-beta] - 2026-05-24
Fixed
- Verification badge popover scroll-close and outside-click-close not working on create/demo forms. The scroll listener and outside-click listener that dismiss the popover lived in the document-level
$docClickScript, which is never registered on create forms (badge not in DOM on initial load). Scroll-close is now handled by a capture-phasescrolllistener onwindowregistered inline in theontogglehandler and removed on close. Outside-click-close is now handled by a full-screen transparent backdrop<div>(position:fixed; inset:0; z-index:-1) inside the popover that catches any click outside the visible card. Both work without document-level listeners.
[1.0.58-beta] - 2026-05-24
Fixed
- Verification badge popover not opening on create forms. The document-level
togglelistener that positions the popover was never registered when the badge first appeared during a Livewire re-render — Livewire's morphdom does not re-execute<script>tags added dynamically. On create forms the badge is not in the DOM on initial page load, so the script never ran and clicking the badge had no visible effect (cursor changed but popover did not open). Fixed by moving positioning to anontoggleinline handler on<details>and Re-verify delegation to an inlineonclickon the button. Both work regardless of whether the document listener was registered. The document-level script is now a progressive enhancement for outside-click-close and scroll-close only.
[1.0.57-beta] - 2026-05-22
Added
- Verification badge popover with Re-verify button (FAP-150). The green "✓ Verified by {Provider}" and blue "✓ Accepted by user" badges are now clickable. Clicking opens a small popover showing the provider name and verification date. A Re-verify Address button inside the popover re-triggers the existing verify action — giving staff a clear Re-verify entry point without cluttering the form with a permanently-visible button on already-verified addresses. The popover is absent when Re-verify is not available (provider not configured, country not covered, no address entered). Implemented with native
<details>/<summary>for the toggle (no JavaScript onclick),position:fixedto escape Filament'soverflow:hiddenTextEntry wrapper, and a document-level delegation listener that survives Livewire re-renders.
[1.0.56-beta] - 2026-05-21
Added
Geocoding-as-verification fallback for countries with no postal provider (FAP-151). When
processFromAddress()runs and the configured postal provider does not cover the address country (e.g. CN, most of Africa/Central Asia), aROOFTOPorRANGE_INTERPOLATEDgeocoding result is now treated as verified:is_verified = true,verification_provider = 'google_geocoding'.GEOMETRIC_CENTERandAPPROXIMATEresults are not promoted — they remain unverified and continue to setneeds_review = true. The form badge shows "✓ Verified by Google Geocoding". No new API calls required — geocoding already runs for coordinates.Quality scorer: neutral score for addresses in countries with no provider coverage (FAP-152).
AddressQualityScorerno longer penalizes unverified addresses when no postal provider covers the country. When providers are configured but none support the address country,calculateVerificationScore()returnsverified_basic(20 pts) instead of 0 — neither a bonus nor a penalty. The guard requires at least one provider to be configured globally; environments with no API keys (dev/test/provider=none) are unaffected and score 0 as before.
[1.0.55-beta] - 2026-05-21
Added
Chunked processing with per-chunk transactions for bulk operations (FAP-155).
BulkVerifyAddressesJobnow processes addresses in chunks of 50, each wrapped in aDB::transaction(). A failed chunk is logged and skipped — remaining chunks continue. Stats are aggregated across chunks. Inner retry with exponential backoff (3 attempts) handles transient failures before giving up on a chunk.Queued jobs for import and quality recalculation (FAP-153). Large imports (> 50 rows or with Geocode/Verify enabled) are dispatched as
ImportAddressesJobbackground jobs with chunked processing, per-chunk transactions, and automatic retry. Quality recalculation dispatchesRecalculateQualityJob(usingchunkById(200)) with scope support (all,unscored,below_threshold,selected). All jobs include progress tracking, completion notifications, and sync-driver detection for inline execution.RetriesChunkstrait — shared per-chunk retry logic (3 attempts, exponential backoff) used by all bulk job types.
Fixed
notificationstable missing on fresh installs causes panel errors.AddressingPanelProviderenables->databaseNotifications()(added in v1.0.52-beta), which causes Filament to query thenotificationstable on every page load. Apps that have never runphp artisan notifications:tablehit a fatal DB error immediately. Installation docs now includephp artisan notifications:tableas a required setup step.
[1.0.54-beta] - 2026-05-20
Fixed
administrative_areafalse change on Verify for GB (and other countries where Smarty returns a finer-grained subdivision). After verification, the post-verification geocoding result is now used to overridestate/administrative_area— Google'sadministrative_area_level_1aligns with the DB hierarchy (e.g. "England" for GB, full state names for US), while Smarty International sometimes returns a postal county or region (e.g. "London") that would appear as a spurious suggested change in the dialog.- Accept Address button re-triggers the review dialog on next open. The
_review_initializedhydration check readsneeds_reviewfrom theverification_metadataJSON blob. The Accept handler cleared the indexedneeds_reviewcolumn but left the flag in the blob, causing the standardization dialog to re-appear every time the record was reopened after accepting. The blob is now cleaned up (removesneeds_review,suggested_changes,flagged_at) to match the cleanup already done by the Use Standardized path. address_line_2duplication when provider absorbs unit/level intoaddress_line_1. Smarty International for AU/NZ returns the secondary address in slash notation (U 503/17 Help St,L 32 2 Chifley Sq). The originaladdress_line_2(Unit 503,Level 32) was still in components, causing both lines to show the unit in the standardization dialog. After applying the provider's address lines, the secondary prefix is stripped and the remaining token is checked as a standalone word in the newaddress_line_1; if found,address_line_2is cleared. Guard is skipped for JP/CN/KR romanized/custom-extractor paths.
[1.0.53-beta] - 2026-05-18
Fixed
needs_reviewbadge now explains USPS DPV secondary address flags. When USPS returns DPVS(unit type mismatch) orD(missing secondary), the badge showed generic "⚠ Needs Review" with no context. Thereview_reasonstored inverification_metadatais now shown in the badge (e.g. "⚠ Needs Review — Address confirmed but type does not match USPS records").
[1.0.52-beta] - 2026-05-18
Fixed
AddressingPanelProvidernow enables database notifications. The bulk verify job sends a completion notification via->sendToDatabase(), but the panel was missing->databaseNotifications()— the bell icon never appeared. Added to match the behaviour of the bundledfiladev-app panel.
[1.0.51-beta] - 2026-05-18
Fixed
needs_reviewform badge now shows provider rejection reason. When Verify Address fails (e.g. Ambiguous / Address Not Found), the reason was only shown in the ephemeral toast — once it faded the badge reverted to generic "⚠ Needs Review" with no context. The verification error is now stored in metadata and displayed in the badge as "⚠ Not verified — Multiple addresses matched" (first clause only; the instructional tail stays in the toast).
[1.0.50-beta] - 2026-05-18
Fixed
needs_reviewform badge now explains why review is needed. The amber badge in the edit form previously always showed "⚠ Needs Review" with no context. It now distinguishes:suggested_changespresent → "⚠ Needs Review — suggested changes available"; SmartyPartial→ "⚠ Partially verified (Smarty) — street-level only"; other → unchanged fallback. Mirrors the context already shown in the listing table tooltip.
[1.0.49-beta] - 2026-05-18
Fixed
- Accept Address after verification failure now produces an "Accepted" badge. When a provider returns Ambiguous or Address Not Found, clicking Verify then Accept left the record as "Not Verified" — the Accept button only cleared
needs_reviewbut never setis_verified. Now, accepting an unverified address setsis_verified=true,verified_at, andmanually_accepted=true, producing the blue "Accepted by user" badge in both the form and the listing table. The existingneeds_reviewAccept path (Smarty Partial, suggested changes) is unchanged — those records are alreadyis_verified=true.
[1.0.48-beta] - 2026-05-18
Fixed
address_line_2fallback creates duplicate when venue name resolves to same street. When a caller passes a venue name inaddress_line_1and the real street inaddress_line_2(e.g.Moscone Center/747 Howard Street), geocoding correctly resolvesaddress_line_1to the street — but the v1.0.46 fallback then copiedaddress_line_2anyway, sending747 Howard Street 747 Howard Streetto USPS and causing a 400 Address Not Found. Fix: skip the fallback whenaddress_line_2equals the geocodedaddress_line_1(case-insensitive).DefaultAddressExtractoruses wrong street order for German and other name-first countries. German (and Austrian, Swiss, Dutch, Nordic, Belgian) addresses follow the conventionroute number(Werner-Heisenberg-Allee 25), notnumber route(25 Werner-Heisenberg-Allee). The extractor was always using Western number-first order. AddedNUMBER_AFTER_ROUTE_COUNTRIESconstant (DE, AT, CH, NL, BE, NO, SE, DK, FI) and country-aware assembly.needs_reviewbadge tooltip shows provider name in lowercase. Provider is stored assmartyin the database; tooltip now usesucfirst()to displaySmarty.
[1.0.47-beta] - 2026-05-17
Fixed
needs_reviewbadge tooltip misleading for Smarty Partial results. The tooltip always said "has suggested changes that need review" regardless of why the flag was set. Whenneeds_reviewis set due to a SmartyPartialverification (no delivery-point precision), there are nosuggested_changesin the metadata — no dialog to open, nothing to diff. The tooltip now distinguishes: suggested changes present → original wording;Partialverification → "Address was only partially verified (provider). Open to accept or re-verify."; other → generic fallback.
[1.0.46-beta] - 2026-05-17
Fixed
address_line_2lost during geocoding + verification flow. Google geocoding never returns suite/unit numbers as a separate address component. WhenprocessFromAddress()passed geocoded components to the verification provider, the originaladdress_line_2(e.g. "Suite 7500") was silently dropped. Verification providers (USPS, Smarty) then received only the street address and could not validate or return the secondary unit. Fix: preserve the caller's originaladdress_line_2when geocoding returns nothing for that field — same pattern as the existingaddress_line_1fallback.
[1.0.45-beta] - 2026-05-17
Fixed
- Export Results button renders with dark text. Filament v4's WCAG contrast algorithm selects dark text on
success(green) in light mode. Addedfi-btn-export-results-addressesCSS class with pinned--bg/--textvariables to force emerald-600 background with white text in both light and dark modes, matching the Import Addresses button.
[1.0.44-beta] - 2026-05-17
Fixed
ExportResultsAddressesActionclass not found error. UsedFilament\Tables\Actions\Actioninstead ofFilament\Actions\Action— the correct namespace for toolbar actions in Filament v4.
[1.0.43-beta] - 2026-05-17
Added
- Export Results toolbar action. New
ExportResultsAddressesActionadded to the addresses table toolbar. Exports all records matching the current filters, search, and sort — not just selected records. Supports CSV and XLSX formats with the same field selection as the bulk export action. Respects theexportgate for visibility and authorization.
[1.0.42-beta] - 2026-05-17
Fixed
needs_reviewnot propagated on blur geocoding no-changes path. When blur geocoding ran verification and no field changes were detected, the form hardcoded$set('needs_review', false)instead of reading from$components['needs_review']. A Smarty Partial result on this path leftneeds_review=falsein the DB despite the provider signalling otherwise.needs_reviewnot propagated on map selection (reverse geocoding) success path. The coordinates/map selection handler setis_verified,verification_provider,verified_at, andverification_metadatafrom components but never setneeds_review. A Partial verification result from this path was silently dropped.BulkVerificationService::updateAddress()hardcodedneeds_review=false. When bulk verification accepted an address with minor/no changes,updateAddress()unconditionally cleared theneeds_reviewflag regardless of what the provider returned. Now respects$verifiedData['needs_review']so Partial results are correctly flagged in bulk runs.
[1.0.41-beta] - 2026-05-17
Fixed
needs_reviewnot set on partial/flagged verification results.applyVerification()stored the provider'sneeds_reviewsignal only inside theverification_metadataJSON blob, never in the indexedneeds_reviewcolumn. As a result, SmartyPartialresults (and any provider returningneeds_review: true) left the DB columnfalse, so the amber "Needs Review" badge never appeared after verification. Three-part fix: (1)applyVerification()now sets$components['needs_review']from the provider's metadata on the success path; (2) the form's no-changes verification path now reads$components['needs_review']instead of hardcodingfalse; (3)_verified_verification_statenow carriesneeds_reviewand the Accept handler uses it instead of hardcodingfalse.
[1.0.40-beta] - 2026-05-15
Fixed
- Dual-spinner bug on "Verify Address" click. When the "Accept Address" and "Verify Address" buttons shared a single
Actions::make()container with an explicit key, both spinners fired simultaneously on any click. Root cause: the shared key caused Filament to inject aschemaComponentparameter into bothwire:clickhandlers viaJs::from(), producingJSON.parse(...)in thewire:targetattribute. Alpine'sevaluate()could not parse that expression, so Livewire fell back to method-name-only matching and activated allmountActionspinners. Fix: the "Accept Address" button is now in its own unkeyed container, removing theJSON.parsefrom its target and scoping each spinner correctly. The "Verify Address" container retains its key for test compatibility. - "Changes detected" footer showed 0 fields after manual verification. When the Verify Address button detected differences and showed the standardization dialog, the
_changesfield was stored as a JSON array (["address_line_1"]) rather than a JSON object. The comparison blade template callsarray_keys()on the decoded value, expecting field names as keys — but got numeric indices ([0, 1]) instead, producing empty labels. Fixed to usearray_fill_keys($changes, true)(matching the blur-geocoding path). Added regression test.
[1.0.39-beta] - 2026-05-15
Changed
- README: accurate per-suite test counts (Unit 249, Integration 787, Feature 72, Smoke 73, Performance 37); smart auto-routing description updated.
- Docs:
Last updateddates corrected to 2026-05-13 for all files modified in that session (VERIFICATION.md, CONFIGURATION-GUIDE.md, FAQ.md, USER-GUIDE.md, PANEL-SETUP.md, UI-STYLE-GUIDE.md, CUSTOMIZATION_GUIDE.md, BETA-TESTING.md).
[1.0.38-beta] - 2026-05-13
Fixed
- USPS secondary address acronyms rendered in title case.
titleCase()was correctly normalising USPS ALL-CAPS responses but had no exception for acronyms in secondary address lines.PMB 42becamePmb 42,PO BoxbecamePo Box, etc. A second acronym-restore pass (after the existing directionals pass) now keepsPMB,PO,APO,FPO,DPO,RR, andHCin uppercase. 2 new tests.
[1.0.37-beta] - 2026-05-13
Added
- Filament v5 / Livewire v4 compatibility. Composer constraint updated to
filament/filament: ^4.0|^5.0. Confirmed compatible via source-level audit:dispatch()browser events,wire:model.live+ programmatic input events,window.Livewire.find().call(), and action modal state path (mountedActions.{n}.data) are all unchanged in Livewire v4 / Filament v5.illuminate/supportwidened to^11.0|^12.0|^13.0. PHP simplified to^8.2. - Smart auto-routing in
automode. Inautomode, provider selection is now country-aware rather than a flat priority list. Countries where Smarty has DeliveryPoint-level precision (155 countries including CA, AU, GB, FR, DE, BR, IL, SG, and others) route to Smarty first; all others (JP, CN, etc.) route to Google first. USPS country pins and explicit provider overrides are unaffected. Routing decisions are recorded inLog::debugwithcountry_code,smarty_strong, andprovider_selectedkeys. Notable exclusions from the Smarty-first list: JP (empirically unreliable), CN (Thoroughfare precision only — causes false Partial matches), KR (not in Google's supported country list). 10 new routing tests.
Changed
- All user-facing docs updated to reflect Filament 4 and 5 compatibility, Laravel 11–13 support, and current test count (1,220+).
VERIFICATION.md: Auto provider selection section updated for smart routing; Google vs Smarty comparison table expanded with diacritics/accent behaviour row; Smarty International uppercase ASCII (postal-authority standard) documented with examples and "Keep My Version" guidance.CONFIGURATION-GUIDE.md:autoprovider description, troubleshooting fix #3, and International Application recipe updated for smart routing.
[1.0.36-beta] - 2026-05-13
Fixed
- Brazilian addresses: bairro (neighbourhood) stored as city. For Brazilian cities, Google's Geocoding API returns the municipality at
administrative_area_level_2(notlocality), whilesublocality_level_1contains the bairro/neighbourhood.DefaultAddressExtractor's city priority chain fell through tosublocality_level_1beforeadministrative_area_level_2, so the bairro ("Jardim Paulista", "Centro", "Copacabana") was stored as the city. This caused Smarty verification to receive the bairro aslocality, leading to wrong-city matches (e.g. "Rua XV de Novembro 1500, Centro" matched to Palotina instead of Curitiba). Fix: forBR(and other countries in a newADMIN_LEVEL_2_CITY_COUNTRIESconstant), the extractor now resolves city post-loop with country-aware priority —administrative_area_level_2takes city,sublocality_level_1goes todependent_locality. 4 new unit tests.
[1.0.35-beta] - 2026-05-12
Fixed
- Accented characters dropped during address field uppercasing.
strtoupper()is ASCII-only — fields subject touppercase_fieldsformatting (e.g. Brazilian locality "Comércio") were rendered as "COMéRCIO" instead of "COMÉRCIO". Same issue affected country names appended to international-format previews (e.g. "México" → "MéXICO"). Both calls replaced withmb_strtoupper($value, 'UTF-8'). 1 new integration test.
[1.0.34-beta] - 2026-05-10
Fixed
- License activation warning repeated on every container wake-up. When
FINGERPRINT_ALREADY_EXISTSwas returned by Anystack (activation record lost, fingerprint still registered),LicenseService::activate()logged the warning and returned without writing anything to theaddress_license_activationtable. On ephemeral hosts (Laravel Cloud, Fly.io), this caused the warning to fire on every container restart or hibernation wake-up. A placeholder record (with nullactivation_id/license_id) is now stored sohasActivation()returns true on subsequent checks, preventing the repeat.validate()skips gracefully whenactivation_idis null. The warning still fires once to prompt the operator to deauthorize and redeploy for full tracking.
[1.0.33-beta] - 2026-05-09
Fixed
- License activation migration not registered in service provider. The
address_license_activationtable migration added in v1.0.32-beta was missing from thehasMigrations()list inFilamentAddressServiceProvider, sophp artisan migratedid not discover or run it on installed instances.
[1.0.32-beta] - 2026-05-09
Fixed
- License activation record moved to a dedicated database table.
LicenseServicepreviously stored the activation record inCache::store('file'). On ephemeral-filesystem hosts (Laravel Cloud, Fly.io, any container-based deployment), the file cache is wiped on every container restart — causinghasActivation()to return false,activate()to fire, Anystack to returnFINGERPRINT_ALREADY_EXISTS, and a warning to be logged on every restart cycle. The activation record is now stored in a dedicatedaddress_license_activationdatabase table (added via migration). A migration-created table is unaffected byphp artisan cache:clear, survives container restarts on any hosting environment, and requires no additional configuration. The file-cache backoff in the service provider is unchanged — it is transient state that does not need to survive restarts.
[1.0.31-beta] - 2026-05-05
Fixed
isNamedPoifalse positive for Israeli/RTL-style address format. Google Places returns the placenamefor Israeli addresses with the street number at the end ("Ranak St 19","Derekh ha-Dukhifat 410"), not the beginning. The named-POI guard only checked for a leading digit (/^\d/), so these passed the check and the place name was incorrectly written intoaddress_line_2. Guard updated to/^\d|\s\d+$/— also blocks names that end with a space-separated number.
[1.0.30-beta] - 2026-05-04
Fixed
- License activation record stored in file cache (not default cache store). The activation record was previously stored in the default cache store (typically database-backed). A DB crash or cache flush would lose the record, causing
hasActivation()to return false,activate()to fire, Anystack to returnFINGERPRINT_ALREADY_EXISTS, and a warning to be logged — repeating every 5 minutes until the operator intervened. The activation record is now stored viaCache::store('file'), matching the backoff key store added in v1.0.28-beta. Survives DB cache clears and DB crashes. - FINGERPRINT_ALREADY_EXISTS backoff increased from 5 minutes to 4 hours. This condition requires manual intervention (
php artisan addresses:license:deactivate+ redeploy) and will not self-heal on retry. A 5-minute backoff spammed logs every 5 minutes; 4 hours gives breathing room while still surfacing the problem regularly. - Livewire trigger simplification in autocomplete mode. Removed redundant
changeevent dispatch andcomponent.set()call from the Places selection handler (address-search-field.js). A singleinputevent is sufficient forwire:model.live; the extra dispatches were triggering duplicate Livewire requests.
[1.0.29-beta] - 2026-05-03
Fixed
- Country-aware address parsing.
AddressInputParsermethods now accept a$countryCodeparameter, gating country-specific logic correctly:- Named-building heuristic ("The Shard, 32 London Bridge St" → line 1 is the street) is now restricted to Western-address countries (GB, US, AU, CA, NZ, IE). Previously it misfired on FR/JP/CN/KR addresses where neighbourhood or ward names precede the street.
- Japanese building extractor is now gated to
JPonly. Previously it included English keywords (Building,Tower,Apartment), causing false matches on English input (e.g. "Empire State Building, 350 Fifth Ave"). The fragile ordering workaround is removed. - All call sites in
AddressFormandGeocodingQueryBuildernow pass the active country code. - 5 new unit tests added.
[1.0.28-beta] - 2026-05-03
Fixed
- License activation warning spam on database failure. Two bugs caused the "activation record was lost" warning to fire on every request when the database cache was unavailable (e.g. periodic DB crashes on Laravel Cloud):
- The
FINGERPRINT_ALREADY_EXISTSpath inactivate()logs a warning and returns without throwing an exception — the service provider's catch blocks never run, so no backoff was ever set for this code path. - All backoff writes used the default (DB-backed)
Cachefacade. When the database cache is down,Cache::put()silently fails, so even the catch-block backoffs didn't persist between requests. Fixed by: (a) switching all backoff reads/writes toCache::store('file')— available even when the DB cache is down; (b) adding a post-try check that sets the file-backed backoff wheneverhasActivation()is still false after the activation attempt, catching the silent FINGERPRINT return path.
- The
[1.0.27-beta] - 2026-05-03
Added
- US Military (APO/FPO/DPO) address support. Military addresses use pseudo-city codes (
APO,FPO,DPO) and special state codes (AE/AP/AA). They have no street number and cannot be geocoded by Google. Three entry points were blocked:- Pre-flight validator (
GeocodingQueryValidator): addedMILITARY_ADDRESS_PATTERNbypass alongside the existing PO Box and Rural Route bypasses. APO/FPO/DPO queries now pass pre-flight without triggering "Street number appears to be missing." - Blur geocoding routing (
AddressForm): military addresses skip the geocoding call entirely and route directly toverifyFromComponents, avoiding a doomed API call to Google. - Aggressive smart-detection mode (
AddressForm): the street-number requirement forsmart_detection_level=aggressiveis now bypassed for military addresses. - USPS verifies APO/FPO/DPO addresses natively via DPV; post-verification geocoding failure (no coordinates) is non-fatal and expected.
- 3 corpus fixtures (APO AE, APO AP, FPO AP) and 9 new unit tests added.
- Pre-flight validator (
[1.0.26-beta] - 2026-05-03
Fixed
- CN: Smarty International can return a false "Partial" match with a completely wrong city/state for Chinese addresses (e.g. a Beijing Chaoyang address matched to Tonghua, Jilin Province).
applyVerificationwas applying Smarty's administrative fields unconditionally, overwriting the correct geocoded values from Google. Added a guard: for CN addresses, city/state/district from Smarty are only applied when the verification status is "Verified" (which essentially never occurs for CN); otherwise the geocoded values fromChineseAddressExtractor+ Google are preserved. Smarty'saddress_line_1normalisation (for display in the choice dialog) is unaffected.
[1.0.25-beta] - 2026-05-02
Fixed
- GB:
postal_townnot included in city extraction priority chain; addresses in Greater London and otherpostal_town-only areas returned the admin area name instead of the city. Fixed inDefaultAddressExtractor. - GB: Google Places returns outward-code-only UK postcodes (e.g. "W1U") when the full postcode is known. Fixed in
AddressProcessingService— the longer of the two postcodes wins when one is a prefix of the other. - GB: Smarty International reverses UK flat address lines, placing the subpremise in
address_line_1. Added$isGarbledSubpremisestructural guard inAddressFormto detect and correct the swap. - GB: Named building prefix (e.g. "The Shard, 32 London Bridge Street") was lost by the parser — treated as a street name rather than a building + street combination. Fixed in
AddressInputParser.extractStreetFromFullInput. - GB: Scottish/English L1 state (Scotland, England) was lost when Smarty returned a granular admin area (Midlothian, Lanarkshire).
AddressProcessingServicenow preservesgeocoded_statefor L1 fallback matching. - GB: Missing postal code caused Smarty to return Ambiguous for otherwise valid addresses.
AddressProcessingServicenow recovers the postcode from the user's input string (country-aware patterns) before sending to verification. - GB:
AddressDuplicateDetectordid not normalise em/en dashes or spaces around hyphens in range street numbers (e.g. "21–23" vs "21-23" vs "21 - 23"); duplicate addresses with typographic variants were stored as distinct records. Fixed innormalizeAddress(). - GB:
$isGarbledSubpremiseguard inAddressFormdid not match slash notation ("6/1");extractSecondaryAddressflat patterns did not capture the full sub-unit with slash. Both fixed. - GB:
extractSecondaryAddressmatched "unit" as a word boundary inside "United Kingdom", producing "Unit ed" inaddress_line_2. Fixed with\bword boundary guard. - US:
$isNamedPoifalse positive for Queens-style hyphenated street numbers (e.g. "30-30 Northern Blvd"). Simplified guard to/^\d/(any leading digit = street number). - CA: Duplicate unit in
address_line_2when user input uses Canadian unit-hyphen-civic format (e.g. "305-1245 Robson St"). The unit is already encoded inaddress_line_1; added$isCanadianHyphenNotationLine1guard inAddressForm. - CA: "Changes detected: 0" shown in the blur-path choice dialog. The
_changesarray was stored as an indexed JSON array; the Blade template'sarray_keys()call returned[0]. Fixed witharray_fill_keys($changes, true). - CA: PO Box postal code was silently overwritten by the geocoded civic street postal.
extractPostalCodeFromInputwas called without a country code, defaulting to US ZIP patterns. Fixed by computing$extractedPostalwith the form's country code and using it throughout. - CA/AU/UK: Same missing country code in
extractPostalCodeFromInputmeant non-US postal codes were not extracted for theoriginalDatacomparison in the choice dialog. - CA: Rural Route addresses ("RR 1", "SS 2", "MR 3") were blocked by the pre-flight geocoding validator. Added
RURAL_ROUTE_PATTERNbypass alongside the existing PO Box bypass inGeocodingQueryValidator.
[1.0.24-beta] - 2026-04-28
Fixed
- Production DB hammering: all Anystack API calls now send
Accept: application/json. Previously the API returned HTML 404 pages, causing a JSON parse exception on every request. FINGERPRINT_ALREADY_EXISTScheck now reads themessagekey from Anystack's response body (was readingerror, which is not present in the actual response format).- 5-minute backoff cache added to
FilamentAddressServiceProviderto prevent repeated license activation retries on every request when the Anystack API is unreachable or returns an error.
[1.0.23-beta] - 2026-04-28
Fixed
- Smarty International API returns the district for China's direct-controlled municipalities (Beijing, Shanghai, Tianjin, Chongqing) in
dependent_locality(level 3), echoing the municipality name at bothadministrative_areaandlocality. This conflicts with the package's database structure where districts are at level 2 — the direct child of the municipality with no prefecture-level city in between. The standardized choice dialog showed the district at level 3, appearing to differ from the user's level 2 input even though both referred to the same place. Fixed by detecting this pattern inparseIntlResponse()and promotingdependent_locality→localityfor CN municipalities.
[1.0.22-beta] - 2026-04-27
Fixed
SmartyUsageWidgetshowed the US section even whenADDRESS_VERIFICATION_SMARTY_US_ENABLED=false. Theshowflag was driven purely by usage data and limits; the template's fallback logic forced at least one section to render, overriding the disabled state. Fixed by forcingshow = falseingetStats()for any disabled section, so the template fallback cannot override it.
[1.0.21-beta] - 2026-04-27
Fixed
SmartyUsageWidgetandUspsRateLimitWidgetappeared in the dashboard whenever provider credentials were configured, ignoring the enabled flags (ADDRESS_VERIFICATION_SMARTY_US_ENABLED,ADDRESS_VERIFICATION_SMARTY_INTERNATIONAL_ENABLED,ADDRESS_VERIFICATION_USPS_ENABLED). Widgets now require both credentials and the provider being enabled — consistent withisAvailableForCountry()behaviour. This allows credentials to remain in place while a provider is temporarily disabled.
[1.0.20-beta] - 2026-04-26
Fixed
- Migration
create_addresses_tablefailed on SQLite and PostgreSQL due to MySQL-specific column prefix index syntax (address_line_1(50)). SQLite is Laravel's default database since Laravel 11, so this broke fresh installs following the quickstart. Fixed by wrapping the index creation in a driver check; MySQL/MariaDB use the prefix index, all other drivers use a plain index.
[1.0.19-beta] - 2026-04-24
Fixed
- "Verify Address" / "Accept Address" buttons invisible on Filament v4.10+ in non-panel Livewire contexts (e.g. the public demo).
Filament\Actions\Actionclosures were typedcallable $get, relying on name-based dependency injection (getSchemaComponent()->makeGetUtility()). In Filament v4.10+,getSchemaComponent()returnsnulloutside a panel page, causing the injection to silently fail and all action visibility closures to evaluate as hidden. Fixed by typing$get/$setparameters as\Filament\Schemas\Components\Utilities\Get/Set, which uses type-based resolution and works in all contexts. Backwards-compatible: on Filament v4.2, name-based resolution fires first (matching the parameter name'get'before the type), so behaviour is unchanged.
[1.0.18-beta] - 2026-04-24
Fixed
- 500 error on first request after deploy when Anystack license API times out during activation. The ServiceProvider
activate()call was only catchingLicenseActivationException; a cURL timeout throwsConnectionExceptionwhich propagated uncaught. Addedcatch (\Throwable)to log a warning and continue — consistent with the existingvalidate()error handling. The next request retries activation when the API is reachable.
[1.0.17-beta] - 2026-04-24
Fixed
- Quality score badge was invisible in Geocoding mode when no verification provider is configured (
ADDRESS_VERIFICATION_PROVIDER=none). Thevisible()condition now also triggers when geocoding coordinates are present (latis set), so the score appears after a successful blur geocode regardless of verification state. - Pasted address with a labeled premise (e.g. "Suite 2115", "Apt 1B") was written to
address_line_2as a bare unit code (#2115,1B) after blur geocoding. Google strips the label from thesubpremisecomponent; the extractor has no access to the original input. Fix: the blur geocoding handler now detects when the geocodedaddress_line_2is a bare unit code (with or without#prefix) and the parser extracted a labeled version from the user's input — the labeled version is preferred.
Changed
docs/USER-GUIDE.md: clarified the subdivision section — subdivisions are linked by stable, canonical ULID identifiers, not text strings. Added concrete example: renaming a subdivision in seed data updates every address referencing that ID automatically.
[1.0.16-beta] - 2026-04-20
Fixed
- Verification state cleared after accepting the USPS standardized version in the choice dialog.
onAddressFieldEditwas missing the_input_sourceguard documented in its own docblock. Filament defersafterStateUpdatedcallbacks until after the originating closure completes — by the time address field callbacks fired,is_verifiedwas alreadytrue, causing verification to be erroneously cleared andneeds_reviewsaved to the database. Fix: added guard for'blur','reverse', and'choice'sources; both accept paths now set_input_source='choice'before applying fields. onAddressFieldEditguard was too broad on edit forms. The'hydrating'source set during form load was never cleared (it clears inlat.afterStateUpdated, which only fires when lat changes — not on edit page load). Including it in the guard permanently blocked verification clearing for all user edits on the edit page.- Geocoding "Verifying address…" spinner toast stuck on screen when pre-flight validation failed (e.g. missing street number). The JS blur handler showed the toast before the Livewire request; when pre-flight returned early,
address:geocoding-completewas never dispatched. Fix: dispatch the event and show an "Address incomplete" warning notification.
Changed
address_line_1is now trimmed of leading/trailing whitespace on blur (common from copy-paste).
[1.0.15-beta] - 2026-04-20
Fixed
AddressVerificationService::isAvailableForCountry()now respects the configured verification provider (ADDRESS_VERIFICATION_PROVIDER). Previously it used an auto-scan of all registered providers, which could make the Verify button appear for countries the configured provider does not support (e.g. showing Verify for France whenprovider=usps). The button would appear but verification would silently do nothing. Now the check passes the configured provider toselectProviders()so button visibility matches actual verification capability.
[1.0.14-beta] - 2026-04-19
Fixed
processFromPlace: reverse geocoding a Places autocomplete selection could inject asubpremise(e.g.#305) intoaddress_line_2when Google returns a unit-level result for the building's coordinates. The place selection is authoritative —address_line_2andsubpremisefrom the reverse geocode are now cleared before the result is returned.- License check skipped for
APP_ENV=localandAPP_ENV=testingenvironments. Previously, copying a production.envto a local app would trigger an activation attempt and consume an activation slot (or fail with "Invalid license key" if the limit was reached).
Docs
docs/LICENSING.md: Updated "Local Development" and "CI/CD" sections to reflectAPP_ENV-based skip. Updated "How Activation Works" to describe Cache storage instead of a filesystem file. Updated FAQ entries accordingly. Replaced "corrupt activation file" language with "corrupt activation record".docs/CONFIGURATION-GUIDE.md,INSTALLATION.md: Removed stale references tostorage/app/.license-activation.json(now stored in Laravel Cache).docs/PANEL-SETUP.md: Config reference updated to showADDRESS_PANEL_ID/PATH=addressing(wasapp).
[1.0.13-beta] - 2026-04-19
Fixed
- License activation record now stored in Laravel Cache instead of the local filesystem. Fixes silent activation failures on ephemeral-storage hosts (Laravel Cloud, Vapor, Fly.io) where
storage/app/is wiped on every deploy, forcing a re-activation call that Anystack rejects withFINGERPRINT_ALREADY_EXISTS. FINGERPRINT_ALREADY_EXISTS(422) response from Anystack is now handled gracefully: logs a warning and continues rather than throwingLicenseActivationException. This confirms the key is valid and the installation was previously activated — the local record was simply lost.
Docs
docs/PANEL-SETUP.md: Added "Prerequisite: FilamentUser" section. Filament v4 requires theUsermodel to implementFilamentUserwithcanAccessPanel()before any panel grants access. Apps usingfilament:install --panelsget this automatically; apps usingAddressingPanelProviderdirectly (Option 1) must add it manually.AddressingPanelProvider: Docblock now includes the requiredFilamentUsersnippet.README.md,docs/USER-GUIDE.md: Added links toINSTALLATION.mdfor first-time setup (beta access, Composer auth, CI/CD, scenario walkthroughs).
[1.0.12-beta] - 2026-04-15
Fixed
needs_reviewflag incorrectly set after blur geocoding whenADDRESS_VERIFICATION_PROVIDER=none. The verification service returned a failure result with an error string ('No provider available for this country') even when verification was intentionally disabled. That error propagated intocomponents['verification_error'], triggering the "Address not verified" warning andneeds_review=true. Fixed by returning a silent failure (no error string) when no providers are available — callers now treat it as "skipped" rather than "failed".- Verify Address button now hidden when
ADDRESS_VERIFICATION_PROVIDER=none. Previously,isAvailableForCountry()used auto-detection (ignoring the configured provider) and could show the button even though clicking it would do nothing useful.
[1.0.11-beta] - 2026-04-15
Fixed
- Double Livewire request on autocomplete selection in page-form mode.
address-search-field.jswas firing both achangeevent and an explicitcomponent.set()call after theinputevent — all three triggered separate Livewire round-trips. Removed the redundantchangedispatch andcomponent.set()call; a singleinputevent is sufficient forwire:model.livein Livewire 3.
Changed
- Production license enforcement: a missing
FILAMENT_ADDRESS_LICENSE_KEYnow throwsLicenseActivationExceptionwhenAPP_ENV=production. Previously the package silently skipped license validation with no key configured, making it impossible to detect bootleg distribution. Local and staging environments continue to boot without a key.
Docs
- Two-key Google Maps setup (
GOOGLE_MAPS_SERVER_KEY+GOOGLE_MAPS_BROWSER_KEY) promoted as the primary recommendation inINSTALLATION.mdanddocs/GETTING-STARTED.md. Single-keyGOOGLE_MAPS_API_KEYfallback moved to a commented secondary option.
[1.0.10-beta] - 2026-04-13
Fixed
GOOGLE_MAPS_API_KEYsingle-key fallback was ignored by bothMapImageController(static map proxy) andAddressSearchField(Places autocomplete). Only the specificGOOGLE_MAPS_SERVER_KEY/GOOGLE_MAPS_BROWSER_KEYconfigs were checked. Customers using the documented single-key setup got 500 errors on the map proxy and no autocomplete. Both now fall back toGOOGLE_MAPS_API_KEYwhen their specific key is unset.
Docs
- Added
docs/GETTING-STARTED.md— quick-start guide covering installation, configuration, and first address form. - Added
docs/BETA-TESTING.md— beta program overview and feedback instructions.
[1.0.9-beta] - 2026-04-13
Fixed
DeleteBulkAction("Delete Selection") was visible to all authenticated users becauseAddressPolicylacked adeleteAny()method. Filament checksdeleteAnyto gate the bulk delete button — without it the check fell through totrue. AddeddeleteAny()mirroring the same Spatie/config logic asdelete().
Docs
SPATIE-PERMISSION.md,AUTHORIZATION.md:delete-addressespermission now documented as also controlling the "Delete Selection" bulk action.
[1.0.6-beta] - 2026-04-13
Fixed
RecalculateQualityAction(bulk action) andRecalculateAllQualityAction(header action) were visible to all authenticated users regardless of permissions. Both now check theupdatepolicy before rendering, so viewer-only roles no longer see either.
Docs
INSTALLATION.md: Added Step 8b documenting thatconfig('addresses.import.allowed_entity_types')must be populated for the standalone Addresses resource create form to work. Without this, the "Belongs To" dropdown is empty and addresses cannot be created.docs/SPATIE-PERMISSION.md: Added "Register Entity Types" section covering the same requirement in the Spatie integration context.
[1.0.5-beta] - 2026-04-13
Fixed
LicenseActivationExceptionno longer escapes the boot hook and crashes the entire app when an invalid or expiredFILAMENT_ADDRESS_LICENSE_KEYis configured. The exception is now caught inpackageBooted(), logged as an error, and the app continues to boot. Customers with a bad key will see a log entry rather than a 500 error page.
[1.0.4-beta] - 2026-04-13
Fixed
php artisan migratenow auto-discovers package migrations without--path=. AddedrunsMigrations()toFilamentAddressServiceProvider::configurePackage().ADDRESS_VERIFICATION_PROVIDER=noneno longer logs a spurious "Unknown verification provider" warning on every verification attempt. The value is now treated as an explicit opt-out and short-circuits silently inselectProviders().
Docs
INSTALLATION.md: Google Maps API key is now correctly labelled optional (not "Required"). Added graceful-degradation note explaining what works without a key.INSTALLATION.md: Addedphp artisan addresses:installwizard as the recommended setup path (Option A in Step 7). Added migration troubleshooting note for--path=workaround.config/addresses.php:noneprovider comment clarified — it suppresses verification silently with no log noise. DocumentsADDRESS_VERIFICATION_ENABLED=falseas the way to disable both verification and geocoding.
[1.0.1-beta] - 2026-04-11
Added
- Runtime license validation via Anystack API (
LicenseService) — activates on boot, caches result for configurable TTL, handles expiry gracefully php artisan addresses:license:deactivatecommand to release an activation slot before moving to a new domainLicenseActivationExceptionfor structured error handling during activation failures
Changed
FilamentAddressServiceProvider::boot()now validates the license key on each request (within TTL cache window)config/addresses.phpgainslicense.*keys (key,product_id,api_token,cache_ttl)- Pest constraint bumped to
^4.0;phpunitto^11.0|^12.0inrequire-dev
Fixed
- Pest 4 base-class-per-folder compatibility:
LicenseServiceTestmoved toIntegration/Services/; added explicituses(PureUnitTestCase::class)to five Unit test files that had no base-class declaration
[1.0.0-beta] - 2026-04-09
Initial beta release.