Skip to content

Commit 60df40e

Browse files
committed
feat: replace mock user helpers with Prisma-backed profile API
- Add firstName, lastName, bio, avatar fields to User model in Prisma schema - Add LearnerProfile model with display name, country, timezone, languages, skill level, interests, goals, and visibility/consent controls - Add OnboardingState model tracking profile completion, email verification, wallet connection, session booking, credential earning, and consent - Create user.service.ts with Prisma-backed methods: - findUserById with profile, onboarding, and profile completion - updateUserProfile with audit logging - updateUserProfileData for LearnerProfile upsert - validatePassword using bcrypt.compare - updateUserPassword using bcrypt hash - updateUserWallet with onboarding state update - getPublicProfile with consent-aware visibility check - getProfileCompletion and getOnboardingState - Update UserController to use service instead of mock helpers - Add audit logging for PROFILE_UPDATED, PASSWORD_CHANGED, WALLET_UPDATED - Add public profile read respecting LearnerProfile visibility - Return profileCompletion and onboardingState in user responses - Add GET /me/profile route for extended profile - Update tests to mock Prisma instead of spying on private methods - All 318 tests pass, TypeScript compiles cleanly Closes: #85
1 parent 53aa17a commit 60df40e

7 files changed

Lines changed: 954 additions & 597 deletions

File tree

package.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,9 @@
7575
"typescript-eslint": "^8.56.0",
7676
"vitest": "^4.0.18"
7777
},
78+
"pnpm": {
79+
"onlyBuiltDependencies": ["@prisma/engines", "prisma", "esbuild"]
80+
},
7881
"packageManager": "pnpm@10.0.0",
7982
"prisma": {
8083
"seed": "tsx prisma/seed.ts"

prisma/schema.prisma

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,18 @@ model User {
1111
email String @unique
1212
username String @unique
1313
password String
14+
firstName String?
15+
lastName String?
16+
bio String?
17+
avatar String?
1418
role Role @default(LEARNER)
1519
walletAddress String? @unique
1620
isVerified Boolean @default(false)
1721
createdAt DateTime @default(now())
1822
updatedAt DateTime @updatedAt
1923
lastLoginAt DateTime?
24+
profile LearnerProfile?
25+
onboarding OnboardingState?
2026
completions Completion[]
2127
credentials Credential[]
2228
transactions Transaction[]
@@ -35,6 +41,45 @@ model User {
3541
@@map("users")
3642
}
3743

44+
model LearnerProfile {
45+
id String @id @default(uuid())
46+
userId String @unique
47+
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
48+
displayName String?
49+
country String?
50+
timezone String?
51+
languages String @default("[]") // JSON array
52+
skillLevel String? // beginner, intermediate, advanced
53+
interests String @default("[]") // JSON array
54+
goals String @default("[]") // JSON array
55+
visibility String @default("public") // public, private, mentor_only
56+
consentGiven Boolean @default(false)
57+
consentAt DateTime?
58+
createdAt DateTime @default(now())
59+
updatedAt DateTime @updatedAt
60+
61+
@@map("learner_profiles")
62+
}
63+
64+
model OnboardingState {
65+
id String @id @default(uuid())
66+
userId String @unique
67+
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
68+
profileComplete Boolean @default(false)
69+
emailVerified Boolean @default(false)
70+
walletConnected Boolean @default(false)
71+
firstSessionBooked Boolean @default(false)
72+
firstCredentialEarned Boolean @default(false)
73+
consentProvided Boolean @default(false)
74+
completedSteps String @default("[]") // JSON array of step keys
75+
currentStep String @default("welcome")
76+
dismissed Boolean @default(false)
77+
createdAt DateTime @default(now())
78+
updatedAt DateTime @updatedAt
79+
80+
@@map("onboarding_states")
81+
}
82+
3883
model Session {
3984
id String @id @default(uuid())
4085
userId String

0 commit comments

Comments
 (0)