application.yml λ° OS νλΌλ―Έν° μμ¨ νλ.
3. ν΅μ¬ μν€ν
μ²: 'κ΄μΈ‘μ±(Observability) κΈ°λ° μμ¨ νλ'
λ¨μν AIκ° μ½λ©νλ κ²μ λμ΄, **[μΈ‘μ β‘οΈ λΆμ β‘οΈ μμ ]**μ μ μν ꡬ쑰λ₯Ό λ§λλλ€.max-threads μ€μ μ΄ λ³λͺ©μ΄λ€."PARTITION BY RANGE (created_at)λ₯Ό μ μ©νμ¬ μΌλ³ ν
μ΄λΈ μλ μμ±/μμ .
β’ Donations: meta_data 컬λΌμ JSONBλ‘ μ€μ νμ¬ TTS, μ΄ννΈ λ± κ°λ³ λ°μ΄ν°λ₯Ό μμ©νκ³ GIN μΈλ±μ€λ‘ κ²μ μ΅μ ν.
β’ Sync λ‘μ§: LISTEN/NOTIFY κΈ°λ₯μ νμ©νμ¬ AI λΈλ리μ€νΈ μ
λ°μ΄νΈ μ λͺ¨λ μλ² μΈλ©λͺ¨λ¦¬ μΊμ μ¦μ λκΈ°ν.
6. μ΅μ’
R&R (3μΈ μΌκ°νΈλ)
β’ λ°±μλ A (ν): [Traffic & AI Ops] μΉμμΌ κ³ λν, Redis Lua μ€ν¬λ¦½νΈ, Claude Code νλ μλν μ°λ, OS νλ.
β’ λ°±μλ B: [Data & Monitoring] PostgreSQL νν°μ
λ, Spring Batch μ μ°, νλ‘λ©ν
μ°μ€/κ·ΈλΌνλ λμ보λ ꡬμΆ.
β’ νλ‘ νΈ/AI: [UX & Agent] μ€μκ° μ±ν
UI, Gemini Batch API μ°λ, Python κΈ°λ° λμ©λ λλ―Έ λ°μ΄ν°(30k) μμ±κΈ°.users
| 컬λΌλͺ | λ°μ΄ν° νμ | μ μ½μ‘°κ±΄ | μ€λͺ |
|---|---|---|---|
| user_id | BIGINT | PRIMARY KEY | μ¬μ©μ κ³ μ μλ³μ |
| VARCHAR(100) | UNIQUE, NOT NULL | λ‘κ·ΈμΈ IDμ© μ΄λ©μΌ | |
| password | VARCHAR(255) | NOT NULL | μνΈνλ λΉλ°λ²νΈ (Bcrypt λ±) |
| nickname | VARCHAR(50) | NOT NULL | μλΉμ€ λ΄ νμλ λλ€μ |
| phone_number | VARCHAR(20) | - | μ¬μ©μ μ νλ²νΈ (μ ν μ¬ν) |
| role | VARCHAR(20) | DEFAULT 'USER' | κΆν (USER, ADMIN) |
| status | VARCHAR(20) | DEFAULT 'ACTIVE' | κ³μ μν (ACTIVE, SUSPENDED, DELETED) |
| last_login_at | TIMESTAMPTZ | - | λ§μ§λ§ λ‘κ·ΈμΈ μΌμ (μ΄μ κ΄μ μ©) |
| created_at | TIMESTAMPTZ | DEFAULT NOW() | κ°μ μΌμ |
| updated_at | TIMESTAMPTZ | DEFAULT NOW() | μ 보 μμ μΌμ |
| deleted_at | TIMESTAMPTZ | - | νμ νν΄ μΌμ (Soft Deleteμ©) |
streams
| 컬λΌλͺ | λ°μ΄ν° νμ | μ μ½μ‘°κ±΄ | μ€λͺ |
|---|---|---|---|
| stream_id | BIGSERIAL | PRIMARY KEY | λ°©μ‘ κ³ μ μλ³μ |
| streamer_id | BIGINT | NOT NULL | μ€νΈλ¦¬λ¨Έ ID (users.user_id FK) |
| title | VARCHAR(255) | NOT NULL | λ°©μ‘ λ°© μ λͺ© |
| category | VARCHAR(50) | - | λ°©μ‘ μΉ΄ν κ³ λ¦¬ (μ: κ²μ, λ¨Ήλ°©, μν΅) |
| max_viewer_count | INTEGER | DEFAULT 0 | μ΅κ³ λμ μμ²μ μ (λ°©μ‘ μ’ λ£ μ Redisμμ λκΈ°ν) |
| status | VARCHAR(20) | DEFAULT 'READY' | λ°©μ‘ μν (READY, LIVE, ENDED) |
| started_at | TIMESTAMPTZ | - | λ°©μ‘ μ€μ μ‘μΆ μμ μΌμ |
| ended_at | TIMESTAMPTZ | - | λ°©μ‘ μ’ λ£ μΌμ |
| created_at | TIMESTAMPTZ | DEFAULT NOW() | λ°© μμ± μΌμ |
| updated_at | TIMESTAMPTZ | DEFAULT NOW() | μ 보 μμ μΌμ |
chat_logs
| 컬λΌλͺ | λ°μ΄ν° νμ | μ μ½μ‘°κ±΄ | μ€λͺ |
|---|---|---|---|
| chat_id | BIGSERIAL | PK (1/2) | μ±ν λ‘κ·Έ κ³ μ μλ³μ |
| stream_id | BIGINT | NOT NULL | μ΄λ€ λ°©μ‘μ μ±ν μΈμ§ (μΈλ±μ€ νμ) |
| user_id | BIGINT | NOT NULL | μ±ν μΉ μ¬μ©μ ID (μΈλ±μ€ νμ) |
| sender_nickname | VARCHAR(50) | NOT NULL | μ±ν λΉμμ λλ€μ (λ°μ κ·ν) |
| message | TEXT | NOT NULL | μ€μ μ±ν λ΄μ© |
| is_blocked | BOOLEAN | DEFAULT FALSE | AI μ°¨λ¨ μ¬λΆ |
| block_reason | VARCHAR(100) | - | AI μ°¨λ¨ μ¬μ (PROFANITY, SPAM λ±) |
| created_at | TIMESTAMPTZ | PK (2/2), νν°μ ν€ | μ±ν λ°μ μΌμ (μλ³ λ²μ νν°μ κΈ°μ€) |
donations
| 컬λΌλͺ | λ°μ΄ν° νμ | μ μ½μ‘°κ±΄ | μ€λͺ |
|---|---|---|---|
| donation_id | BIGSERIAL | PRIMARY KEY | νμ μ΄λ²€νΈ κ³ μ μλ³μ |
| stream_id | BIGINT | NOT NULL | νμμ΄ ν°μ§ λ°©μ‘ ID (μΈλ±μ€ νμ) |
| sender_id | BIGINT | NOT NULL | λμ μ μμ²μ ID (μΈλ±μ€ νμ) |
| receiver_id | BIGINT | NOT NULL | λμ λ°μ μ€νΈλ¦¬λ¨Έ ID |
| amount | BIGINT | NOT NULL | νμ κΈμ‘ |
| message | TEXT | - | νμκ³Ό ν¨κ» λ³΄λΈ λ©μμ§ |
| is_blocked | BOOLEAN | DEFAULT FALSE | [AI μ°¨λ¨ μ¬λΆ] AIκ° μμ€ λ±μΌλ‘ νλ μ true |
| is_refunded | BOOLEAN | DEFAULT FALSE | [νλΆ μ¬λΆ] κ²°μ μ·¨μ μ true |
| status | VARCHAR(20) | NOT NULL | COMPLETED |
| created_at | TIMESTAMPTZ | DEFAULT NOW() | νμ λ°μ μΌμ |
blacklist
| 컬λΌλͺ | λ°μ΄ν° νμ | μ μ½μ‘°κ±΄ | μ€λͺ |
|---|---|---|---|
| blacklist_id | BIGSERIAL | PRIMARY KEY | λΈλ리μ€νΈ κ³ μ μλ³μ (PK) |
| user_id | BIGINT | NOT NULL | μ°¨λ¨λΉν μ μ± μ μ ID (μΈλ±μ€ νμ) |
| reason | VARCHAR(100) | NOT NULL | μ°¨λ¨ μ¬μ (μ: AI_PROFANITY_STRIKE_OUT) |
| unblock_at | TIMESTAMPTZ | NOT NULL | μ°¨λ¨ ν΄μ μΌμ (μ: 7μΌ μ μ§λ©΄ 7μΌ λ€ μκ°) |
| created_at | TIMESTAMPTZ | DEFAULT NOW() | μ°¨λ¨ λ°μ μΌμ (DEFAULT NOW()) |
wallets
| 컬λΌλͺ | λ°μ΄ν° νμ | μ μ½μ‘°κ±΄ | μ€λͺ |
|---|---|---|---|
| wallet_id | BIGSERIAL | PRIMARY KEY | μ§κ° μλ³μ |
| user_id | BIGINT | UNIQUE, NOT NULL | μμ μ ID (μΈλ±μ€) |
| balance | BIGINT | DEFAULT 0 | νμ¬ μμ‘ |
| created_at | TIMESTAMPTZ | DEFAULT NOW() | μμ± μΌμ |
| updated_at | TIMESTAMPTZ | DEFAULT NOW() | λ§μ§λ§ λ³λ μΌμ |
point_histories
| 컬λΌλͺ | λ°μ΄ν° νμ | μ μ½μ‘°κ±΄ | μ€λͺ |
|---|---|---|---|
| history_id | BIGSERIAL | PRIMARY KEY | μμ₯ μλ³μ |
| wallet_id | BIGINT | NOT NULL | λ³λμ΄ λ°μν μ§κ° ID (FK μ μ½ μμ, μΈλ±μ€) |
| user_id | BIGINT | NOT NULL | λμ μ μ ID (μΈλ±μ€) |
| type | VARCHAR(20) | NOT NULL | μ ν (CHARGE, DONATE, REFUND) |
| amount | BIGINT | NOT NULL | λ³λ κΈμ‘ |
| balance_snapshot | BIGINT | NOT NULL | [ν΅μ¬] λ³λ ν μμ‘ (κ°μ¬μ©) |
| created_at | TIMESTAMPTZ | DEFAULT NOW() | λ°μ μΌμ |
payments
| 컬λΌλͺ | λ°μ΄ν° νμ | μ μ½μ‘°κ±΄ | μ€λͺ |
|---|---|---|---|
| payment_id | BIGSERIAL | PRIMARY KEY | κ²°μ μλ³μ |
| user_id | BIGINT | NOT NULL | κ²°μ μ μ ID |
| amount | BIGINT | NOT NULL | κ²°μ κΈμ‘ (KRW) |
| status | VARCHAR(20) | NOT NULL | μν (PENDING, SUCCESS, FAIL) |
| method | VARCHAR(20) | - | κ²°μ μλ¨ (CARD, PAY λ±) |
| external_tid | VARCHAR(255) | UNIQUE | PGμ¬ κ±°λ λ²νΈ (νλΆ/λμ¬ νμ) |
| fail_reason | TEXT | - | μ€ν¨ μ¬μ |
| created_at | TIMESTAMPTZ | DEFAULT NOW() | μμ² μΌμ |
settlements