Skip to content

Repository files navigation

QRP

QRP는 ** QR 코드 기반 응급 의료정보 제공 서비스**입니다. 헬멧이나 안전모 혹은 차량에 부착된 QR 코드를 구조자나 의료진이 스캔하면, 로그인 없이도 응급처치에 필요한 핵심 의료정보와 긴급연락처를 빠르게 확인할 수 있습니다.

문제 정의

사고 현장에서는 환자의 상세 병력보다도 아래 정보가 먼저 필요합니다.

  • 혈액형
  • 알레르기
  • 기저질환
  • 복용 중인 약
  • 긴급 연락처

QRP는 이 정보를 QR 스캔 한 번으로 즉시 조회할 수 있게 해, 응급 대응 시간을 줄이는 것을 목표로 합니다.

주요 기능

  • QR 코드 등록 기반 회원가입
    • 사용자 계정과 QR 코드를 연결
    • 아이디 중복 확인 지원
  • 3단계 의료정보 등록 플로우
    • 계정 정보
    • 개인 정보
    • 건강 정보
  • QR 기반 공개 의료정보 조회
    • /medical-info/:qrCode 경로로 로그인 없이 접근 가능
  • 로그인/로그아웃 및 세션 유지
    • JWT를 HttpOnly 쿠키로 관리
  • 의료정보 수정 기능
    • 등록된 QR 코드 기준으로 정보 수정 가능
  • 민감정보 암호화 저장
    • 이름, 생년월일, 혈액형, 알레르기, 연락처 등 주요 필드를 DB 저장 시 암호화
  • 모노레포 기반 공통 타입/스키마 공유
    • 프론트엔드와 백엔드가 packages/shared의 Zod 스키마를 함께 사용

아키텍처

[사용자/구조자 브라우저]
        |
        v
[React + Vite Web App]
        |
        | REST API + Cookie Credentials
        v
[NestJS API Server]
        |
        v
[MySQL]

구성 의도

  • apps/web
    • 모바일 우선 UI
    • QR 등록, 로그인, 의료정보 조회/수정 화면 제공
  • apps/api
    • 사용자 등록, 인증, 공개 의료정보 조회 API 제공
    • JWT 쿠키 인증과 DB 접근 담당
  • packages/shared
    • Zod 스키마와 DTO 타입 공유
    • 프론트/백엔드 데이터 계약 일원화
  • packages/ui
    • 공통 UI 컴포넌트 패키지
    • shadcn/ui 기반 디자인 시스템 역할

배포 및 인프라 아키텍처

가독성을 위해 이 문서는 운영(Production) 아키텍처로컬 개발(Local Development) 아키텍처를 분리해서 설명합니다.

  • 운영 환경에서는 Vercel + DNS + EC2(Nginx/PM2/NestJS/MySQL) 가 핵심입니다.
  • 개발 환경에서는 Vite dev server + /api 프록시 가 핵심입니다.

운영(Production) 아키텍처

Vercel EC2 Custom Domain 배포 아키텍처

운영 요청 흐름 요약

  1. 사용자는 Vercel에 배포된 프론트엔드에 HTTPS로 접속합니다.
  2. 프론트엔드는 API 요청을 https://api.emergencyqr.cc 로 보냅니다.
  3. DNS가 api.emergencyqr.cc 를 현재 EC2 IP(3.37.129.25)로 해석합니다.
  4. EC2의 NginxHost: api.emergencyqr.cc 기준으로 요청을 받습니다.
  5. Nginx가 요청을 localhost:4000PM2-managed NestJS API 로 프록시합니다.
  6. NestJS API는 필요 시 MySQL 과 통신합니다.

Host 레벨 vs Path 레벨

이 프로젝트를 이해할 때 가장 중요한 포인트는 도메인(host) 라우팅애플리케이션 path 라우팅이 분리되어 있다는 점입니다.

1) Host 레벨: Nginx가 처리

