Commit Graph

6 Commits (main)

Author SHA1 Message Date
boban deb5f310a1 fix(bio): plan-aware URL + plan-seeder + ulid→slug fix
- Migration: add bio_pages_limit to plans, make limit cols nullable (agency=unlimited)
- PlanSeeder: 4 plans (free/pro/business/agency) with tier/features/bio_pages_limit
- workspaces:assign-default-plan command: assigns free plan to unassigned workspaces
- BioPage::publicUrl(): free=apex-path, pro+=subdomain, custom=custom-domain
  - Security: str_ends_with check uses '.'.$apex to prevent evilnimu.li bypass
- BioPage::shortPublicUrl(): URL without scheme for display
- PlanLimitsService: use bio_pages_limit column (was features['bio_pages']), null=unlimited
- BioPageController: fix $bio → $page variable (view expects $page)
- Bio index/edit views: use publicUrl()/shortPublicUrl(), not hardcoded ULID URLs
- Bio edit view: publicUrlBase/displayUrlBase from component (plan-aware prefix)
- Create-bio modal: plan-aware URL prefix display
- PlanFactory/WorkspaceFactory: free()/pro() states for tests
- Tests: PublicUrlTest (5 cases), Free404FixTest (3 cases)

Known pre-existing failure (not caused by this change):
- Tests\Feature\Auth\EmailVerificationTest::email can be verified

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-17 22:44:54 +02:00
boban c479e46f55 fix(livewire): remove require_workspace() from action methods and render()
Livewire AJAX requests go to /livewire/update — ResolveWorkspace
middleware never runs, CurrentWorkspace is null, require_workspace()
throws RuntimeException.

- Members: add mount() to store workspaceId, use it in render()
- QrCodes/Create save(): use Workspace::where('ulid', $workspaceUlid)
- Modal components (CreateBioPage, CreateWebhook, InviteMember, AddDomain):
  replace `?: require_workspace()` fallback with abort_if($id === 0, 404)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-17 15:21:15 +02:00
boban 43ff6d6407 fix(FIX-10): 6 bugs — route ULID, QR modal, bio unique, nav active, copy btn, analytics context
- Workspace.getRouteKeyName()='ulid' so route() generates ULID URLs not ID
- QR modal 4xl→5xl; import QRCode in @script→window.QRCode (no ESM in @script)
- Bio slug unique rule scoped to (workspace_id, domain_id) not global
- updateActiveNav uses URL.pathname not raw getAttribute('href') (absolute URL fix)
- Add resources/views/components/ui/copy-button.blade.php Alpine component
- Analytics Index.render/baseQuery use $workspaceId not require_workspace() — prevents RuntimeException on Livewire action calls without middleware

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-16 17:01:16 +02:00
boban 248c5100d1 fix(sidebar+types): mobile slide animation, close-on-navigate, PHPStan clean
- sidebar: transition-[width,transform] so mobile open/close animates
- sidebar: pure :class binding replaces mixed class+:style for translate
- layout: livewire:navigated closes mobile sidebar via Alpine store
- tests: RouteSmokeTest covers all 17 workspace/profile/AI routes
- scripts: crawl-all-routes.mjs + console-check.mjs (Playwright)
- phpstan: add @property-read, @var, @return generics across 15 modal/component files → 0 errors
- pint: auto-fix style violations in 9 files

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-16 15:47:17 +02:00
boban 2510620f67 fix(modals): make create/edit/delete modals actually save + auto-refresh lists
- All create modals now validate→create→dispatch(kebab-case event)→toast→close
- All edit/delete modals dispatch kebab-case events to Index classes
- Index components listen via #[On] and call resetPage() to refresh
- QR Code save() validates url field conditionally per type
- Tests updated to assert kebab-case event names

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-16 15:13:44 +02:00
boban c67bde8fc5 feat: Toaster, button-component, 10 new modals, links-page fix, vite-tuning
- Toaster Livewire component (toast event, dismiss, auto-hide, 6 tests)
- <x-ui.button> Blade component with wire:loading indicator + variants
- QR modals: CreateQrCode, EditQrCode, DeleteQrCode (TDD, 8 tests)
- Bio modals: CreateBioPage, EditBioPage, DeleteBioPage (TDD, 7 tests)
- Domain modals: AddDomain, VerifyDomain, DeleteDomain (TDD, 7 tests)
- Profile modal: DeleteAccount with password confirm (TDD, 4 tests)
- Links page: fix openModal event name, wire up Edit/Delete to modals, toast on all CRUD
- vite.config.js: add chart.js/auto + optimizeDeps.force
- QrCode model: add newFactory() + QrCodeFactory
- Layout: Toaster embedded before </body>
- 141 tests / 296 assertions all green, verify 29/29

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-16 13:55:25 +02:00