Commit Graph

4 Commits (7d2926ce77015843165ab94122847dbabe2dd6dc)

Author SHA1 Message Date
boban 7d2926ce77 fix(bio): prevent page scroll-jump on slug check (#[Renderless])
.checkSlug() triggered Livewire re-render on every keystroke,
causing the editor to scroll to top. #[Renderless] skips re-render
while still returning the bool result to Alpine.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-17 23:30:55 +02:00
boban f742b40921 feat(bio): live slug availability check while typing
- Edit view: debounced $wire.checkSlug() call on input (350ms)
- Shows red error text + red border immediately when slug taken
- Hides help text when error shown
- Edit component: checkSlug() queries DB excluding current page

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-17 23:25:19 +02:00
boban 308778b99d fix(bio): prevent duplicate slugs within same workspace
- Migration: add UNIQUE(workspace_id, slug) to bio_pages
  Old (subdomain_host, slug) unique allowed MySQL NULL bypass —
  two free-plan bios with NULL subdomain_host + same slug were not caught
- Edit::save(): validate slug uniqueness before update, dispatch toast on conflict
- Edit::save(): validate slug format (alphanumeric + dash/underscore, max 64)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-17 23:09:17 +02:00
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