예: https://api.emergencyqr.cc/auth/me

  • host: api.emergencyqr.cc
  • path: /auth/me

여기서 Nginx는 먼저 api.emergencyqr.cc 라는 호스트명으로 어떤 server block을 사용할지 결정합니다. 즉 api.emergencyqr.ccURL path가 아니라 도메인/호스트 레벨입니다.

2) Path 레벨: NestJS가 처리

Nginx가 프록시한 뒤에는 NestJS가 실제 경로를 처리합니다. 현재 백엔드 컨트롤러 기준 path는 다음과 같습니다.

  • /
  • /auth/*
  • /users/*

즉 현재 백엔드에는 global /api prefix가 없습니다.

로컬 개발(Local Development) 아키텍처

[Developer Browser]
      |
      | requests /api/...
      v
[Vite Dev Server :5173]
      |
      | proxy + rewrite
      | /api/foo  ->  http://localhost:4000/foo
      v
[NestJS API :4000]
      |
      v
[MySQL]

개발 환경의 /api 프록시 동작

  • apps/web/vite.config.ts 에서 개발 서버 프록시가 설정되어 있습니다.
  • 개발 환경에서는 /api/* 요청이 http://localhost:4000/* 으로 프록시됩니다.
  • 이때 Vite가 rewrite: (path) => path.replace(/^\/api/, "")/api prefix를 제거한 뒤 백엔드로 전달합니다.
  • 프론트 axios 클라이언트(apps/web/src/api/axios.ts)는 다음 우선순위로 API base URL을 결정합니다.
    1. import.meta.env.VITE_API_URL
    2. 값이 없으면 기본값 "/api"

즉:

  • 로컬 개발의 브라우저 요청 경로/api/... 일 수 있고,
  • 실제 NestJS 서버 라우트/auth/..., /users/... 처럼 /api 없이 동작합니다.
  • 이 차이를 메워주는 레이어가 바로 Vite dev proxy 입니다.

운영 환경에서의 API 호출 방식

운영 배포에서는 Vite dev proxy가 존재하지 않으므로, 프론트는 VITE_API_URL 을 통해 API 도메인을 직접 바라보는 구성이 자연스럽습니다.

예:

  • VITE_API_URL=https://api.emergencyqr.cc

이 경우 브라우저는:

  • /api/auth/me 가 아니라
  • https://api.emergencyqr.cc/auth/me 형태로 직접 호출하게 됩니다.

실제 확인한 라우트 동작

실제 서버에서 확인한 결과:

  • 동작함: /auth/me, /users/check-userid
  • 동작 안 함(404): /api/auth/me, /api/users/check-userid

즉 현재 구현 기준으로는 브라우저 쪽 요청 경로는 /api 로 시작할 수 있지만, EC2 위의 NestJS 서버 자체 라우트는 /api prefix를 갖고 있지 않습니다.

참고한 실제 운영 설정

  • DNS resolution: api.emergencyqr.cc -> 3.37.129.25
  • Vercel config: /home/ubuntu/QRP/apps/web/vercel.json
  • Frontend API client: /home/ubuntu/QRP/apps/web/src/api/axios.ts
  • Vite proxy config: /home/ubuntu/QRP/apps/web/vite.config.ts
  • Nginx site config: /etc/nginx/sites-available/qrp
  • PM2 process: qrp-api
  • API entry: /home/ubuntu/QRP/apps/api/dist/main.js

기술 스택

Frontend

  • React 19
  • Vite 7
  • TypeScript
  • React Router 7
  • Zustand
  • React Hook Form
  • Zod
  • Tailwind CSS 4
  • shadcn/ui
  • @zxing/browser (QR 스캔)

Backend

  • NestJS 11
  • TypeScript
  • TypeORM
  • MySQL
  • JWT
  • cookie-parser
  • bcrypt

Monorepo / Tooling

  • pnpm workspace
  • Turborepo
  • ESLint
  • Prettier

저장소 구조

QRP/
├─ apps/
│  ├─ web/          # React + Vite 프론트엔드
│  └─ api/          # NestJS 백엔드
├─ packages/
│  ├─ shared/       # 공통 스키마 / DTO / 타입
│  └─ ui/           # 공통 UI 컴포넌트
├─ package.json
├─ pnpm-workspace.yaml
└─ turbo.json

핵심 사용자 흐름

  1. 사용자가 회원가입 화면에서 QR 코드와 계정을 연결합니다.
  2. 개인 정보와 의료 정보를 입력합니다.
  3. 정보는 백엔드에서 검증 후 저장되며, 민감 필드는 암호화됩니다.
  4. 사고 발생 시 구조자가 QR 코드를 스캔합니다.
  5. 브라우저에서 해당 QR의 공개 의료정보 페이지가 열립니다.
  6. 구조자는 필요한 응급 정보를 즉시 확인합니다.

로컬 실행 방법

1) 요구 사항

  • Node.js 20+
  • pnpm 10+
  • MySQL

2) 의존성 설치

루트에서 실행:

pnpm install

3) 환경변수 설정

Backend

cp apps/api/.env.example apps/api/.env.development

apps/api/.env.development 예시 항목:

NODE_ENV=development
DB_TYPE=mysql
DB_HOST=localhost
DB_PORT=3306
DB_USER=root
DB_PASSWORD=
DB_NAME=qrp
JWT_SECRET=
JWT_EXPIRES_IN=1h
ENCRYPTION_SECRET_KEY=
CORS_ORIGIN=http://localhost:5173
FRONTEND_URL=http://localhost:5173

Frontend

cp apps/web/.env.example apps/web/.env.development

apps/web/.env.example

VITE_API_URL=http://localhost:4000

참고: 개발 환경에서는 Vite proxy가 /api -> http://localhost:4000 으로 연결되도록 설정되어 있습니다.

4) 데이터베이스 준비

MySQL에서 qrp 데이터베이스를 생성한 뒤, 백엔드 환경변수의 접속 정보를 맞춰주세요.

예시:

CREATE DATABASE qrp;

5) 개발 서버 실행

루트에서 실행:

pnpm dev

기본 동작:

  • web: http://localhost:5173
  • api: http://localhost:4000

개별 스크립트

루트

pnpm dev
pnpm build
pnpm lint
pnpm format
pnpm typecheck

Web

pnpm --filter web dev
pnpm --filter web build
pnpm --filter web preview

API

pnpm --filter api dev
pnpm --filter api build
pnpm --filter api test

주요 API

인증

  • POST /auth/login
  • POST /auth/logout
  • GET /auth/me

사용자 / 의료정보

  • POST /users — 회원가입
  • GET /users/check-userid?userId=... — 아이디 중복 확인
  • GET /users/medical-info/:qrCode — 공개 의료정보 조회
  • PATCH /users/medical-info/:qrCode — 의료정보 수정

보안 메모

  • 로그인 상태는 HttpOnly 쿠키 기반으로 관리됩니다.
  • 의료정보 주요 필드는 ENCRYPTION_SECRET_KEY를 사용해 암호화 저장됩니다.
  • 운영 환경에서는 아래 항목을 반드시 점검해야 합니다.
    • 강력한 JWT_SECRET
    • 안전한 ENCRYPTION_SECRET_KEY
    • 정확한 CORS_ORIGIN
    • HTTPS 환경에서의 쿠키 정책

향후 개선 아이디어

  • QR 코드 발급/관리 어드민 기능
  • 구조자 전용 읽기 화면 UX 개선
  • 의료정보 접근 로그/감사 기능
  • 비상 연락 알림 연동
  • 테스트 코드 및 배포 문서 보강

프로젝트 목표 한 줄 요약

QRP는 사고 현장에서 QR 코드로 라이더의 핵심 의료정보를 빠르게 전달하기 위한 서비스입니다.

About

qr코드를 통한 의료정보 제공

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages