cfd550bed8
Deploy via SSH / remote-deploy (push) Failing after 6s
Backend (server/src): - services/anthropic.ts — Claude API 래퍼 (키 없으면 룰베이스 fallback) - services/ocr.ts — Naver Clova + Google Vision 듀얼 연동 + 영수증 필드 파서 - services/solapi.ts — 카카오 알림톡 HMAC 서명 + 드라이런 - services/expoPush.ts — Expo Push API 전송 - services/codef.ts — 보험 통합조회 mock + 실연동 포인트 - routes/ai.ts, ocr.ts, devices.ts, social.ts (naver/apple), alimtalk.ts, codef.ts - Prisma: PushDevice 모델 + binaryTargets linux-musl-openssl-3.0.x - Dockerfile: apk add openssl (Prisma schema engine 정상화) - api-secrets에 9개 외부 API 키 슬롯 추가 (optional) Frontend: - api/endpoints.ts: aiApi, ocrApi, deviceApi, socialApi, codefApi - services/kakao.ts — Kakao JS SDK 동적 로드 + Auth.login - services/push.ts — expo-notifications 권한/토큰 등록 + 서버 전송 - LoginScreen — 카카오/네이버/애플 버튼 (웹은 토큰 입력 fallback) - AIJudgeScreen — 실제 /ai/claim-judge 호출, source(llm/rules) 표시 - ClaimScreen — 영수증 촬영 시 자동 OCR → 병원/날짜/제목 자동 기입 - useAuthStore hydrate 시 푸시 토큰 등록 Infra: - eas.json (development/preview/production 빌드 프로필) - API_KEYS.md — 9개 외부 서비스 발급/등록 가이드 - scripts/deploy-remote.sh 개선 (sudo 정확히, traefik cp 버그 수정, API fail 시 로그 출력) - deploy/k8s/api.yaml — 외부 API 키 환경변수 매핑 (optional=true) CI/CD: - .gitea/workflows/deploy.yml → SSH 기반으로 전환 (appleboy/ssh-action으로 서버 접속 → deploy-remote.sh 실행) - 필요 Secrets: SSH_HOST, SSH_USER, SSH_PASSWORD Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
275 lines
5.6 KiB
Plaintext
275 lines
5.6 KiB
Plaintext
generator client {
|
|
provider = "prisma-client-js"
|
|
binaryTargets = ["native", "linux-musl", "linux-musl-openssl-3.0.x"]
|
|
}
|
|
|
|
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[]
|
|
devices PushDevice[]
|
|
}
|
|
|
|
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])
|
|
}
|
|
|
|
enum DevicePlatform {
|
|
ios
|
|
android
|
|
web
|
|
}
|
|
|
|
model PushDevice {
|
|
id String @id @default(cuid())
|
|
userId String
|
|
expoPushToken String @unique
|
|
platform DevicePlatform
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
|
|
@@index([userId])
|
|
}
|