Switch all models to ULID primary keys#17
Merged
Conversation
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The demo:setup command hardcoded project_id 1/2 and ->named(1,1)/(2,2), which were valid under auto-increment but break under ULID primary keys (FK violation inserting domains). Resolve projects by name and derive their domain id, mirroring the existing getOwnerOneUser() lookup pattern. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Migrates every owned Eloquent model from auto-increment bigint primary keys to time-ordered ULID (
char(26)) primary keys.Why ULID, not UUIDv4: the goal was a single non-sequential identifier type plus headroom for higher request volume. Random UUIDv4 PKs would hurt under load — they fragment the index on the high-volume
statisticstable. ULIDs are time-ordered, so inserts stay sequential like auto-increment while remaining globally unique and non-guessable.Data was disposable (test data only), so the rollout is
migrate:fresh --seed— no data transform.Changes
ulid('id')->primary()andforeignUlid(...)for every FK. Cascade/soft-delete behavior and composite pivot keys (project_user,pixel_url) preserved.HasUlidsadded to all 8 owned models (User,Project,Domain,Url,QrCode,Pixel,Statistic,ProjectInvitation).int-typed id params widened tostringacross controllers,RecordClickStatisticJob,StatisticsAggregator, andReportDataService;domain_id/url_idvalidation rules changedinteger→ulid. Genuinely-numeric values ($days,$limit,smtp_port,logo_size,type/status, count return types) left untouched.id/*_id/pixel_idsTypeScript types widened fromnumbertostring.demo:setupfixed to resolve projects by name instead of hardcoded integer ids.Out of scope (intentionally untouched)
settings(spatie-settings) and frameworkcache/jobs/password_reset_tokenstables stay on bigintid().Verification
npm run build(tsc + Vite): clean, 3192 modules.getIncrementing()=falseeverywhere; redirect returns 302;RecordClickStatisticJobwrites a Statistic with ULID FKs; QR attach works.demo:setup --force: exit 0, seeds 3 users / 2 projects / 2 domains / 40 URLs with valid ULID FKs.Notes for deploy
migrate:fresh --seedrebuilds thesessionstable → users re-authenticate.RecordClickStatisticJobpayloads with old integer ids would fail against the newstringconstructor.🤖 Generated with Claude Code