Skip to content

feat(user): configurable foreign key type (bigint/uuid/ulid)#124

Merged
cjmellor merged 2 commits into
mainfrom
feat/configurable-user-key-type
May 17, 2026
Merged

feat(user): configurable foreign key type (bigint/uuid/ulid)#124
cjmellor merged 2 commits into
mainfrom
feat/configurable-user-key-type

Conversation

@cjmellor
Copy link
Copy Markdown
Owner

@cjmellor cjmellor commented May 15, 2026

Summary

Adds level-up.user.foreign_key_type so host apps whose User model uses HasUuids or HasUlids can install the package without hand-editing every user-FK column.

  • New config key level-up.user.foreign_key_type (default 'bigint', accepts 'uuid' or 'ulid')
  • New helper LevelUp\Experience\Support\UserForeignKey::on($table) that returns the right column type and is callable from migrations
  • All six user-FK migration stubs now route through the helper: experiences, streaks, achievement_user, challenge_user, experience_audits, streak_histories
  • UUID + ULID fixtures and end-to-end flow tests covering experience, streak and challenge flows

Migration

This is opt-in and backwards-compatible. The default 'bigint' keeps the current foreignId(...) behaviour, so existing installs see no change at all. Only set foreign_key_type to 'uuid'/'ulid' on a fresh install where the host User PK matches.

// config/level-up.php
'user' => [
    'foreign_key' => 'user_id',
    'foreign_key_type' => 'uuid', // 'bigint' (default) | 'uuid' | 'ulid'
    'model' => App\Models\User::class,
    'users_table' => 'users',
],

Out of scope (known limitations)

  • Package-internal PKs (e.g. experiences.id, levels.id) stay bigint. The pain point this PR addresses is the user-FK boundary; internal PKs only matter to package code which already treats keys polymorphically through Eloquent.
  • multiplier_scopes.scopeable_id is still unsignedBigInteger, so scoping a Multiplier directly to a UUID/ULID user via morphedByMany won't match. Tier scopes are unaffected. Tracked as a follow-up.

@cjmellor cjmellor self-assigned this May 15, 2026
@cjmellor cjmellor marked this pull request as ready for review May 15, 2026 14:40
pull Bot pushed a commit to KornaLaravel/laravel-level-up that referenced this pull request May 16, 2026
Move the package migration loop out of getEnvironmentSetUp (which fires
during config bootstrap, before RegisterProviders/BootProviders) into
Testbench's defineDatabaseMigrations() hook, which runs after providers
have booted. getEnvironmentSetUp now only handles config plus the host
users table schema.

This lets the service provider's boot() register Blueprint macros (and
anything else container-bound) before any package migration runs — a
prerequisite for the configurable entity-id-type work (PR cjmellor#125) and for
retrofitting the configurable user-key-type macro (PR cjmellor#124).
@cjmellor cjmellor force-pushed the feat/configurable-user-key-type branch from 42b148f to b47b0ac Compare May 17, 2026 20:10
cjmellor and others added 2 commits May 17, 2026 21:17
Add `level-up.user.foreign_key_type` (default `bigint`) so host apps
whose User model uses HasUuids or HasUlids can install the package
without manually editing every user-FK column. Migrations now route
through `LevelUp\Experience\Support\UserForeignKey::on()` which picks
`foreignId`/`foreignUuid`/`foreignUlid` from the config. Existing
installs see no change.

Affected migrations: experiences, streaks, achievement_user,
challenge_user, experience_audits, streak_histories.

Adds UuidUser/UlidUser fixtures and end-to-end flow tests for both key
types covering experience, streak and challenge flows.
@cjmellor cjmellor force-pushed the feat/configurable-user-key-type branch from b47b0ac to a534963 Compare May 17, 2026 20:21
@cjmellor cjmellor merged commit c49213c into main May 17, 2026
11 checks passed
@cjmellor cjmellor deleted the feat/configurable-user-key-type branch May 17, 2026 20:25
pull Bot pushed a commit to KornaLaravel/laravel-level-up that referenced this pull request May 17, 2026
Proof-of-shape for the (b) half of UUID/ULID support: lets host apps
choose the primary-key column type for the package's own entities so
package IDs can be exposed as UUIDs/ULIDs on a public API surface
(christoph-kluge's ask on PR cjmellor#124).

Wires:
- `level-up.entities.id_type` config (default `bigint`, accepts `uuid`/`ulid`)
- `Blueprint::entityId()` / `Blueprint::entityForeignId()` macros registered
  in `LevelUpServiceProvider::bootingPackage()`. Now safe in tests after
  PR cjmellor#125 moved package migrations to run after providers boot.
- `Concerns\HasConfigurableIds` trait — composes Laravel's `HasUniqueIds`,
  reads config at runtime, no-ops in bigint mode.
- Applied to the `Experience` model + `create_experiences_table` stub as
  the shape proof; remaining 12 models + migrations follow next.

BC: with default config, the trait's `uniqueIds()` returns `[]` so
`HasUniqueIds`' creating-hook no-ops, `getKeyType()` returns `int`, and
`getIncrementing()` returns `true` — byte-identical to today. Existing
installs see no change.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant