Skip to content

fix: close four auth/schema gaps (PrismaModule import, typed mappers, UserStatus enum, session filter) - #860

Open
Zinai10 wants to merge 1 commit into
mux-labs:stagingfrom
Zinai10:fix/auth-schema-gaps-prisma-enum-typed-mappers
Open

fix: close four auth/schema gaps (PrismaModule import, typed mappers, UserStatus enum, session filter)#860
Zinai10 wants to merge 1 commit into
mux-labs:stagingfrom
Zinai10:fix/auth-schema-gaps-prisma-enum-typed-mappers

Conversation

@Zinai10

@Zinai10 Zinai10 commented Sep 1, 2026

Copy link
Copy Markdown

Summary

Closes four correctness gaps that could cause silent runtime failures in production:


Issue 1 – PrismaModule missing from AuthModule @Module imports

PrismaModule was imported at the top of auth.module.ts but omitted from @Module({ imports }), silently relying on a global side-effect. Without this, PrismaService cannot be injected into RefreshTokenService at runtime — auth token issuance would fail at startup in any module that doesn't happen to import PrismaModule elsewhere in its own graph.

Changes:

  • Added PrismaModule to AuthModule's imports array.
  • Fixed key-management.module.ts: added missing EventEmitterModule import and KeyValidationCacheService provider declaration.
  • Fixed jest moduleNameMapper: added mapping for the bare generated/prisma import path (only the /client suffix was mapped previously, causing test-suite compilation failures).
  • Rewrote auth.module.spec.ts as a fast Reflect.getMetadata regression guard — fails immediately if PrismaModule is ever removed from imports again.
  • Updated Prisma client mock to inline all enum values (eliminates a circular import that was blocking the test suite).

Issue 2 – mapPrismaXxx mappers typed as (prisma: any)

Three private mapper functions accepted any, hiding schema drift until runtime.

Changes:

  • wallets.service.ts: mapPrismaWalletToDomainPrismaWallet (generated Wallet row type).
  • users/idempotent-user.service.ts: mapPrismaUserToDomain and validateUserStatePrismaUser.
  • api-keys/api-key.service.ts: mapPrismaApiKeyToDomainPrismaApiKey.

Accessing a renamed or removed column now produces a TypeScript compile error (tsc --noEmit) rather than a silent undefined at runtime.


Issue 3 – User.status stored as free-form String

User.status was a String column with no DB-level constraint, meaning any arbitrary string could be written and the application would silently misinterpret it.

Changes:

  • Added UserStatus enum to prisma/schema.prisma with the five lifecycle states already authoritative in user.entity.ts: PROVISIONING, ACTIVE, RECOVERY_PENDING, SUSPENDED, DISABLED.
  • Changed User.status from String @default("ACTIVE")UserStatus @default(ACTIVE).
  • Added migration 20260831000001_add_user_status_enum with a safe upgrade path: normalises legacy INACTIVE rows to DISABLED, guards with a fail-fast DO 15858 block, then ALTER TABLE ... USING cast.
  • Regenerated Prisma client; generated UserStatus matches the entity enum exactly (same string values) — no application-layer casting changes required.

Issue 4 – Session filter enum alignment

AuthSessionFilterDto already uses UserStatus from user.entity.ts for its @IsEnum validator and Swagger @ApiProperty({ enum: UserStatus }). The controller's @ApiQuery decorator also documents the correct five states. No code changes needed — verified correct and explicitly documented.


Test coverage

Fix Verification
Issue 1 5 Reflect.getMetadata assertions in auth.module.spec.ts (all pass)
Issue 2 tsc --noEmit — compile-time enforcement; schema drift is now a build error
Issue 3 Migration fail-fast guard aborts on unrecognised values before ALTER TABLE
Issue 4 DTO validation verified correct; no behaviour change

No regressions introduced

  • No secrets logged.
  • No fail-open auth or rate-limit paths.
  • No new default secrets.
  • pnpm test suite unaffected for all files not touched by this PR.

closes #773
closes #774
closes #775
closes #776

…status enum, session filter)

Issue 1 – PrismaModule missing from AuthModule @module imports
- Added PrismaModule to AuthModule's imports array; it was imported at the
  top of the file but omitted from @module({ imports }), silently relying on
  a global side-effect registration. Without this, PrismaService cannot be
  injected into RefreshTokenService at runtime.
- Fixed key-management.module.ts: added missing EventEmitterModule import
  and KeyValidationCacheService import + provider declaration.
- Fixed jest moduleNameMapper: added mapping for the bare 'generated/prisma'
  import path used by refresh-token.service.ts (previously only the
  '/client' suffix was mapped).
- Rewrote auth.module.spec.ts as a fast, hermetic Reflect.getMetadata check
  that fails immediately if PrismaModule is ever removed from imports again.
- Updated Prisma client mock to inline all enum values, eliminating the
  circular-import problem that blocked the test suite.

Issue 2 – mapPrismaXxx mappers typed as (prisma: any)
- wallets.service.ts: mapPrismaWalletToDomain now accepts PrismaWallet
  (generated Wallet row type) instead of any.
- users/idempotent-user.service.ts: mapPrismaUserToDomain and
  validateUserState now accept PrismaUser instead of any.
- api-keys/api-key.service.ts: mapPrismaApiKeyToDomain now accepts
  PrismaApiKey instead of any.
- Schema drift (accessing a renamed/removed column) now causes a TypeScript
  compile error rather than a silent runtime bug.

Issue 3 – User.status stored as free-form String
- Added UserStatus enum to prisma/schema.prisma with the five lifecycle
  states already defined in user.entity.ts: PROVISIONING, ACTIVE,
  RECOVERY_PENDING, SUSPENDED, DISABLED.
- Changed User.status column from String @default("ACTIVE") to
  UserStatus @default(ACTIVE).
- Added migration 20260831000001_add_user_status_enum with a safe,
  fail-closed upgrade path: normalises legacy 'INACTIVE' rows to 'DISABLED',
  guards against unknown values, then ALTERs the column with an explicit
  USING cast.
- Regenerated Prisma client; the generated UserStatus enum matches the
  entity's UserStatus exactly (same string values), so no application-layer
  casting changes are needed.

Issue 4 – Session filter enum aligned with UserStatus
- AuthSessionFilterDto already uses UserStatus from user.entity.ts, so the
  DTO validation and the controller's @apiquery decorator both reflect the
  authoritative five-state enum. No behaviour change — this was verified
  correct and documented explicitly.

Test coverage
- auth.module.spec.ts: 5 regression guards via Reflect.getMetadata; will
  fail if PrismaModule is removed from imports or providers/exports change.
- Typed mappers: TypeScript compile-time enforcement (tsc --noEmit) catches
  schema drift; no new runtime tests needed for a pure type-narrowing change.
- Migration: fail-fast DO 15439 block aborts if unrecognised status values
  exist before the ALTER TABLE executes.

No secrets logged. No fail-open auth paths introduced.
@drips-wave

drips-wave Bot commented Sep 1, 2026

Copy link
Copy Markdown

@Zinai10 Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits.

You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀

Learn more about application limits

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant