f78949c21a
Build & Deploy / build-and-deploy (push) Failing after 9s
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>
62 lines
1.9 KiB
TypeScript
62 lines
1.9 KiB
TypeScript
import type { FastifyInstance } from 'fastify';
|
|
import { z } from 'zod';
|
|
import { computeScore } from './score';
|
|
|
|
const DiagnosisBody = z.object({
|
|
answers: z.record(z.string(), z.string()),
|
|
});
|
|
|
|
export async function diagnosisRoutes(app: FastifyInstance) {
|
|
app.addHook('onRequest', app.authenticate);
|
|
|
|
app.get('/', async (req) => {
|
|
return app.prisma.diagnosis.findMany({
|
|
where: { userId: req.user.sub },
|
|
orderBy: { createdAt: 'desc' },
|
|
take: 10,
|
|
});
|
|
});
|
|
|
|
app.post('/', async (req, reply) => {
|
|
const body = DiagnosisBody.parse(req.body);
|
|
const score = await computeScore(app, req.user.sub);
|
|
const recommendations = recommend(body.answers, score.breakdown);
|
|
|
|
const saved = await app.prisma.diagnosis.create({
|
|
data: {
|
|
userId: req.user.sub,
|
|
answers: body.answers,
|
|
score: score.total,
|
|
breakdown: { categories: score.breakdown, recommendations },
|
|
},
|
|
});
|
|
reply.code(201);
|
|
return saved;
|
|
});
|
|
}
|
|
|
|
function recommend(answers: Record<string, string>, breakdown: Array<{ label: string; status: string }>) {
|
|
const recs: Array<{ name: string; reason: string; priority: '필수' | '권장' | '선택' }> = [];
|
|
|
|
const missing = breakdown.filter((b) => b.status === 'none' || b.status === 'bad');
|
|
missing.forEach((m) => {
|
|
recs.push({
|
|
name: m.label,
|
|
reason: `현재 ${m.status === 'none' ? '미가입' : '보장 부족'}`,
|
|
priority: m.label === '실손보험' ? '필수' : '권장',
|
|
});
|
|
});
|
|
|
|
if (answers.family === '있음') {
|
|
recs.push({ name: '암보험 진단비 강화', reason: '가족력 있음', priority: '필수' });
|
|
}
|
|
if (answers.smoke === '흡연') {
|
|
recs.push({ name: '뇌혈관/심장 특약', reason: '흡연자 고위험군', priority: '권장' });
|
|
}
|
|
if (answers.hospital === '3회 이상') {
|
|
recs.push({ name: '입원일당 특약', reason: '잦은 입원 이력', priority: '권장' });
|
|
}
|
|
|
|
return recs.slice(0, 6);
|
|
}
|