File size: 2,300 Bytes
aa9892b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
-- ๋‹จ๋ง ๋‹จ์œ„ ์ผ์ผ ํฌ๋ ˆ๋”ง ์‚ฌ์šฉ๋Ÿ‰ ์ถ”์  (2026-05-06).
--
-- ๋ฐฐ๊ฒฝ: "๊ณ„์ •๋‹น ์ผ 100 ํฌ๋ ˆ๋”ง" ์ •์ฑ…์€ ๋™์ผ ์‚ฌ์šฉ์ž๊ฐ€ Google ๊ณ„์ •์„ ๋‹ค์ค‘
-- ์ƒ์„ฑํ•ด ๋‹จ๋ง 1๊ฐœ๋กœ ๋ฌดํ•œ ํฌ๋ ˆ๋”ง ํš๋“ ๊ฐ€๋Šฅ. ์–ด๋ทฐ์ฆˆ ์ฐจ๋‹จ์„ ์œ„ํ•ด
-- (๊ณต์ธ IP + ๋‹จ๋ง fingerprint) ๋‹จ์œ„๋กœ ์ผ์ผ cap ์ ์šฉ.
--
-- ์ •์ฑ… (services/device_cap_service.py):
--   - Free ์‚ฌ์šฉ์ž: ๋‹จ๋ง๋‹น ์ผ 100 ํฌ๋ ˆ๋”ง ํ•ฉ์‚ฐ cap
--   - Standard/Pro ๊ฒฐ์ œ ์‚ฌ์šฉ์ž: ๋‹จ๋ง cap ๋ฉด์ œ (๊ณ„์ • cap ๋งŒ ์ ์šฉ)
--
-- ๋‹จ๋ง ์‹๋ณ„:
--   - client_ip: ๊ณต์ธ IP (X-Forwarded-For ์„œ๋ฒ„ ์ธก ์ถ”์ถœ)
--   - device_fp: frontend ๊ฐ€ X-Device-FP ํ—ค๋”๋กœ ์ „์†ก (canvas+UA+screen
--     +timezone+lang+hardware ์ข…ํ•ฉ SHA-256 hash)
--   - ๋ณด์กฐ: device_id (localStorage UUID, X-Device-ID ํ—ค๋”) โ€” fp ๋ณด๊ฐ•์šฉ

CREATE TABLE IF NOT EXISTS public.device_daily_usage (
    id BIGSERIAL PRIMARY KEY,
    client_ip TEXT NOT NULL,
    device_fp TEXT NOT NULL,
    device_id TEXT,                              -- localStorage UUID (์„ ํƒ)
    date DATE NOT NULL,                          -- KST ๊ธฐ์ค€
    used_credits INTEGER NOT NULL DEFAULT 0,
    last_user_id UUID,                           -- ๋””๋ฒ„๊น…์šฉ: ์ตœ๊ทผ ์‚ฌ์šฉ ๊ณ„์ •
    created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

CREATE UNIQUE INDEX IF NOT EXISTS uq_device_daily_usage
    ON public.device_daily_usage (client_ip, device_fp, date);

CREATE INDEX IF NOT EXISTS idx_device_daily_usage_date
    ON public.device_daily_usage (date DESC);

-- ์šด์˜ ์•ˆ์ „: 30์ผ ์ด์ƒ ๋œ row ์ž๋™ ์ •๋ฆฌ cron ํ›„์† (services ์ธก). RLS ๋น„ํ™œ์„ฑ
-- (์„œ๋น„์Šค ๋กค๋งŒ ์ ‘๊ทผ, ์‚ฌ์šฉ์ž ์ง์ ‘ ์กฐํšŒ ์•ˆ ํ•จ).
ALTER TABLE public.device_daily_usage ENABLE ROW LEVEL SECURITY;
-- ์ •์ฑ… ๋ฏธ์„ค์ • = ์„œ๋น„์Šค ๋กค๋งŒ ํ†ต๊ณผ. ์‚ฌ์šฉ์ž SELECT ๋ถˆ๊ฐ€.

-- updated_at ์ž๋™ ๊ฐฑ์‹  ํŠธ๋ฆฌ๊ฑฐ
CREATE OR REPLACE FUNCTION public.tg_device_daily_usage_updated_at()
RETURNS TRIGGER AS $$
BEGIN
  NEW.updated_at = NOW();
  RETURN NEW;
END;
$$ LANGUAGE plpgsql;

DROP TRIGGER IF EXISTS trg_device_daily_usage_updated_at ON public.device_daily_usage;
CREATE TRIGGER trg_device_daily_usage_updated_at
  BEFORE UPDATE ON public.device_daily_usage
  FOR EACH ROW EXECUTE FUNCTION public.tg_device_daily_usage_updated_at();