Files
insurance/server/prisma/schema.prisma
T
chpark f78949c21a
Build & Deploy / build-and-deploy (push) Failing after 9s
feat: 실제 동작하는 백엔드 + DB + 카카오 로그인
Backend (server/):
- Fastify + Prisma + PostgreSQL 16
- JWT 인증 (bcrypt) + 카카오 OAuth (/auth/kakao — kapi.kakao.com 호출)
- REST API: auth, users, family, policies, claims, score, notifications, diagnosis, consults
- 실제 보험점수 알고리즘 (카테고리별 가중치·최소보장 기반)
- Multipart 업로드 (영수증/진단서 → 디스크 persistence)
- Swagger UI /docs

Client:
- api/client.ts + api/endpoints.ts (fetch 래퍼 + AsyncStorage 토큰)
- 인증 스토어 (hydrate/login/register/kakao/logout)
- 로그인/회원가입 화면 + 카카오 버튼
- 홈/내보험/가족/점수/청구 API 연동 (pull-to-refresh)
- 보험 추가 모달 + 가족 구성원 추가 모달
- 로그인 전/후 스택 분기 (RootNavigator)

Infra:
- docker-compose.yml (로컬 Postgres+API)
- server/Dockerfile (Prisma migrate deploy + node)
- deploy/k8s/postgres.yaml (StatefulSet + 10Gi PVC)
- deploy/k8s/api.yaml (Deployment + Ingress api.insurance.junggomoa.com)
- CI workflow 확장 (web + api 동시 빌드·배포)
- POSTGRES_PASSWORD / JWT_SECRET Gitea Secrets 추가 필요
- 반응형 웹 레이아웃 (max-width 480px 폰 프레임)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-23 00:32:44 +09:00

254 lines
5.1 KiB
Plaintext

generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
enum AuthProvider {
EMAIL
KAKAO
APPLE
NAVER
GOOGLE
}
model User {
id String @id @default(cuid())
email String? @unique
passwordHash String?
name String
phone String?
provider AuthProvider @default(EMAIL)
kakaoId String? @unique
appleSub String? @unique
naverId String? @unique
googleId String? @unique
profileImage String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
profile Profile?
family FamilyMember[]
policies Policy[]
claims Claim[]
notifications Notification[]
diagnoses Diagnosis[]
healthChecks HealthCheck[]
consults Consult[]
}
model Profile {
id String @id @default(cuid())
userId String @unique
age Int
gender Gender
job String?
monthlyPremium Int @default(0)
score Int @default(0)
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
}
enum Gender {
MALE
FEMALE
}
enum Relation {
SELF
SPOUSE
CHILD
PARENT
SIBLING
}
model FamilyMember {
id String @id @default(cuid())
userId String
relation Relation
name String
age Int
gender Gender
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
policies Policy[]
@@index([userId])
}
enum PolicyType {
SILSON
CANCER
LIFE
ACCIDENT
CHILD
NURSING
FEMALE
DENTAL
DRIVER
CAR
}
model Policy {
id String @id @default(cuid())
userId String
familyMemberId String?
name String
insurer String
type PolicyType
monthlyPremium Int
coverage BigInt
joinDate DateTime
maturityDate DateTime?
renewalDate DateTime?
silsonGen Int?
isGroup Boolean @default(false)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
familyMember FamilyMember? @relation(fields: [familyMemberId], references: [id], onDelete: SetNull)
@@index([userId])
@@index([familyMemberId])
}
enum ClaimStatus {
SUBMITTED
REVIEWING
ADDITIONAL_DOCS
APPROVED
PAID
REJECTED
}
model Claim {
id String @id @default(cuid())
userId String
title String
hospital String?
visitDate DateTime?
status ClaimStatus @default(SUBMITTED)
amount Int?
aiEstimated String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
attachments ClaimAttachment[]
events ClaimEvent[]
@@index([userId, status])
}
enum AttachmentType {
RECEIPT
DIAGNOSIS
DETAIL
OTHER
}
model ClaimAttachment {
id String @id @default(cuid())
claimId String
type AttachmentType
objectKey String
mimeType String?
size Int?
createdAt DateTime @default(now())
claim Claim @relation(fields: [claimId], references: [id], onDelete: Cascade)
@@index([claimId])
}
model ClaimEvent {
id String @id @default(cuid())
claimId String
status ClaimStatus
note String?
createdAt DateTime @default(now())
claim Claim @relation(fields: [claimId], references: [id], onDelete: Cascade)
@@index([claimId])
}
enum NotificationTone {
INFO
WARN
DANGER
}
model Notification {
id String @id @default(cuid())
userId String
title String
body String
tone NotificationTone @default(INFO)
scheduled DateTime
readAt DateTime?
createdAt DateTime @default(now())
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
@@index([userId, scheduled])
}
model Diagnosis {
id String @id @default(cuid())
userId String
answers Json
score Int
breakdown Json
createdAt DateTime @default(now())
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
@@index([userId])
}
model HealthCheck {
id String @id @default(cuid())
userId String
date DateTime
metrics Json
summary String?
createdAt DateTime @default(now())
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
@@index([userId, date])
}
enum ConsultMethod {
KAKAO
PHONE
VISIT
}
enum ConsultStatus {
REQUESTED
SCHEDULED
DONE
CANCELED
}
model Consult {
id String @id @default(cuid())
userId String
method ConsultMethod
phone String?
preferredAt DateTime?
memo String?
status ConsultStatus @default(REQUESTED)
createdAt DateTime @default(now())
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
@@index([userId, status])
}