๋ฐ์ดํฐ๋ฒ ์ด์ค
CSO ์ ์ฐ ํฌํธ์ ๋ฐ์ดํฐ๋ฒ ์ด์ค ๊ตฌ์กฐ, ๋ฐ์ดํฐ ๊ด๋ฆฌ ๋ฐฉ๋ฒ, ๋ฌด๊ฒฐ์ฑ ๊ฒ์ฌ์ ๋ํด ์ค๋ช ํฉ๋๋ค.
Supabase PostgreSQL ๊ตฌ์กฐ
ํฌํธ์ Supabase๊ฐ ์ ๊ณตํ๋ PostgreSQL ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ฅผ ์ฌ์ฉํฉ๋๋ค. Supabase Auth๋ ์ฌ์ฉํ์ง ์๊ณ ์์ฒด JWT ์ธ์ฆ์ ๊ตฌํํ๋ฉฐ, DB ์ ๊ทผ์ Supabase ํด๋ผ์ด์ธํธ(@supabase/supabase-js)๋ฅผ ํตํด ์ํํฉ๋๋ค.
์ ๊ทผ ๋ฐฉ์
| ์ฉ๋ | ํค | ํ๊ฒฝ๋ณ์ |
|---|---|---|
| ํด๋ผ์ด์ธํธ (์ฝ๊ธฐ) | Anon Key | NEXT_PUBLIC_SUPABASE_ANON_KEY |
| ์๋ฒ (์ฝ๊ธฐ/์ฐ๊ธฐ) | Service Role Key | SUPABASE_SERVICE_ROLE_KEY |
์๋ฒ ์ธก API ๋ผ์ฐํธ์์๋ Service Role Key๋ฅผ ์ฌ์ฉํ์ฌ RLS๋ฅผ ์ฐํํฉ๋๋ค. ํด๋ผ์ด์ธํธ์์ ์ง์ DB์ ์ ๊ทผํ๋ ๊ฒฝ์ฐ๋ ์์ผ๋ฉฐ, ๋ชจ๋ ๋ฐ์ดํฐ ์กฐ์์ API ๋ผ์ฐํธ๋ฅผ ๊ฒฝ์ ํฉ๋๋ค.
์ฃผ์ ํ ์ด๋ธ
members (ํ์)
CSO ์ ์ฒด ํ์ ์ ๋ณด๋ฅผ ์ ์ฅํฉ๋๋ค.
| ์ปฌ๋ผ | ํ์ | ์ค๋ช |
|---|---|---|
id | UUID | ๊ธฐ๋ณธํค |
business_number | VARCHAR(10) | ์ฌ์ ์๋ฒํธ (Unique, ๋ก๊ทธ์ธ ID) |
company_name | TEXT | ์ ์ฒด๋ช |
ceo_name | TEXT | ๋ํ์๋ช |
email | TEXT | ๋ํ ์ด๋ฉ์ผ |
password_hash | TEXT | bcrypt ํด์ |
is_admin | BOOLEAN | ๊ด๋ฆฌ์ ์ฌ๋ถ |
is_approved | BOOLEAN | ๊ฐ์ ์น์ธ ์ฌ๋ถ |
is_test | BOOLEAN | ํ ์คํธ ๊ณ์ ์ฌ๋ถ |
must_change_password | BOOLEAN | ๋น๋ฐ๋ฒํธ ๋ณ๊ฒฝ ๊ฐ์ |
profile_complete | BOOLEAN | ํ์์ ๋ณด ์์ฑ ์ฌ๋ถ |
failed_login_attempts | INTEGER | ๋ก๊ทธ์ธ ์คํจ ํ์ (15ํ ์ ์ ๊ธ) |
locked_at | TIMESTAMPTZ | ๊ณ์ ์ ๊ธ ์ผ์ |
last_login_at | TIMESTAMPTZ | ์ต๊ทผ ๋ก๊ทธ์ธ ์ผ์ |
settlements (์ ์ฐ)
SIT ์๋ฃจ์ ์์ ๋ด๋ณด๋ธ ์ ์ฐ ๋ฐ์ดํฐ๋ฅผ ์ ์ฅํฉ๋๋ค. ์์ 1ํ์ด 1๊ฑด์ ์ฒ๋ฐฉ/๊ฑฐ๋์ ํด๋นํฉ๋๋ค.
| ์ปฌ๋ผ | ํ์ | ์ค๋ช |
|---|---|---|
id | SERIAL | ๊ธฐ๋ณธํค |
business_number | VARCHAR(10) | ๊ฑฐ๋์ฒ(์ฝ๊ตญ) ์ฌ์ ์๋ฒํธ |
์ ์ฐ์ | TEXT | ์ ์ฐ ๊ธฐ์ค์ (์: 2026-01) |
์ฒ๋ฐฉ์ | TEXT | ์ฒ๋ฐฉ ๊ธฐ์ค์ |
CSO๊ด๋ฆฌ์
์ฒด | TEXT | CSO ์ ์ฒด๋ช (๋งค์นญ ํค) |
๊ฑฐ๋์ฒ๋ช
| TEXT | ์ฝ๊ตญ/๊ฑฐ๋์ฒ ์ด๋ฆ |
์์
์ฌ์ | TEXT | ๋ด๋น ์์ ์ฌ์ |
์ ํ๋ช
| TEXT | ์์ฝํ ์ ํ๋ช |
์๋ | NUMERIC | ์ฒ๋ฐฉ ์๋ |
๊ธ์ก | NUMERIC | ๊ฑฐ๋ ๊ธ์ก |
์ ์ฝ์์๋ฃ_ํฉ๊ณ | NUMERIC | ์ ์ฝ์ฌ ์์๋ฃ ํฉ๊ณ |
๋ด๋น์์๋ฃ_ํฉ๊ณ | NUMERIC | ๋ด๋น์ ์์๋ฃ ํฉ๊ณ |
upload_year_month | TEXT | ์ ๋ก๋ ์์ ์ฐ์ |
upload_date | TEXT | ์ ๋ก๋ ์ผ์ |
์ด 47๊ฐ์ ํ๊ธ ์ปฌ๋ผ์ด ์กด์ฌํฉ๋๋ค. ์์๋ฃ์จ, ์ธ์ผํฐ๋ธ์จ ๋ฑ ์์ธ ํญ๋ชฉ์ ์ ์ฝ์ฌ ์ ์ฐ ๊ตฌ์กฐ์ ๋ฐ๋ฆ ๋๋ค.
์ฃผ์:
settlements.business_number๋ ๊ฑฐ๋์ฒ(์ฝ๊ตญ) ์ฌ์ ์๋ฒํธ์ ๋๋ค. CSO ์ ์ฒด์ ์ฌ์ ์๋ฒํธ๊ฐ ์๋๋๋ค. CSO ์ ์ฒด ์ฌ์ ์๋ฒํธ๋ฅผ ์ฐพ์ผ๋ ค๋ฉดCSO๊ด๋ฆฌ์ ์ฒดโcso_matchingํ ์ด๋ธ์ JOINํด์ผ ํฉ๋๋ค.
cso_matching (CSO ๋งค์นญ)
์ ์ฐ์์ CSO๊ด๋ฆฌ์
์ฒด ์ด๋ฆ๊ณผ ํ์์ ์ฌ์
์๋ฒํธ๋ฅผ ๋งคํํฉ๋๋ค. ์ด ํ
์ด๋ธ์ด ์์ผ๋ฉด ํ์์ ์๊ธฐ ์ ์ฐ์ ์กฐํํ ์ ์์ต๋๋ค.
| ์ปฌ๋ผ | ํ์ | ์ค๋ช |
|---|---|---|
cso_company_name | TEXT | ์ ์ฐ์ CSO๊ด๋ฆฌ์ ์ฒด๋ช (PK) |
business_number | VARCHAR(10) | ํด๋น ์ ์ฒด์ ์ฌ์ ์๋ฒํธ |
created_at | TIMESTAMPTZ | ์์ฑ์ผ์ |
updated_at | TIMESTAMPTZ | ์์ ์ผ์ |
๋งค์นญ ๊ด๊ณ: settlements.CSO๊ด๋ฆฌ์
์ฒด = cso_matching.cso_company_name โ cso_matching.business_number = members.business_number
email_logs (์ด๋ฉ์ผ ๋ก๊ทธ)
๋ฐ์ก๋ ๋ชจ๋ ์ด๋ฉ์ผ์ ์ด๋ ฅ์ ์ ์ฅํฉ๋๋ค.
| ์ปฌ๋ผ | ํ์ | ์ค๋ช |
|---|---|---|
id | UUID | ๊ธฐ๋ณธํค |
recipient_email | TEXT | ์์ ์ ์ด๋ฉ์ผ |
subject | TEXT | ์ด๋ฉ์ผ ์ ๋ชฉ |
template_type | TEXT | ์ ํ (์๋ ์ฐธ์กฐ) |
status | TEXT | pending / sent / failed |
error_message | TEXT | ์คํจ ์ ์๋ฌ ๋ฉ์์ง |
sent_at | TIMESTAMPTZ | ๋ฐ์ก ์๋ฃ ์ผ์ |
created_at | TIMESTAMPTZ | ์์ฑ ์ผ์ |
template_type ๋ชฉ๋ก:
| ๊ฐ | ์ค๋ช | ์์ ์ |
|---|---|---|
registration_request | ๊ฐ์ ์ ์ฒญ ์๋ฆผ | ๊ด๋ฆฌ์ |
approval_complete | ๊ฐ์ ์น์ธ ์๋ฆผ | ํ์ |
approval_rejected | ๊ฐ์ ๊ฑฐ๋ถ ์๋ฆผ | ํ์ |
settlement_uploaded | ์ ์ฐ์ ์ ๋ก๋ ์๋ฆผ | ํ์ |
password_reset | ๋น๋ฐ๋ฒํธ ์ฌ์ค์ | ํ์ |
mail_merge | ๋ฉ์ผ๋จธ์ง ๋ฐ์ก | ํ์ |
company_settings (ํ์ฌ ์ค์ )
์ฌ์ดํธ ์ ์ฒด ์ค์ ์ ์ ์ฅํฉ๋๋ค. ๋จ์ผ ํ ํ ์ด๋ธ์ ๋๋ค.
| ์ปฌ๋ผ ๊ทธ๋ฃน | ์ฃผ์ ํญ๋ชฉ |
|---|---|
| ํ์ฌ ์ ๋ณด | ํ์ฌ๋ช , ๋ํ์๋ช , ์ฌ์ ์๋ฒํธ, ์ฃผ์, ์ฐ๋ฝ์ฒ |
| ์ด๋ฉ์ผ ์ค์ | ํ๋ก๋ฐ์ด๋(Resend/SMTP), SMTP ํธ์คํธ/ํฌํธ/์ธ์ฆ, ๋ฐ์ก ๊ฐ๊ฒฉ |
| ์๋ฆผ ์ค์ | ์ด๋ฉ์ผ ์ ํ๋ณ ON/OFF (5์ข ) |
| ๊ณต์ง์ฌํญ | ๋์๋ณด๋ ๊ณต์ง ๋ด์ฉ (๋ณ์ ์นํ ์ง์) |
password_reset_tokens (๋น๋ฐ๋ฒํธ ์ฌ์ค์ ํ ํฐ)
๋น๋ฐ๋ฒํธ ์ฐพ๊ธฐ ์์ฒญ ์ ์์ฑ๋๋ ์ผํ์ฉ ํ ํฐ์ ์ ์ฅํฉ๋๋ค. ์ ํจ๊ธฐ๊ฐ์ 30๋ถ์ ๋๋ค.
settlement_uploads (์ ๋ก๋ ์ด๋ ฅ)
์ ์ฐ์ ์ ๋ก๋ ์ด๋ ฅ๊ณผ ์ ์ ์ ์ฒด ์ค๋ ์ท์ ์ ์ฅํฉ๋๋ค.
RLS (Row Level Security) ์ ์ฑ
ํฌํธ์ ์๋ฒ ์ธก์์ ๊ถํ์ ๊ฒ์ฆํ๊ณ Service Role Key๋ก DB์ ์ ๊ทผํ๋ฏ๋ก, Supabase RLS๋ ๋ณด์กฐ์ ์ธ ์์ ์ฅ์น ์ญํ ์ ๋๋ค.
์ ์ฐ ๋ฐ์ดํฐ ์ ๊ทผ ์ ์ด
์ผ๋ฐํ์์ ์ ์ฐ ๋ฐ์ดํฐ ์ ๊ทผ์ API ๋ผ์ฐํธ์์ ๋ค์๊ณผ ๊ฐ์ด ํํฐ๋ง๋ฉ๋๋ค.
- JWT์์
business_number์ถ์ถ cso_matchingํ ์ด๋ธ์์ ํด๋น ์ฌ์ ์๋ฒํธ์ ๋งคํ๋cso_company_name๋ชฉ๋ก ์กฐํsettlementsํ ์ด๋ธ์์CSO๊ด๋ฆฌ์ ์ฒด IN (๋งค์นญ๋ ์ ์ฒด๋ช )์กฐ๊ฑด์ผ๋ก ํํฐ๋ง
๊ด๋ฆฌ์(is_admin: true)๋ ํํฐ ์์ด ์ ์ฒด ๋ฐ์ดํฐ์ ์ ๊ทผํฉ๋๋ค.
๋ฐ์ดํฐ ์ ๋ก๋ ์ ์ฐจ
SIT ์๋ฃจ์ ์์ ๋ด๋ณด๋ธ ์์ ํ์ผ์ ํฌํธ์ ์ ๋ก๋ํ๋ ์ ์ฐจ์ ๋๋ค.
์ ๋ก๋ ๊ณผ์ (/admin/upload)
-
ํ์ผ ์ ํ:
.xlsx๋๋.xlsํ์ผ์ ๋๋๊ทธ ์ค ๋๋กญํ๊ฑฐ๋ ์ ํํฉ๋๋ค.- ์ต๋ ํ์ผ ํฌ๊ธฐ: 4MB
- ์ฒซ ๋ฒ์งธ ์ํธ๋ง ์ฒ๋ฆฌ๋ฉ๋๋ค.
-
์ปฌ๋ผ ๋งคํ ํ์ธ (์ ํ): โ์ปฌ๋ผ ๋งคํ ํ์ธโ ๋ฒํผ์ ํด๋ฆญํ๋ฉด ์์ ์ปฌ๋ผ๊ณผ DB ์ปฌ๋ผ์ ๋งคํ์ ๋ฏธ๋ฆฌ ๋ณผ ์ ์์ต๋๋ค.
- ์ปฌ๋ผ๋ช ์ด ์ ํํ ์ผ์นํ๋ฉด ์๋ ๋งคํ
- ์ ์ฌํ ์ด๋ฆ์ ์ ์ฌ๋ ์ ์(0.6 ์ด์)๋ก ์๋ ๋งคํ
- ์๋ ๋งคํ ์คํจ ์ ์๋์ผ๋ก ์ง์ ๊ฐ๋ฅ
- ํ์ ์ปฌ๋ผ:
์ฌ์ ์๋ฒํธ,์ ์ฐ์
-
์ ๋ก๋ ์คํ: โ๋ฐ๋ก ์ ๋ก๋โ ๋๋ โ๋งคํ ํ์ธ ํ ์ ๋ก๋โ ํด๋ฆญ
- ๊ฐ์ ์ ์ฐ์ ๋ฐ์ดํฐ๊ฐ ์์ผ๋ฉด ๊ธฐ์กด ๋ฐ์ดํฐ๋ฅผ ์ญ์ ํ ํ ์ ๋ฐ์ดํฐ๋ฅผ ์ฝ์ ํฉ๋๋ค.
- ๋ฐฐ์น ํฌ๊ธฐ: 500๊ฑด ๋จ์๋ก DB์ ์ฝ์
-
์ ๋ก๋ ๊ฒฐ๊ณผ ํ์ธ: ์ฑ๊ณต ๊ฑด์, ์คํจ ๊ฑด์, ์ ๋ก๋๋ ์ ์ฐ์ ๋ชฉ๋ก์ด ํ์๋ฉ๋๋ค.
-
์ด๋ฉ์ผ ๋ฐ์ก (์ ํ): ์ ๋ก๋ ์๋ฃ ํ โ์ ์ฐ์ ์ ๋ก๋ ์๋ฆผโ ์ด๋ฉ์ผ์ ๋ฐ์กํ ์ ์์ต๋๋ค.
- ๋งค์นญ๋ CSO ์ ์ฒด ํ์์๊ฒ๋ง ๋ฐ์ก๋ฉ๋๋ค.
๋ฐ์ดํฐ ๊ด๋ฆฌ (/admin/data)
์ ๋ก๋๋ ์ ์ฐ ๋ฐ์ดํฐ๋ฅผ ์ ์ฐ์ ๊ธฐ์ค์ผ๋ก ๊ด๋ฆฌํฉ๋๋ค.
| ๊ธฐ๋ฅ | ์ค๋ช |
|---|---|
| ํต๊ณ ์นด๋ | ์ ์ฒด ๊ฑด์, ์ ์ฐ์ ์, CSO ์ ์ฒด ์ |
| ์ ์ฐ์๋ณ ํ ์ด๋ธ | ๊ฐ ์์ ๊ฑด์, CSO ์ ์ฒด ์, ์ ๋ก๋ ์ผ์ |
| ์๋ณ ์ญ์ | ํน์ ์ ์ฐ์ ๋ฐ์ดํฐ ์ ์ฒด ์ญ์ (ํ์ธ ๋ค์ด์ผ๋ก๊ทธ) |
| ์๋ก๊ณ ์นจ | ์ต์ ํต๊ณ ์ฌ์กฐํ |
CSO ๋งค์นญ ๋ฌด๊ฒฐ์ฑ ๊ฒ์ฌ
๋ฌด๊ฒฐ์ฑ ๊ฒ์ฌ๋
์ ์ฐ์์ CSO๊ด๋ฆฌ์
์ฒด์ ํ์ ์ฌ์
์๋ฒํธ ๊ฐ ๋งคํ์ด ์ฌ๋ฐ๋ฅธ์ง ๊ฒ์ฌํฉ๋๋ค. ๋งค์นญ์ด ๋๋ฝ๋๋ฉด ํด๋น ์
์ฒด์ ์ ์ฐ ๋ฐ์ดํฐ๊ฐ ์ด๋ค ํ์์๊ฒ๋ ๋ณด์ด์ง ์์ต๋๋ค.
๋งค์นญ ์ํ (/admin/integrity)
| ์ํ | ์๋ฏธ | ์กฐ์น |
|---|---|---|
normal | ์ ์ ๋งค์นญ ์๋ฃ | ์กฐ์น ๋ถํ์ |
unregistered | ๋งค์นญ์ ์์ผ๋ ํด๋น ์ฌ์ ์๋ฒํธ๋ก ๊ฐ์ ํ ํ์์ด ์์ | ํ์ ๊ฐ์ ์๋ด ๋๋ ์ฌ์ ์๋ฒํธ ํ์ธ |
pending_join | ํ์์ด ๊ฐ์ ์ ์ฒญํ์ผ๋ ์์ง ์น์ธ๋์ง ์์ | /admin/members์์ ์น์ธ ์ฒ๋ฆฌ |
missing_match | ์ ์ฐ์์ ์
์ฒด๋ช
์ด ์์ผ๋ cso_matching์ ๋งคํ์ด ์์ | ๋งค์นญ ๋ฐ์ดํฐ ์ถ๊ฐ |
๋ฌด๊ฒฐ์ฑ ๊ฒ์ฌ ๊ฒฐ๊ณผ ํญ๋ชฉ
| ํญ๋ชฉ | ์ค๋ช |
|---|---|
| CSO ๊ด๋ฆฌ์ ์ฒด๋ช | ์ ์ฐ์์ ๊ธฐ์ฌ๋ ์ ์ฒด๋ช |
| ์ฌ์ ์๋ฒํธ | ๋งค์นญ๋ ์ฌ์ ์๋ฒํธ (์์ผ๋ฉด ๋น์ด ์์) |
| ์ํ | ์ 4๊ฐ์ง ์ค ํ๋ |
| ์ ์ฐ ๊ฑด์ | ํด๋น ์ ์ฒด์ ์ ์ฐ ๋ฐ์ดํฐ ๊ฑด์ |
| ์ต๊ทผ ์ ์ฐ์ | ๊ฐ์ฅ ์ต๊ทผ ์ ์ฐ์ |
| ์น์ธ ์ฌ๋ถ | ํ์ ๊ฐ์ ์น์ธ ์ํ |
๋งค์นญ ๋ฐ์ดํฐ ์์
๋ฌด๊ฒฐ์ฑ ๊ฒ์ฌ ํ์ด์ง์์ missing_match ์ํ์ ์
์ฒด์ ๋ํด ์ฌ์
์๋ฒํธ๋ฅผ ์ง์ ์
๋ ฅํ์ฌ ๋งค์นญ์ ์ถ๊ฐํ ์ ์์ต๋๋ค. ๋งค์นญ ์ถ๊ฐ ์ cso_matching ํ
์ด๋ธ์ UPSERT๋ฉ๋๋ค.
๋ฐ์ดํฐ ๋ฐฑ์ /๋ณต์
Supabase ์๋ ๋ฐฑ์
Supabase Pro ํ๋์์ ์ ๊ณตํ๋ ์๋ ๋ฐฑ์ ์ ์ฌ์ฉํฉ๋๋ค.
- ์ผ์ผ ๋ฐฑ์ : ๋งค์ผ ์๋ ์ํ
- ๋ณด๊ด ๊ธฐ๊ฐ: 7์ผ (Pro ํ๋ ๊ธฐ๋ณธ)
- ๋ณต์: Supabase ๋์๋ณด๋ โ Database โ Backups์์ ํน์ ์์ ์ผ๋ก ๋ณต์
์๋ ๋ฐฑ์
Supabase ๋์๋ณด๋์์ SQL Editor๋ฅผ ํตํด ํน์ ํ ์ด๋ธ์ CSV๋ก ๋ด๋ณด๋ผ ์ ์์ต๋๋ค.
-- ์ ์ฐ ๋ฐ์ดํฐ ํ์ธ (ํน์ ์)
SELECT COUNT(*) FROM settlements WHERE "์ ์ฐ์" = '2026-01';
-- ๋งค์นญ ๋ฐ์ดํฐ ์ ์ฒด ์กฐํ
SELECT * FROM cso_matching ORDER BY cso_company_name;
-- ํ์ ๋ชฉ๋ก (๋น๋ฐ๋ฒํธ ํด์ ์ ์ธ)
SELECT id, business_number, company_name, email, is_admin, is_approved, created_at
FROM members ORDER BY created_at DESC;์ ์ฐ ๋ฐ์ดํฐ ๋ณต์
์ ์ฐ ๋ฐ์ดํฐ๋ ์๋ณธ ์์ ํ์ผ์ ๋ค์ ์ ๋ก๋ํ๋ฉด ๋ณต์๋ฉ๋๋ค. ๊ฐ์ ์ ์ฐ์ ๋ฐ์ดํฐ๋ฅผ ์ ๋ก๋ํ๋ฉด ๊ธฐ์กด ๋ฐ์ดํฐ๊ฐ ๊ต์ฒด๋๋ฏ๋ก, ์๋ณธ ์์ ํ์ผ์ ๋ณ๋๋ก ๋ณด๊ดํ๋ ๊ฒ์ด ์ค์ํฉ๋๋ค.