Skip to content

Commit 9752709

Browse files
committed
feat: add auth backend flow
1 parent c602ee0 commit 9752709

24 files changed

Lines changed: 1824 additions & 12948 deletions

File tree

apps/backend/package.json

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,12 @@
1414
"db:migrate": "prisma migrate dev",
1515
"db:deploy": "prisma migrate deploy",
1616
"db:seed": "tsx prisma/seed.ts",
17-
"db:studio": "prisma studio"
17+
"db:studio": "prisma studio",
18+
"postinstall": "prisma generate",
19+
"typecheck": "tsc --noEmit"
1820
},
1921
"dependencies": {
20-
"@devcard/shared": "workspace:*",
22+
"@devcard/shared": "file:../../packages/shared",
2123
"@fastify/cookie": "^11.0.0",
2224
"@fastify/cors": "^10.0.0",
2325
"@fastify/helmet": "^12.0.0",

apps/backend/prisma/migrations/20260312125106_init/migration.sql

Lines changed: 0 additions & 99 deletions
This file was deleted.

apps/backend/prisma/migrations/20260312162249_analytics_models/migration.sql

Lines changed: 0 additions & 38 deletions
This file was deleted.

apps/backend/prisma/migrations/20260615051500_card_sharing/migration.sql

Lines changed: 0 additions & 25 deletions
This file was deleted.

apps/backend/prisma/schema.prisma

Lines changed: 67 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,12 @@ datasource db {
66
url = env("DATABASE_URL")
77
88
}
9-
9+
enum Role{
10+
SUPERADMIN
11+
ADMIN
12+
USER
13+
14+
}
1015
model User {
1116
id String @id @default(uuid())
1217
email String @unique
@@ -15,28 +20,64 @@ model User {
1520
bio String?
1621
pronouns String?
1722
role String?
23+
authRole Role @default(USER)
1824
company String?
1925
avatarUrl String? @map("avatar_url")
2026
accentColor String @default("#6366f1") @map("accent_color")
21-
provider String
22-
providerId String @map("provider_id")
27+
emailVerified Boolean @default(false) @map("email_verified")
28+
phoneNumber String? @unique @map("phone_number")
29+
lastSignInAt DateTime? @map("last_sign_in_at")
2330
createdAt DateTime @default(now()) @map("created_at")
2431
updatedAt DateTime @updatedAt @map("updated_at")
32+
isActive Boolean @default(false)
2533
34+
identities UserIdentity[]
35+
refreshTokens RefreshToken[]
2636
platformLinks PlatformLink[]
2737
cards Card[]
2838
oauthTokens OAuthToken[]
2939
ownedViews CardView[] @relation("cardOwner")
3040
viewedCards CardView[] @relation("cardViewer")
3141
followLogs FollowLog[]
32-
organizer Event[]
33-
attendedEvents EventAttendee[]
42+
organizer Event[]
43+
attendedEvents EventAttendee[]
44+
ownedTeams Team[] @relation("TeamOwner")
45+
teamMemberships TeamMember[] @relation("TeamMember")
46+
47+
@@map("users")
48+
}
49+
50+
model UserIdentity {
51+
id String @id @default(uuid())
52+
userId String @map("user_id")
53+
provider String // "google.com" | "apple.com" | "firebase" | "phone"
54+
providerId String @map("provider_id") // Google sub / Apple sub / Firebase UID
55+
createdAt DateTime @default(now()) @map("created_at")
3456
35-
ownedTeams Team[] @relation("TeamOwner")
36-
teamMemberships TeamMember[] @relation("TeamMember")
57+
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
3758
3859
@@unique([provider, providerId])
39-
@@map("users")
60+
@@index([userId])
61+
@@map("user_identities")
62+
}
63+
64+
65+
model RefreshToken {
66+
id String @id @default(uuid())
67+
userId String @map("user_id")
68+
tokenHash String @unique @map("token_hash") //SHA-256 hash
69+
family String // token rotation
70+
expiresAt DateTime @map("expires_at")
71+
revokedAt DateTime? @map("revoked_at") // null = still valid
72+
createdAt DateTime @default(now()) @map("created_at")
73+
userAgent String? @map("user_agent")
74+
ip String? //hash
75+
76+
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
77+
78+
@@index([userId])
79+
@@index([family])
80+
@@map("refresh_tokens")
4081
}
4182

4283
model PlatformLink {
@@ -55,27 +96,35 @@ model PlatformLink {
5596
}
5697

5798
enum CardVisibility {
58-
PUBLIC
59-
UNLISTED
60-
PRIVATE
99+
PUBLIC // Anyone can view the card
100+
UNLISTED // Anyone with the link can view, but not publicly listed
101+
PRIVATE // Only the card owner can view
61102
}
62103

63104
model Card {
64105
id String @id @default(uuid())
65106
userId String @map("user_id")
107+
66108
title String
67-
description String?
68-
slug String @unique
109+
description String?
110+
111+
slug String @unique
112+
69113
visibility CardVisibility @default(PUBLIC)
70-
qrEnabled Boolean @default(true) @map("qr_enabled")
71-
viewCount Int @default(0) @map("view_count")
114+
115+
qrEnabled Boolean @default(true)
116+
117+
viewCount Int @default(0)
118+
72119
isDefault Boolean @default(false) @map("is_default")
73120
createdAt DateTime @default(now()) @map("created_at")
74121
updatedAt DateTime @updatedAt @map("updated_at")
75122
76123
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
124+
77125
cardLinks CardLink[]
78126
views CardView[]
127+
79128
80129
@@map("cards")
81130
@@index([userId])
@@ -117,7 +166,7 @@ model CardView {
117166
cardId String? @map("card_id") // null = default profile view
118167
ownerId String @map("owner_id") // card/profile owner
119168
viewerId String? @map("viewer_id") // null = anonymous web viewer
120-
viewerIp String? @map("viewer_ip")
169+
viewerIp String? @map("viewer_ip") //hashed
121170
viewerAgent String? @map("viewer_agent")
122171
source String @default("qr") // "qr" | "link" | "web" | "app"
123172
createdAt DateTime @default(now()) @map("created_at")
@@ -203,10 +252,10 @@ model TeamMember{
203252
role TeamRole
204253
joinedAt DateTime
205254
206-
team Team @relation("TeamMember",fields: [teamId] , references: [id])
255+
team Team @relation("TeamMember",fields: [teamId] , references: [id], onDelete: Cascade)
207256
user User @relation("TeamMember",fields: [userId] , references: [id])
208257
209258
@@unique([userId, teamId])
210259
@@index([userId])
211260
@@map("team_members")
212-
}
261+
}

0 commit comments

Comments
 (0)