"์์คํ ๋ ์ ๊ตฌํ๊ธฐ ์ํ ์ค์๊ฐ ํผ์ฆ ๋ ์ด์ค" โฑ๏ธ๐โโ๏ธ
SOS: Save Our Special day๋ ์ ํ ์๊ฐ ๋ด์ ์กฐ๊ฐ๋ ํผ์ฆ์ ๋ง์ถ๊ณ , ์ค์๊ฐ์ผ๋ก ๊ธฐ๋ก์ ๊ฒจ๋ฃจ๋ ๊ฒฝ์ํ ํผ์ฆ ์น ์ ํ๋ฆฌ์ผ์ด์ ์ ๋๋ค. ๐ฎ
๋ณธ ์๋น์ค๋ ์์ ํ **๋ ๋ฆฝ ๊ตฌ๋ํ ์๋น์ค(Self-Contained Service)**๋ก ์ค๊ณ๋์์ต๋๋ค. ํ๋ก ํธ์๋, ๋ฐฑ์๋ API ์๋ฒ, ๋ฐ์ดํฐ๋ฒ ์ด์ค(PostgreSQL), ๋ฉ๋ชจ๋ฆฌ ๋ด ๊ณ ์ ๋ฐ์ดํฐ ์ ์ฅ์(Redis)๊ฐ ํ๋์ Docker Compose๋ก ๋ฌถ์ฌ ์์ต๋๋ค. ๐ฆ ๋ฐ๋ผ์ ์ธ๋ถ ๋ฐ์ดํฐ๋ฒ ์ด์ค ๊ตฌ์ถ์ด๋ ๋ฒ๊ฑฐ๋ก์ด ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์์กด์ฑ ์ค์น ์์ด, ๋ช ๋ น์ด ํ ์ค๋ง์ผ๋ก ๋ก์ปฌ์ด๋ ํด๋ผ์ฐ๋ ํ๊ฒฝ์์ ์ฆ์ ๋ฐฐํฌ ๋ฐ ๋ ๋ฆฝ ๊ตฌ๋์ด ๊ฐ๋ฅํฉ๋๋ค.
- ๐ ์ค์๊ฐ ๊ธ๋ก๋ฒ ์์ํ: ํผ์ฆ์ ์๋ฃํ๋ ์ฆ์ ๋ด ๊ธฐ๋ก์ด ๊ธ๋ก๋ฒ ์์ํ์ ์ค์๊ฐ ๋ฐ์๋์ด ๋ค๋ฅธ ํ๋ ์ด์ด๋ค๊ณผ ์ค์๊ฐ ๊ฒฝ์์ ์ฆ๊ธธ ์ ์์ต๋๋ค.
- โฑ๏ธ ๊ธด์ฅ๊ฐ ๋์น๋ ์๊ฐ ์ ํ ๋ฐ ๐ก ์ค๋งํธ ํํธ: 60์ด์ ์ ํ ์๊ฐ ๋์ ํผ์ฆ์ ๋ง์ถ๋ ๊ธด์ฅ๊ฐ ์์ ์ด๋ ค์ธ ๋๋ ๊ฒ์๋น ๋จ ํ ๋ฒ 10์ด๊ฐ ์๋ณธ ์ด๋ฏธ์ง๋ฅผ ํ์ธํ๋ ํํธ๋ฅผ ์ธ ์ ์์ต๋๋ค.
- ๐ 1๋ฑ๋ง์ ์ํ ๋น๋ฐ ๋ฉ์์ง: 1๋ฑ์ ์ฐจ์งํ ๋จ ํ ๋ช ์๊ฒ๋ง ์จ๊ฒจ์ง ํน๋ณํ ๋น๋ฐ ๋ฉ์์ง๊ฐ ๊ณต๊ฐ๋ฉ๋๋ค.
- ๐ ๊ฐ์ธ ๋์ ์ด๋ ฅ ๋ฐ ์ต๊ณ ๊ธฐ๋ก ๊ด๋ฆฌ: ๋ด๊ฐ ๋์ ํ ๋ชจ๋ ๊ฒ์ ๊ธฐ๋ก(ํด๋ฆฌ์ด ์๊ฐ, ๋ ์ง)๊ณผ ๊ฐ์ธ ์ต๊ณ ๊ธฐ๋ก ๋๋น ํ์ฌ ์ฑ๊ณผ๋ฅผ ํ๋์ ๋ณผ ์ ์๋๋ก ์ ๊ณตํฉ๋๋ค.
- ๐ก๏ธ ๋ถ์ ํ์ ์ค์๊ฐ ๊ฐ์ง ๋ฐ ๋ฐฉ์ง: ๋น์ ์์ ์ธ ๋งคํฌ๋ก๋ ์๊ฐ์ ์กฐ์ ์๋๋ฅผ ๋ฐฑ์๋ ์ ํจ์ฑ ๊ฒ์ฌ๋ก ์ค์๊ฐ ๊ฐ์งํ์ฌ ๊นจ๋ํ ๋ญํน ์์คํ ์ ์ ์งํฉ๋๋ค.
- ๐จ ๋ชฐ์ ๊ฐ ๋์ ์ธํฐ๋ํฐ๋ธ ์ ๋๋ฉ์ด์ : ํผ์ฆ ์กฐ์ ์์ ๋ฐ์ํ ํผ๋๋ฐฑ๊ณผ ํจ๊ป ์๋ฃ ์ ๋น๋๋ ๊ธ๋ก์ฐ ํจ๊ณผ ๋ฐ ํญ์ฃฝ ์ถํ ์ฐ์ถ๋ก ๋ฐ์ด๋ ์๊ฐ์ ๋ชฐ์ ๊ฐ์ ์ ๊ณตํฉ๋๋ค. ๐
ํ๋ก์ ํธ๋ฅผ ์คํํ๋ ค๋ฉด ๋ค์ ์ํํธ์จ์ด๊ฐ ์ค์น๋์ด ์์ด์ผ ํฉ๋๋ค.
- ๐ณ Docker & Docker Compose (์ปจํ ์ด๋ ํ๊ฒฝ ์คํ ์ ๊ถ์ฅ)
- ๐ข Node.js v20 ์ด์ & npm (๋ก์ปฌ ํ๋ก ํธ์๋ ๊ฐ๋ฐ ์ ํ์)
- ๐ Python 3.11 ์ด์ (๋ก์ปฌ ๋ฐฑ์๋ ๊ฐ๋ฐ ์ ํ์)
์คํ ์ ํ๋ก์ ํธ ๋ฃจํธ ๋๋ ํ ๋ฆฌ์ .env ํ์ผ์ ์์ฑํด์ผ ํฉ๋๋ค. ์ ๊ณต๋ .env.example ํ์ผ์ ๋ณต์ฌํ์ฌ ์์ฑํ์ธ์.
cp .env.example .envImportant
๊ฒ์์ฉ ํผ์ฆ ์ด๋ฏธ์ง ์กฐ๊ฐ์ ๋์ ์ผ๋ก ์์ฑํ๊ณ ์๋นํ๊ธฐ ์ํด AWS S3 ์ค์ (AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, S3_BUCKET_NAME)์ด ๋ฐ๋์ ๊ธฐ์ฌ๋์ด์ผ ๊ฒ์ ์ ์ ๊ตฌ๋์ด ๊ฐ๋ฅํฉ๋๋ค. โ๏ธ
๋ณ๋์ ์์กด์ฑ ์ค์น ์์ด ์ ์ฒด ์คํ(Frontend, Backend, PostgreSQL, Redis)์ ์ผ๊ด ์คํํฉ๋๋ค.
- ์๋น์ค ๋น๋ ๋ฐ ๋ฐฑ๊ทธ๋ผ์ด๋ ์คํ ๐
docker compose up --build -d
- ๊ตฌ๋ ํ์ธ ๐
- ํ๋ก ํธ์๋ Web: http://localhost:3000 ๐
- ๋ฐฑ์๋ API: http://localhost:8000/api/v1 โก
- API ๋ฌธ์ (Swagger): http://localhost:8000/api/v1/openapi.json ๐
๊ฐ๋ฐ ์ ์ฝ๋ ํซ ๋ฆฌ๋ก๋(Hot Reload)๋ฅผ ํ์ฉํ๋ ค๋ฉด ํ๋ก ํธ์๋์ ๋ฐฑ์๋๋ฅผ ๋ก์ปฌ์์ ์ง์ ๊ตฌ๋ํ ์ ์์ต๋๋ค.
- ๋ฐฑ์๋ ํด๋๋ก ์ด๋ ํ ๊ฐ์ํ๊ฒฝ ์์ฑ ๋ฐ ํจํค์ง ์ค์น:
cd backend python -m venv venv source venv/bin/activate # Windows: venv\Scripts\activate pip install -r requirements.txt
- ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ค๋น ๋ฐ FastAPI ์๋ฒ ๊ตฌ๋:
# (์ ํ) .env์์ SQLite๋ฅผ ์ฌ์ฉํ๋ ค๋ฉด DATABASE_URL="sqlite+aiosqlite:///./data/sos.db"๋ก ์ค์ # Redis๊ฐ ๋ก์ปฌ(localhost:6379)์ ๊ธฐ๋ ์ค์ด์ด์ผ ์ค์๊ฐ ๋ญํน์ด ์ฌ๋ฐ๋ฅด๊ฒ ๋์ํฉ๋๋ค. uvicorn app.main:app --host 0.0.0.0 --port 8000 --reload
- ๋ฃจํธ ๋๋ ํ ๋ฆฌ๋ก ์ด๋ํ์ฌ ์์กด์ฑ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ค์น:
npm install
- ๋ก์ปฌ ๊ฐ๋ฐ ์๋ฒ ๊ตฌ๋:
๊ตฌ๋ ์๋ฃ ์ ๋ธ๋ผ์ฐ์ ์์ http://localhost:5173์ ํตํด ์ ์ํฉ๋๋ค. ๐ป
npm run dev
ํ๋ก๋์ ํ๊ฒฝ์์ ์๋ง์ ์ฌ์ฉ์์ ์ค์๊ฐ ์ ์ ๋ฐ ๋์ ํผ์ฆ ์ด๋ฒคํธ๋ฅผ ์ ์ฐํ๊ณ ์์ ํ๊ฒ ์ฒ๋ฆฌํ๊ธฐ ์ํ AWS ์ถ์ฒ ์ํคํ ์ฒ ๊ตฌ์ฑ์ ๋๋ค. ๐ ๏ธ
graph TD
User([์ฌ์ฉ์ ๋ธ๋ผ์ฐ์ ]) <--> |Route 53| CloudFront[AWS CloudFront]
CloudFront --> |์ ์ ์์
์๋น| S3_Static[S3 Static Bucket]
CloudFront --> |API & WebSocket ์์ฒญ| ALB[Application Load Balancer]
ALB --> |HTTPS / WSS| ECS[ECS Fargate: App Container Task]
ECS --> |๋น๋๊ธฐ ํธ๋ํฝ & ์์ ์บ์ฑ| Cache[Amazon ElastiCache Redis]
ECS --> |์์ ์ฌ์ฉ์ ๋ฐ ๊ธฐ๋ก ์ ์ฅ| RDS[(Amazon RDS PostgreSQL)]
ECS <--> |ํผ์ฆ ์ด๋ฏธ์ง ์๋น & Presigned URL| S3_Assets[S3 Game Assets Bucket]
ํผ์ฆ๋ก ์กฐ๊ฐ๋ผ ์๋ณธ ๊ณ ํ์ง ์ด๋ฏธ์ง๋ฅผ ์๋นํ๊ธฐ ์ํด AWS S3 ๋ฒํท์ ๊ตฌ์ฑํฉ๋๋ค. ๋ธ๋ผ์ฐ์ ์์ ์ด๋ฏธ์ง ์กฐ๊ฐ์ Canvas์ ์ฌ๋ฐ๋ฅด๊ฒ ๊ฐ๊ณตํ๊ณ CORS ์ค๋ฅ๋ฅผ ํผํ๊ธฐ ์ํด ๋ฒํท์ CORS(Cross-Origin Resource Sharing) ๊ท์น์ ํ์ ์ค์ ํด์ผ ํฉ๋๋ค.
S3 ๋ฒํท CORS ๊ตฌ์ฑ ์์ JSON: ๐
[
{
"AllowedHeaders": ["*"],
"AllowedMethods": ["GET", "HEAD"],
"AllowedOrigins": ["*"],
"ExposeHeaders": ["ETag", "Content-Type"],
"MaxAgeSeconds": 3000
}
]- ์ปดํจํ
(ECS Fargate):
- API ์๋ฒ์ ๋น๋๊ธฐ ์ฒ๋ฆฌ ๋ฐ WebSocket ์ฐ๊ฒฐ ์ ์ง๋ฅผ ์ํด ์คํ ์ค์ผ์ผ๋ง์ด ์ ์ฉ๋ Amazon ECS(Fargate) ๊ตฌ์ฑ์ ์ถ์ฒํฉ๋๋ค.
- ALB(Application Load Balancer)์์ WebSocket ์ฐ๊ฒฐ ์ ์ง๋ฅผ ์ํด ์ธ์ ์คํฐํค๋์ค(Sticky Sessions) ๋๋ ์ต์ 300์ด ์ด์์ ์ ํด ์ ํ ์๊ฐ ์ค์ ์ ๊ถ์ฅํฉ๋๋ค.
- ๋ฐ์ดํฐ๋ฒ ์ด์ค (RDS PostgreSQL):
- ์ฌ์ฉ์ ๋ฐ์ดํฐ ๋ฐ ์์ธ ์ด๋ ฅ ์ ์ฅ์ ์ํด
db.t4g.micro๋๋db.t4g.smallํด๋์ค์ PostgreSQL์ ์ฌ์ฉํ์ฌ ๋น์ฉ ๋๋น ์ต์ ์ ์ฑ๋ฅ์ ๋ผ ์ ์์ต๋๋ค.
- ์ฌ์ฉ์ ๋ฐ์ดํฐ ๋ฐ ์์ธ ์ด๋ ฅ ์ ์ฅ์ ์ํด
- ๊ณ ์ ์บ์ฑ & ๋ญํน (ElastiCache for Redis):
- ๊ธ๋ก๋ฒ ์์ํ์ ์ด๊ณ ์ ์กฐํ ๋ฐ ๋ญํน ๊ฐฑ์ (Zset ์ฐ์ฐ)์ ์ ์งํ๊ธฐ ์ํด ์ต์ ์ฌ์์ Amazon ElastiCache Serverless(Redis) ๋๋
cache.t4g.micro๋ ธ๋๋ฅผ ๋ฐฐ์นํฉ๋๋ค.
- ๊ธ๋ก๋ฒ ์์ํ์ ์ด๊ณ ์ ์กฐํ ๋ฐ ๋ญํน ๊ฐฑ์ (Zset ์ฐ์ฐ)์ ์ ์งํ๊ธฐ ์ํด ์ต์ ์ฌ์์ Amazon ElastiCache Serverless(Redis) ๋๋
- ๐ ๋ค์ํ ๋์ด๋ ๋ชจ๋ ์ง์: ๊ธฐ์กด 4x4 ๊ณ ์ ํผ์ฆ์์ 3x3(์ฌ์), 5x5(์ด๋ ค์) ๋ฑ ์ฌ์ฉ์ ์ ํ ๋์ด๋ ์ถ๊ฐ
- ๐ ์์ ๋ก๊ทธ์ธ ๋ค๊ฐํ: Google, Apple, Kakao ๋ฑ ๊ฐํธ ์์ ๊ณ์ ๊ฐ์ ๊ธฐ๋ฅ ์ฐ๋
- ๐ธ ์ฌ์ฉ์ ์ปค์คํ ์ด๋ฏธ์ง ํผ์ฆ: ๋ณธ์ธ์ด ์ง์ ์ฌ๋ฆฐ ์ฌ์ง์ผ๋ก ํผ์ฆ๋ฐฉ์ ์์ฑํด ์น๊ตฌ๋ค๊ณผ ๊ธฐ๋ก ๊ฒฝ์์ ํ ์ ์๋ ๊ฐ์ธ ๋ง์ถคํ ํผ์ฆ ๋ชจ๋
- ๐ฑ ๋ชจ๋ฐ์ผ ํฐ์น ๊ฐ๋ ๋ฐ ์ ์ค์ฒ ์ต์ ํ: ๋ชจ๋ฐ์ผ ๋ธ๋ผ์ฐ์ ํ๊ฒฝ์์์ ๋๋๊ทธ ์ค ๋๋กญ ์ฌ๋ผ์ด๋ฉ ์กฐ์๊ฐ ๊ฐ์ ๋ฐ ํ ํฑ ์ง๋ ํผ๋๋ฐฑ ์ ์ฉ
- ๐ ๋ค๊ตญ์ด ์ง์(i18n): ๊ธ๋ก๋ฒ ๋ ์ด์๋ค์ ์ํ ์์ด, ์ผ์ด ๋ฑ ๋ฒ์ญ ๋ฆฌ์์ค ๋ฒ๋ค๋ง
๋ณธ ํ๋ก์ ํธ๋ MIT License์ ๋ฐ๋ผ ๋ฐฐํฌ๋ฉ๋๋ค. ์์ธํ ๋ด์ฉ์ ํ๋ก์ ํธ ๋ด LICENSE ํ์ผ์ด ์์ฑ๋๋ฉด ํ์ธํ์ค ์ ์์ต๋๋ค.

