μ΅μ΄ μμ±: 2026-10-08 | μ΅μ’
μ
λ°μ΄νΈ: 2026-10-14
ADR-001(FE λ°°ν¬), ADR-004(λ°±μλ κΈ°μ μ€ν) λ°μ
graph TD
subgraph Client
WEB[React PWA<br/>Vite + TypeScript<br/>max-width 390px]
end
subgraph Vercel
CDN[Vercel Edge<br/>μ μ νμΌ μλΉ]
end
subgraph Server["μλ² (λ°°ν¬ νκ²½ λ―Έμ )"]
API[Spring Boot REST API<br/>:8080]
end
subgraph Storage
DB[(MySQL)]
S3[AWS S3<br/>λ―Έλμ΄ νμΌ]
end
subgraph External
GOOGLE[Google OAuth 2.0]
OPENAI[OpenAI API<br/>Whisper STT + GPT-4o]
end
WEB -->|HTTPS / JSON| API
WEB -->|λ°°ν¬| CDN
API -->|JPA| DB
API -->|SDK v2| S3
API -->|OAuth ν ν° κ²μ¦| GOOGLE
API -->|μμ± μ μ¬ + κΈ°λ‘ μ΄μ| OPENAI
WEB -->|Presigned URL μ§μ μ
λ‘λ κ°λ₯| S3
Loading
PIC-2-team-project/
βββ frontend/ β React PWA (Vite + TypeScript)
βββ backend/ β Spring Boot
| νλͺ© |
κΈ°μ |
| νλ μμν¬ |
React 19 + TypeScript 6 |
| λ²λ€λ¬ |
Vite 8 |
| λΌμ°ν° |
react-router-dom 7 |
| ν
μ€νΈ |
Vitest + @testing-library/react |
| PWA |
vite-plugin-pwa |
| λ°°ν¬ |
Vercel (main λΈλμΉ push β μλ λ°°ν¬) |
| νλͺ© |
κΈ°μ |
| νλ μμν¬ |
Spring Boot 4.1.1 + Java 21 |
| ORM |
Spring Data JPA + Hibernate |
| DB |
MySQL 8.x (νλ‘λμ
), H2 (κ°λ°) |
| μΈμ¦ |
Spring Security 7 + jjwt 0.12.x |
| Refresh Token |
DB ν
μ΄λΈ (refresh_tokens) |
| OAuth |
spring-security-oauth2-client (Google) |
| νμΌ μ€ν λ¦¬μ§ |
AWS S3 (AWS SDK v2) |
| AI |
OpenAI Java SDK β Whisper STT + GPT-4o |
| API λ¬Έμ |
springdoc-openapi 3.1.0 (Swagger UI) |
| μ νΈ |
Lombok |
κ²°μ κ·Όκ±°μ κ²ν ν λμ: ADR-001, ADR-004
| μλΉμ€ |
ν¬νΈ |
| FE (dev) |
3000 |
| BE |
8080 |
| DB |
3306 |
| Swagger UI |
http://localhost:8080/swagger-ui |
| OpenAPI JSON |
http://localhost:8080/api-docs |
- ν΄λΌμ΄μΈνΈ β
POST /api/auth/login β access token (15λΆ, Bearer) + refresh token (30μΌ, HttpOnly cookie)
- λ³΄νΈ API μμ²:
Authorization: Bearer {accessToken} ν€λ
- λ§λ£ μ
POST /api/auth/refresh β μ access token λ°κΈ
- ν΄λΌμ΄μΈνΈ β
POST /api/care-recipients/{id}/media (μλ² νλ‘μ λ°©μ)
- μλ² β AWS S3 μ
λ‘λ β
mediaId λ°ν
- λ€μ΄λ‘λ:
GET /api/.../media/{id}/download-url β 5λΆ μ ν¨ Presigned URL
AI κΈ°λ‘ μ΄μ μμ± νλ¦
- ν΄λΌμ΄μΈνΈ β
POST /api/ai/record-drafts (ν
μ€νΈ λλ μμ± mediaId)
- μλ² β Whisper STT (μμ±μΈ κ²½μ°) β GPT-4o μΉ΄ν
κ³ λ¦¬ λΆλ₯ + μ΄μ μμ± β
transcript, content, category λ°ν
- ν΄λΌμ΄μΈνΈ β μμ ν
POST /api/care-recipients/{id}/records λ‘ μ μ₯
| νλͺ© |
κ²°μ |
κ·Όκ±° |
| FE λ°°ν¬ νκ²½ |
Vercel Hobby (MVP), μμ
ν μ Vercel Pro λλ Cloudflare Pages |
ADR-001 |
| BE λ°°ν¬ νκ²½ |
λ―Έμ β ν΄λΌμ°λ λ°°ν¬ νκ²½ μ μ νμ |
β |
| μΈμ¦ ν ν° μ μ₯ λ°©μ |
access token: Bearer ν€λ, refresh token: HttpOnly Secure cookie + DB ν
μ΄λΈ |
ADR-004 |
| νμΌ μ
λ‘λ μ€ν λ¦¬μ§ |
AWS S3 (μλ² νλ‘μ μ
λ‘λ, Presigned URL λ€μ΄λ‘λ) |
ADR-004 |