๐ JUVIS UTM ํํผ๋ + ์ง์ ๋ธ๋ก๊ทธ ํญ ์ค๊ณ v1.0 (์ฅ๊ฒฝํ ์๋ฌด ์์ฒญ)
ํต์ฌ ์์ฝ
# JUVIS UTM ํํผ๋ + ์ง์ ๋ธ๋ก๊ทธ ํญ ์ค๊ณ v1.0
> ์์ฑ: 2026-04-20 | DATA_ENG_BQ | Phase: ๐ PLAN (G1 ๋๊ธฐ)
> ์์ฒญ: ์ฅ๊ฒฝํ ์๋ฌด (Asana 1210900334445452)
> ์ถ์ฒ: ๋ค์ธ ๊ด๊ณ ๋ํ์ฌ ์๊ตฌ์ฌํญ 2๊ฑด + ์ฅฌ๋น์ค UTM ์ฝ๋ฉ ๊ฐ์ด๋ PDF
---
0. ์๊ตฌ์ฌํญ ์์ฝ (์ฅ๊ฒฝํ ์๋ฌด 2026-04-20)
๊ด๊ณ ๋ํ์ฌ(๋ค์ธ ) ์๊ตฌ 2๊ฑด โ ๊ธฐ์ฌ๋ชจ๋ธ ๋ฏธ์ ์ฉ
์๊ตฌ โ : UTM ๊ธฐ์ค ํํผ๋ ๋ถ์
- Dimension: UTM Source / Medium / Campaign / Term / Content 5์ฐจ์
- ํผ๋: ์ ์ โ ํ์ฑ ์ฌ์ฉ์ โ ๋ฌธ์ โ ์๋ด ์์ฝ โ ๊ฒฐ์
- ๋งค์ถ์ ํผ๋ ๋จ๊ณ๊ฐ ์๋ ์ฑ๊ณผ ์งํ๋ก ๋ฐ์
utm_term(์์ฌ) ์์ธ ์์ญ: ์์ฌ๋ช + ๊ด๊ณ ์ธ๋ค์ผ ๋ ธ์ถ ๋๋ ์๋ณธ ๋งํฌ ์ฐ๊ฒฐ
์๊ตฌ โก: ์ง์ ๋ธ๋ก๊ทธ ์ฝํ ์ธ ์ฑ๊ณผ ํญ (์ ๊ท)
- ๊ตฌ๋ถ ๊ธฐ์ค: ์ง์ =
utm_campaign, ์ฝํ ์ธ ์ ํ=utm_term, ์์ฑ์=utm_content - ์งํ: ์ ์ ์ / ํ์ฑ ์ฌ์ฉ์ ์ / ์ด ์๋ด ์ ์ฒญ / ๊ฒฐ์ ์ / ๊ฒฐ์ ์์ต
- ์กฐํ: ์ง์ ๋ณ ๋์๋ณด๋ ๋ถ๋ฆฌ ์์ด ํ๋์ ํญ์ ํํฐ/๋ทฐ๋ก ํตํฉ
์ ์ฝ์ฌํญ
- ๊ธฐ์ฌ๋ชจ๋ธ ์ ์ฉํ์ง ์์ โ
attribution_model='last'๋จ์ผ ๊ณ ์ - ๊ธฐ์กด ๋ฆฌํฌํธ ์ ์ง ๊ฐ๋ฅ, ์ ๊ท ํญ 2๊ฐ ์ถ๊ฐ๋ก ์ ๊ทผ
---
1. UTM ์ฝ๋ฉ ๊ฐ์ด๋ (์ฅฌ๋น์ค ์ ๊ณต PDF ๋ฐ์)
1-1. ํ๋ผ๋ฏธํฐ ์ค๊ณ์
| ํ๋ผ๋ฏธํฐ | ๊ถ์ฅ ๊ฐ | ์ ์/ํ์ฉ |
|---|---|---|
utm_source | blog | ์ ์ ์ฑ๋ ๊ตฌ๋ถ (๋ค์ด๋ฒ ๋ธ๋ก๊ทธ, ํฐ์คํ ๋ฆฌ ๋ฑ) |
utm_medium | branch_post | ์์ ํ ์ง์ ๊ฒ์๋ฌผ ๋ช ์ (๋ณธ์ฌ ๊ด๊ณ ์ ๊ตฌ๋ถ) |
utm_campaign | jv_gangnam ๋ฑ | [ํต์ฌ] ๊ฐ ์ง์ ์ ๊ณ ์ ์๋ฌธ ์ฝ๋ |
utm_term | success, info, program, event, daily | ์ฝํ ์ธ ์ฑ๊ฒฉ ๊ตฌ๋ถ |
utm_content | 260415_manager_cgh | ์์ฑ์ผ์_์ง์ฑ _์ด๋์ |
1-2. ์ง์ ์ฝ๋ ๋งคํ (42๊ฐ)
์์ธ (19๊ฐ)
| ์ง์ | ์ฝ๋ | ์ง์ | ์ฝ๋ |
|---|---|---|---|
| ๊ฐ๋จ์ | jv_gangnam | ๋งํฌ์ | jv_mapo |
| ์กํ์ | jv_songpa | ๊ฐ์์ | jv_gangseo |
| ์ ์ค์ | jv_jamsil | ์์ฒญ์ | jv_sicheong |
| ๋ ธ์์ | jv_nowon | ๊ด์ ์ | jv_gwanak |
| ์์ญ๋ฆฌ์ | jv_wangsimni | ์ฑ๋ถ์ | jv_seongbuk |
| ์ผ์ฑ๋์ | jv_samseong | ๋ฌต๋์ | jv_mukdong |
| ๋ชฉ๋์ | jv_mokdong | ๋ฌธ์ ์ (6๊ทธ๋ฃน) | jv_munjeong |
| ์ฌ์๋์ | jv_yeouido | ๋๊ณก์ (6๊ทธ๋ฃน) | jv_dogok |
| ์ฑ์์ | jv_seongsu | โ | โ |
| ์ํ์ | jv_eunpyeong | โ | โ |
| ์์ด์ | jv_seocho | โ | โ |
๊ฒฝ๊ธฐ/์ธ์ฒ (10๊ฐ)
์ผ์ฐ jv_ilsan / ํ์ด jv_pyeongchon / ๋ถ๋น jv_bundang / ์ก๋ jv_songdo / ์์์ํต jv_suwon_yt / ์์์ธ๊ณ jv_suwon_ig / ์์ง๊ตฌ์ฒญ jv_suji / ๋ถ์ฒ jv_bucheon / ์ธ์ฒ jv_incheon / ์์ ๋ถ jv_uijeongbu
์ถฉ์ฒญ/์ ๋ผ (7๊ฐ)
์์ฒ jv_suncheon / ์ ์ฃผ jv_jeonju / ๋์ ๋์ฐ jv_daejeon_ds / ๋์ ์ ์ฑ jv_daejeon_ys / ๊ด์ฃผ๊ด์ฒ jv_gwangju_gc / ๊ด์ฃผ์์ jv_gwangju_sw / ์ฒญ์ฃผ jv_cheongju
๊ฒฝ์ (6๊ฐ)
์ธ์ฐ jv_ulsan / ๋ถ์ฐ์๋ฉด jv_busan_sm / ๋ถ์ฐ์ผํ
์ํฐ jv_busan_ct / ๋๊ตฌ์ฃฝ์ jv_daegu_jj / ๋๊ตฌ๋ฒ์ด jv_daegu_bo / ์ฐฝ์ jv_changwon
1-3. utm_term 5์ข
| ๊ฐ | ์ฝํ ์ธ ํ ๋ง | ๋ถ์ ๋ชฉ์ |
|---|---|---|
success | ์ฑ๊ณต ํ๊ธฐ (๊ฐ๋ ์ /ํ, ์ธํฐ๋ทฐ) | ์ ๋ขฐ๋ ๊ธฐ๋ฐ ๊ฒฐ์ ์ ๋ ํจ๊ณผ ๋ถ์ |
info | ์ ๋ณด์ฑ ํ (์๋จ/์๋ฆฌ/์ด๋๋ฒ) | ์ ๋ณด ๊ฒ์ ์ ์ ์ ์๋ด ์ ํ์จ |
program | ํ๋ก๊ทธ๋จ ์๊ฐ (๊ธฐ๊ธฐ/ํธ๋/์ปจ์คํ ) | ์ํ๋ณ ๊ด์ฌ๋ ์ง์ ์ธก์ |
event | ์ด๋ฒคํธ/ํํ (์๋ณ ํ๋ก๋ชจ์ ) | ๋จ๊ธฐ ํ๋ก๋ชจ์ ๋ฐ์ ์๋ |
daily | ์ง์ ์ผ์ (๋งค๋์ ์๊ฐ/๋ถ์๊ธฐ) | ์ฅ๊ธฐ ๋ธ๋๋ฉ์ ๊ฒฐ์ ์ํฅ |
1-4. utm_content ๊ท์น
- ํ์:
{YYMMDD}_{์ง์ฑ }_{์ด๋์ }(์:260415_manager_cgh) - ๋ชฉ์ : ์ง์ ๋ด ๊ฐ์ธ๋ณ ๊ธฐ์ฌ๋ ์ธก์
---
2. ํํฉ ๋ถ์ โ ์ฆ์ ํ์ฉ ๊ฐ๋ฅํ ์ธํ๋ผ
2-1. ํ
์ด๋ธ โ lift_utm_attribution_v2
๊ฒฐ๋ก : ์ ๊ท ํ ์ด๋ธ ๋ถํ์. ํ์ฌ ๊ตฌ์กฐ์ 5๊ฐ UTM ์ฐจ์ + ํํผ๋ ์งํ๊ฐ ์ด๋ฏธ ๋ชจ๋ ์กด์ฌ.
| ์ปฌ๋ผ ๊ทธ๋ฃน | ๋ณด์ ํ๋ |
|---|---|
| UTM 5์ฐจ์ | utm_source, utm_medium, utm_campaign, utm_term, utm_content |
| ํผ๋ ์งํ | landing, active_user, g6(๋ฌธ์), g7(์๋ด์์ฝ), odr_count(๊ฒฐ์ ), order_amount(๋งค์ถ) |
| ๋ถ๊ฐ | stat_date, attribution_model, g1~g10, g6_user, pageview, landing_user/session |
| ๊ท๋ชจ | 228MB, ๊ธฐ๊ฐ๋ณ ํํฐ์ ์์(๋จ์ ํ ์ด๋ธ) |
2-2. ๊ธฐ์กด RPC
ga4_get_utm_attribution(client_code, attribution_model, date_from, date_to)โ ํ์ฌ ๊ธฐ์ฌ๋ถ์ ํญ์ด ์ด ํจ์ ์ฌ์ฉ. ๋ฐํ์ UTM source/medium ๋จ์๋ก ์ง๊ณ๋ ์ฑ๋ ๋ฆฌ์คํธ.
2-3. ๊ฐญ ๋ถ์
| ์๊ตฌ | ๊ธฐ์กด ๋์ | ์ ๊ท ํ์ |
|---|---|---|
| UTM 5์ฐจ์ ๋๋ฆด๋ค์ด | โ (source/medium๋ง ๋ฐํ) | RPC ํ์ฅ ๋๋ ์ ๊ท |
| ํํผ๋ ์งํ 6๊ฐ | โ ๋ชจ๋ ์ปฌ๋ผ ์กด์ฌ | ๊ทธ๋๋ก ์ฌ์ฉ |
| ์์ฌ ์ธ๋ค์ผ | โ ๏ธ ga4_get_creative_meta RPC ์กด์ฌ(CreativePathsTab ์ฌ์ฉ) | ์ฌ์ฌ์ฉ |
| ์ง์ (campaign) ํํฐ | โ ํ๋ก ํธ ํํฐ ์์ | ํ๋ก ํธ ์ถ๊ฐ |
| ์์ฑ์(content) ์ง๊ณ | โ | RPC + ํ๋ก ํธ |
---
3. ์ํคํ ์ฒ ์ค๊ณ
[๋ฐ์ดํฐ ๋ ์ด์ด]
BQ gp-juvis-107339 mart_tables (์๋ณธ)
โ FDW
Supabase.lift_utm_attribution_v2 (๊ธฐ์กด, ์ฌ์ฌ์ฉ)
โโ attribution_model='last' ๋จ์ผ ์ฌ์ฉ
[RPC ๋ ์ด์ด] โ ์ ๊ท 2๊ฐ
ga4_get_utm_fullfunnel(client_code, date_from, date_to, dims[])
โ dims๋ณ ๊ทธ๋ฃนํ์ผ๋ก ํํผ๋ 6๊ฐ ์ง๊ณ ๋ฐํ
โ dims = ['utm_source','utm_medium','utm_campaign','utm_term','utm_content']
์ค ์์ฒญํ ์กฐํฉ์ผ๋ก GROUP BY
ga4_get_branch_blog_perf(client_code, date_from, date_to, branch?, term?, author?)
โ utm_medium='branch_post' ํํฐ
โ ์ง์ (campaign) ร ์ฝํ
์ธ ์ ํ(term) ร ์์ฑ์(content) 3์ถ ๋๋ฆด๋ค์ด
โ 5๊ฐ ์งํ ๋ฐํ (landing, active_user, g6, odr_count, order_amount)
ga4_get_creative_meta(client_code) โ ๊ธฐ์กด ์ฌ์ฌ์ฉ (์ธ๋ค์ผ์ฉ)
[ํ๋ก ํธ ๋ ์ด์ด] โ ์ ๊ท ํญ 2๊ฐ
โโโ ์์ฒ ๋ฐ์ดํฐ ํ์ (๊ธฐ์กด ๊ทธ๋ฃน)
โ โโโ ์ผ๋ณ KPI ํธ๋ ๋ (๊ธฐ์กด)
โ โโโ ์ ํ ํผ๋ ๋ถ์ (๊ธฐ์กด)
โ โโโ ๋งค์ฒด๋ณ ์ฑ๊ณผ (๊ธฐ์กด)
โ โโโ ๋ฐ์ดํฐ ์ ํฉ์ฑ ๋น๊ต (๊ธฐ์กด)
โ โโโ UTM ํํผ๋ ํ์ โญ NEW
โ โโโ ์ง์ ๋ธ๋ก๊ทธ ์ฑ๊ณผ โญ NEW
๊ฐ ํญ์ AiInsightSection ๋ถํฌํจ (๊ธฐ์ฌ๋ชจ๋ธ ๋ฏธ์ ์ฉ์ด๋ฏ๋ก AI ์ธ์ฌ์ดํธ ๋ถํ์)
---
4. ์ ๊ท ํญ โ UTM ํํผ๋ ํ์
4-1. UX ์์ด์ดํ๋ ์
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ UTM ํํผ๋ ํ์ ๊ธฐ๊ฐ: [2026-04-01 ~ 04-20] โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
โ ๋๋ฆด๋ค์ด ์ถ (๋ค์ค์ ํ): โ
โ [โ Source] [โ Medium] [ Campaign] [ Term] [ Content] โ
โ โ
โ ํผ๋ ์์ฝ ๋ฐ (์ ์ฒด) โ
โ ์ ์
(54,904) โโโถ ํ์ฑ์ฌ์ฉ์(48,231) โโโถ ๋ฌธ์(1,344) โโโถ โ
โ ์๋ด์์ฝ(198) โโโถ ๊ฒฐ์ (79) ๋งค์ถ: โฉ441,494,700 โ
โ โ
โ ๋งค์ฒด ร ํผ๋ ํํธ๋งต โ
โ source/medium ์ ์
ํ์ฑ ๋ฌธ์ ์๋ด์์ฝ ๊ฒฐ์ ๋งค์ถ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ (not set) 131,936 54,904 989 43 79 โฉ441M โ
โ Meta / feed โฆ โ
โ Naver / BSA_MO โฆ โ
โ โ
โ [๐ฝ Naver/BSA_MO ํ ํด๋ฆญ โ Campaign ๋๋ฆด๋ค์ด] โ
โ โ
โ Term ์์ธ (์์ฌ ์ธ๋ค์ผ ํฌํจ) โ
โ โโโโโโโโโโโโโฌโโโโโโโโโโโโโโฌโโโโโโโฌโโโโโโโฌโโโโโโโ โ
โ โ [์ธ๋ค์ผ] โ utm_term โ ์ ์
โ ๋ฌธ์ โ ๊ฒฐ์ โ โ
โ โ ๐ท100x100 โ tiktok_tcpa โ 12,070โ 2 โ 2 โ โ
โ โโโโโโโโโโโโโดโโโโโโโโโโโโโโดโโโโโโโดโโโโโโโดโโโโโโโ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
4-2. ๊ธฐ๋ฅ ์๊ตฌ
- ์ถ ๋ค์ค ์ ํ: Source, Medium, Campaign, Term, Content ์ค 1~5๊ฐ ์ ํ. ์ ํ ์กฐํฉ์ผ๋ก GROUP BY
- ๊ธฐ๋ณธ ์ ํ: Source + Medium (๊ธฐ์กด ๊ธฐ์ฌ๋ถ์๊ณผ ๋์ผ)
- ์งํ 6๊ฐ ๊ณ ์ : landing / active_user / g6 / g7 / odr_count / order_amount
- ์์ฌ ์ธ๋ค์ผ: utm_term ์ถ ์ ํ ์ ์๋์ผ๋ก ga4_creative_meta ์กฐ์ธ โ ์ธ๋ค์ผ ํ์
- ๋๋ฆด๋ค์ด: ํ ํด๋ฆญ ์ ํด๋น ๊ฐ ๊ณ ์ ํ ๋ค์ ์ถ ์ถ๊ฐ
- ์ ๋ ฌ: ๋ชจ๋ ์ซ์ ์ปฌ๋ผ ํด๋ฆญ ์ ๋ ฌ
- CSV ๋ค์ด๋ก๋: ํ์ฌ ํํฐ๋ ๋ฐ์ดํฐ ๋ด๋ณด๋ด๊ธฐ
4-3. RPC ์ค๊ณ
CREATE OR REPLACE FUNCTION ga4_get_utm_fullfunnel(
p_client_code varchar,
p_date_from date,
p_date_to date,
p_dims text[] DEFAULT ARRAY['utm_source','utm_medium']
)
RETURNS jsonb
LANGUAGE plpgsql
SECURITY DEFINER
AS $$
DECLARE
v_result jsonb;
v_dim_cols text;
v_group_cols text;
BEGIN
-- ํ์ฉ dims๋ง ํํฐ๋ง (SQL injection ๋ฐฉ์ด)
SELECT string_agg(quote_ident(d), ', '), string_agg(quote_ident(d), ', ')
INTO v_dim_cols, v_group_cols
FROM unnest(p_dims) d
WHERE d IN ('utm_source','utm_medium','utm_campaign','utm_term','utm_content');
-- ๋์ SQL๋ก GROUP BY ์คํ
EXECUTE format($sql$
SELECT jsonb_build_object(
'dims', %L::jsonb,
'date_range', jsonb_build_object('from', %L::text, 'to', %L::text),
'client_code', %L,
'totals', jsonb_build_object(
'landing', COALESCE(SUM(landing), 0),
'active_user', COALESCE(SUM(active_user), 0),
'g6', COALESCE(SUM(g6), 0),
'g7', COALESCE(SUM(g7), 0),
'odr_count', COALESCE(SUM(odr_count), 0),
'order_amount', COALESCE(SUM(order_amount), 0)
),
'rows', COALESCE(jsonb_agg(row_data ORDER BY landing_sum DESC), '[]'::jsonb)
)
FROM (
SELECT
jsonb_build_object(
%s,
'landing', SUM(landing),
'active_user', SUM(active_user),
'g6', SUM(g6),
'g7', SUM(g7),
'odr_count', SUM(odr_count),
'order_amount', SUM(order_amount)
) AS row_data,
SUM(landing) AS landing_sum
FROM lift_utm_attribution_v2
WHERE client_code = %L
AND stat_date BETWEEN %L AND %L
AND attribution_model = 'last'
GROUP BY %s
) t
$sql$,
to_jsonb(p_dims), p_date_from, p_date_to, p_client_code,
-- dim key ํ์ด ์์ฑ
(SELECT string_agg(quote_literal(d)||', '||quote_ident(d), ', ')
FROM unnest(p_dims) d
WHERE d IN ('utm_source','utm_medium','utm_campaign','utm_term','utm_content')),
p_client_code, p_date_from, p_date_to, v_group_cols
) INTO v_result;
RETURN v_result;
END;
$$;
ํต์ฌ ์์ ์ฅ์น:
- ํ์ฉ๋ dim ์ด๋ฆ๋ง whitelist (SQL injection ๋ฐฉ์ด)
- ๋์ SQL์ ๋ฆฌํฐ๋ด ๊ฐ ์ฃผ์ (format + quote_literal/ident)
- SECURITY DEFINER (FDW RPC 3์ด ์ ํ ํํผ)
4-4. ์ ๊ท ํ์ผ: UtmFullFunnelTab.tsx
---
5. ์ ๊ท ํญ โก ์ง์ ๋ธ๋ก๊ทธ ์ฝํ ์ธ ์ฑ๊ณผ
5-1. UX ์์ด์ดํ๋ ์
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ ์ง์ ๋ธ๋ก๊ทธ ์ฝํ
์ธ ์ฑ๊ณผ ๊ธฐ๊ฐ: [2026-04-01 ~ 04-20] โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโค
โ ํํฐ โ
โ ์ง์ : [์ ์ฒด 42๊ฐ โผ] ์ฝํ
์ธ ์ ํ: [์ ์ฒด โผ] ์์ฑ์: [์ ์ฒด โผ] โ
โ โ
โ ์ ์ฒด ์์ฝ โ
โ โโโโโโโโฌโโโโโโโฌโโโโโโโฌโโโโโโโฌโโโโโโโโโ โ
โ โ ์ ์
โํ์ฑ์ฌ์ฉ์โ์ด์๋ด์ ์ฒญโ ๊ฒฐ์ โ ๊ฒฐ์ ์์ต โ โ
โ โ 3,241 โ 2,876 โ 47 โ 12 โ โฉ68M โ โ
โ โโโโโโโโดโโโโโโโดโโโโโโโดโโโโโโโดโโโโโโโโโ โ
โ โ
โ [์ง์ ๋ณ] ํญ โ [์ฝํ
์ธ ์ ํ๋ณ] ํญ โ [์์ฑ์๋ณ] ํญ โ [์์ธ] ํญ โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ ์ง์ (campaign) ์ ์
ํ์ฑ ๋ฌธ์ ๊ฒฐ์ ๋งค์ถ CVR โ
โ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โ
โ ๊ฐ๋จ์ 812 721 14 4 โฉ22M 1.7% โ
โ ๋ถ๋น์ 543 489 9 3 โฉ16M 1.7% โ
โ โฆ โ
โ โ
โ [์ ์ฒด ํ
์ด๋ธ CSV ๋ค์ด๋ก๋] โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
5-2. ๊ธฐ๋ฅ ์๊ตฌ
- ์๋ ํํฐ:
utm_medium = 'branch_post'ํญ์ ๊ณ ์ (์ผ๋ฐ ๊ด๊ณ ์ ์ธ) - 3์ถ ํํฐ: ์ง์ (campaign) / ์ฝํ ์ธ ์ ํ(term) / ์์ฑ์(content) ๊ฐ๊ฐ ๋๋กญ๋ค์ด
- ์ง์ ๋๋กญ๋ค์ด: ์ง์ ์ฝ๋+ํ๊ธ๋ช ๋งคํ ํ ์ด๋ธ๋ก ํ์ ("jv_gangnam โ ๊ฐ๋จ์ ")
- ์ฝํ ์ธ ์ ํ ๋๋กญ๋ค์ด: success/info/program/event/daily 5์ข
- ์์ฑ์ ๋๋กญ๋ค์ด: DB์์ distinct utm_content ์ถ์ถ
- 4๊ฐ ์๋ธํญ:
1. ์ง์ ๋ณ: campaign์ผ๋ก ๊ทธ๋ฃนํ, ์ ์งํ ํ์
2. ์ฝํ ์ธ ์ ํ๋ณ: term์ผ๋ก ๊ทธ๋ฃนํ
3. ์์ฑ์๋ณ: content๋ก ๊ทธ๋ฃนํ
4. ์์ธ(๊ต์ฐจ): campaign ร term ร content ์ ์ฒด ๊ต์ฐจ
- 5๊ฐ ์งํ: ์ ์ / ํ์ฑ์ฌ์ฉ์ / ์ด์๋ด์ ์ฒญ(g6) / ๊ฒฐ์ (odr_count) / ๊ฒฐ์ ์์ต(order_amount)
- ํ์ ์งํ: CVR (๊ฒฐ์ /์ ์ %)
- ๋ณด์กฐ ํ ์ด๋ธ: ์ง์ ์ฝ๋โํ๊ธ๋ช ๋งคํ (lift_juvis_branch_mapping ์ ๊ท)
5-3. RPC ์ค๊ณ
CREATE OR REPLACE FUNCTION ga4_get_branch_blog_perf(
p_client_code varchar,
p_date_from date,
p_date_to date,
p_group_by text DEFAULT 'campaign', -- campaign | term | content | all
p_branch text DEFAULT NULL, -- ํํฐ: utm_campaign ๊ฐ
p_term text DEFAULT NULL, -- ํํฐ: utm_term ๊ฐ
p_author text DEFAULT NULL -- ํํฐ: utm_content ๊ฐ
)
RETURNS jsonb
LANGUAGE plpgsql
SECURITY DEFINER
AS $$
DECLARE
v_result jsonb;
v_group_col text;
BEGIN
-- ๊ทธ๋ฃนํ ์ปฌ๋ผ ๊ฒฐ์ (whitelist)
v_group_col := CASE p_group_by
WHEN 'campaign' THEN 'utm_campaign'
WHEN 'term' THEN 'utm_term'
WHEN 'content' THEN 'utm_content'
WHEN 'all' THEN 'utm_campaign, utm_term, utm_content'
ELSE 'utm_campaign'
END;
EXECUTE format($sql$
WITH base AS (
SELECT utm_campaign, utm_term, utm_content,
landing, active_user, g6, odr_count, order_amount
FROM lift_utm_attribution_v2
WHERE client_code = %L
AND stat_date BETWEEN %L AND %L
AND attribution_model = 'last'
AND utm_medium = 'branch_post'
AND (%L IS NULL OR utm_campaign = %L)
AND (%L IS NULL OR utm_term = %L)
AND (%L IS NULL OR utm_content = %L)
)
SELECT jsonb_build_object(
'totals', jsonb_build_object(
'landing', COALESCE(SUM(landing), 0),
'active_user', COALESCE(SUM(active_user), 0),
'g6', COALESCE(SUM(g6), 0),
'odr_count', COALESCE(SUM(odr_count), 0),
'order_amount', COALESCE(SUM(order_amount), 0)
),
'rows', (
SELECT COALESCE(jsonb_agg(
jsonb_build_object(
%s,
'landing', landing_sum,
'active_user', active_user_sum,
'g6', g6_sum,
'odr_count', odr_count_sum,
'order_amount', order_amount_sum,
'cvr', CASE WHEN landing_sum > 0
THEN ROUND((odr_count_sum::numeric / landing_sum) * 100, 2)
ELSE 0 END
) ORDER BY landing_sum DESC
), '[]'::jsonb)
FROM (
SELECT %s,
SUM(landing) AS landing_sum,
SUM(active_user) AS active_user_sum,
SUM(g6) AS g6_sum,
SUM(odr_count) AS odr_count_sum,
SUM(order_amount) AS order_amount_sum
FROM base
GROUP BY %s
) g
)
)
FROM base
$sql$,
p_client_code, p_date_from, p_date_to,
p_branch, p_branch, p_term, p_term, p_author, p_author,
-- jsonb ํค-๊ฐ ํ์ด
'...', -- group_by์ ๋ฐ๋ผ ๋์ ์์ฑ
v_group_col, v_group_col
) INTO v_result;
RETURN v_result;
END;
$$;
5-4. ๋ณด์กฐ ํ
์ด๋ธ: lift_juvis_branch_mapping
CREATE TABLE lift_juvis_branch_mapping (
branch_code varchar(50) PRIMARY KEY, -- 'jv_gangnam'
branch_name varchar(50) NOT NULL, -- '๊ฐ๋จ์ '
region varchar(20) NOT NULL, -- '์์ธ'|'๊ฒฝ๊ธฐ/์ธ์ฒ'|'์ถฉ์ฒญ/์ ๋ผ'|'๊ฒฝ์'
is_active boolean DEFAULT true,
created_at timestamptz DEFAULT now()
);
-- 42๊ฐ ์ง์ INSERT (UTM ์ฝ๋ฉ ๊ฐ์ด๋ ๊ธฐ์ค)
5-5. ์ ๊ท ํ์ผ: BranchBlogTab.tsx
---
6. ํ๋ก ํธ ๋ผ์ฐํ
6-1. ๋ฉ๋ด ํธ๋ฆฌ ํ์ฅ
์์ฒ ๋ฐ์ดํฐ ํ์ (๊ธฐ์กด ๊ทธ๋ฃน, ํผ์นจ)
โโโ ์ผ๋ณ KPI ํธ๋ ๋
โโโ ์ ํ ํผ๋ ๋ถ์
โโโ ๋งค์ฒด๋ณ ์ฑ๊ณผ
โโโ ๋ฐ์ดํฐ ์ ํฉ์ฑ ๋น๊ต
โโโ UTM ํํผ๋ ํ์ โญ NEW
โโโ ์ง์ ๋ธ๋ก๊ทธ ์ฑ๊ณผ โญ NEW (JUVIS์์๋ง ํ์)
6-2. ํ ๋ํธ ์กฐ๊ฑด๋ถ ํ์
- "์ง์ ๋ธ๋ก๊ทธ ์ฑ๊ณผ" ํญ์
lift_tenant_config_v2.display_metrics์ ์ ํ๋show_branch_blog: true์ถ๊ฐํ์ฌ JUVIS๋ง ๋ ธ์ถ - "UTM ํํผ๋ ํ์" ํญ์ ๋ชจ๋ ํ ๋ํธ ๋ ธ์ถ (UTM์ ๋ณดํธ์ )
---
7. ์์ ์ฐ์
| ์์ | ๋ด๋น | ๊ณต์ |
|---|---|---|
| โ BranchMapping ํ ์ด๋ธ ์์ฑ + 42๊ฐ INSERT | ์ฐฐ์ค | 0.5์ผ |
โก ga4_get_utm_fullfunnel RPC ๊ฐ๋ฐ+ํ
์คํธ | ์ฐฐ์ค | 1์ผ |
โข ga4_get_branch_blog_perf RPC ๊ฐ๋ฐ+ํ
์คํธ | ์ฐฐ์ค | 1์ผ |
โฃ UtmFullFunnelTab.tsx ํ๋ก ํธ (Lovable) | Claude | 1์ผ |
โค BranchBlogTab.tsx ํ๋ก ํธ (Lovable) | Claude | 1์ผ |
โฅ ๋ฉ๋ด ๋ผ์ฐํ
+ config show_branch_blog | Claude | 0.3์ผ |
| โฆ UTM ์ฝ๋ฉ ๊ฐ์ด๋ Asana ์ฒจ๋ถ + ๋ค์ธ ๊ณต์ | ์ฅ๊ฒฝํ/์ฐฐ์ค | 0.2์ผ |
| โง ๊ฒ์ฆ (๋ธ๋ผ์ฐ์ , ๋ฐ์ดํฐ ์ ํฉ์ฑ) | ์ฐฐ์ค | 0.5์ผ |
| ํฉ๊ณ | ์ฝ 5.5์ผ(MD) |
---
8. ๋ฆฌ์คํฌ & ๊ฒํ ์ฌํญ
๐จ ๋ฐ์ดํฐ ์กด์ฌ์ฑ ํ์ธ ํ์
- ํ์ฌ
lift_utm_attribution_v2์utm_medium='branch_post'๋ ์ฝ๋๊ฐ 0๊ฑด์ผ ๊ฐ๋ฅ์ฑ โ ๋ค์ธ ๊ฐ ๋ธ๋ก๊ทธ UTM ํ๊น ์ ์์ง ์์ ์ ํ์ผ๋ฉด ํญ์ ๋น์ด์๊ฒ ๋จ - โ G1 ์น์ธ ์ ์ฆ์ SQL๋ก ์ฒดํฌ ํ์
โ ๏ธ ์ธ๋ค์ผ ๋งคํ ๋ฒ์
ga4_get_creative_metaRPC๋ ํ์ฌ CreativePathsTab์์ utm_term ๊ธฐ์ค ์ธ๋ค์ผ ๋ฐํ (์์ฌ๋ช โ ์ธ๋ค์ผ URL ๋งคํ)- ๋ธ๋ก๊ทธ ์ฝํ ์ธ ์ ๊ฒฝ์ฐ ์ธ๋ค์ผ์ ์๊ณ ๋ธ๋ก๊ทธ ์๋ณธ URL ์ฐ๊ฒฐ๋ง ๊ฐ๋ฅ โ ๋ค์ธ ์ ํ์ธ ํ์
โ ๏ธ ์ง์ ์ฝ๋ ํ์คํ
- PDF๋ 42๊ฐ ์ง์ ์ด๋ผ๊ณ ํ์ผ๋ ๋ฆฌ์คํธ ์ด๊ฑฐ๋ ์์ธ 19 + ๊ฒฝ๊ธฐ/์ธ์ฒ 10 + ์ถฉ์ฒญ/์ ๋ผ 7 + ๊ฒฝ์ 6 = 42๊ฐ ๋ง์
- ๋ค๋ง "์ฌ์๋์ "์ด ์๋๊ถ ๋ฆฌ์คํธ์ 2๋ฒ ๋ฑ์ฅ (์คํ๋ก ์ถ์ ) โ ํ์ธ ํ์
- ์ง์ ์ถ๊ฐ/ํ์ ์ mapping ํ ์ด๋ธ๋ง ์์ ํ๋ฉด ๋ฐ์๋จ
โ ๏ธ JUVIS ๋ธ๋ก๊ทธ ๋ง์ผํ ํ์ฐ ์ผ์
- UTM ์ฝ๋ฉ ๊ฐ์ด๋๊ฐ ์ง์ ์ฅ/๋ง์ผํ ๋ด๋น์์๊ฒ ๋ฐฐํฌ ์ ์ด๋ฉด, ์ฐ์ ๋์๋ณด๋ ๊ตฌ์ถ ํ ์ ์ง์ ์ผ๋ก ๋ฐ์ดํฐ ์์
- ์ด๊ธฐ์ "์์ง ๋ฐ์ดํฐ ์์" ๋น ํ๋ฉด ๋ณด์ผ ์ ์์ โ ์น์ ํ empty state ๋ฉ์์ง ํ์
---
9. G1 ๊ฒฐ์ ํ์ ์ฌํญ
์ฐฐ์ค ์น์ธ ํ์ ํญ๋ชฉ 4๊ฐ์ง:
Q1. ๋ฐ์ดํฐ ์กด์ฌ์ฑ ํ์ธ
ํ์ฌ branch_post medium ๋ฐ์ดํฐ๊ฐ ์๋์ง ๋จผ์ ํ์ธํ๊ณ , 0๊ฑด์ด๋ฉด ๋ค์ธ ์ "ํ๊น
๊ฐ์ด๋ ๋ฐฐํฌ ํ ๋์๋ณด๋ ์คํ" ์์๋ก ํ ๊น์, ์๋๋ฉด UI ๋จผ์ ๋ง๋ค๊น์?
- (A) ๋ฐ์ดํฐ ํ์ธ ํ ์งํ ์ฌ๋ถ ๊ฒฐ์
- (B) UI ์ ๊ฐ๋ฐ (empty state ํฌํจ)
Q2. ์ธ๋ค์ผ ์ฒ๋ฆฌ
๋ธ๋ก๊ทธ ์ฝํ ์ธ ๋ ์ธ๋ค์ผ์ด ์๋ ๊ฒฝ์ฐ๊ฐ ๋ง์๋ฐ:
- (A) ๋ธ๋ก๊ทธ ์๋ณธ URL ๋งํฌ๋ง ์ ๊ณต (์ธ๋ค์ผ ์์)
- (B) ๋ค์ด๋ฒ/ํฐ์คํ ๋ฆฌ ๋ธ๋ก๊ทธ ๋ฉํํ๊ทธ(og:image) ํฌ๋กค๋งํด์ ์ธ๋ค์ผ ํ๋ณด (์ถ๊ฐ ๊ณต์ 1์ผ)
- (C) ์ฐ์ A๋ก ์์, ํ์ ์ B๋ก ํ์ฅ
Q3. ๊ตฌํ ์์
- (A) ํญ โ UTM ํํผ๋ ๋จผ์ โ โก ์ง์ ๋ธ๋ก๊ทธ ์์ฐจ
- (B) ํญ โก ์ง์ ๋ธ๋ก๊ทธ ๋จผ์ (์ฅ ์๋ฌด ์์ฒญ ํต์ฌ)
- (C) ๋ณ๋ ฌ ์งํ
Q4. ๊ธฐ์กด "๋งค์ฒด๋ณ ์ฑ๊ณผ" ํญ๊ณผ์ ๊ด๊ณ
"์์ฒ ๋ฐ์ดํฐ ํ์ > ๋งค์ฒด๋ณ ์ฑ๊ณผ" ํญ๊ณผ ์ ๊ท "UTM ํํผ๋ ํ์"์ด ๊ฒน์น ์ ์์.
- (A) ๋ ๋ค ์ ์ง (์ญํ ๋ถ๋ฆฌ: ๋งค์ฒด๋ณ=์ ์ฒด ์ฑ๊ณผ ์์ฝ, ํํผ๋=๋๋ฆด๋ค์ด ํ์)
- (B) ๋งค์ฒด๋ณ ์ฑ๊ณผ๋ฅผ UTM ํํผ๋๋ก ํก์
- (C) ๋งค์ฒด๋ณ์ ์ ์งํ๊ณ ํํผ๋์ "๋งค์ฒด๋ณ ๋ทฐ" ์๋ธํญ ์ถ๊ฐ
์ถ์ฒ์: Q1=A(๋ฐ์ดํฐ ๋จผ์ ํ์ธ), Q2=C(์ ์ง์ ), Q3=C(๋ณ๋ ฌ), Q4=A(์ญํ ๋ถ๋ฆฌ)
---
10. ์ฐ๊ด ๋ฌธ์
- ์ฅฌ๋น์ค UTM ์ฝ๋ฉ ๊ฐ์ด๋ PDF (์ฅ๊ฒฝํ ์๋ฌด ์ฒจ๋ถ)
- Asana ํ์คํฌ:
1210900334445452 - LIFT ์คํค๋ง ํ์ค v1.0: KHub
0ff4d7df - JUVIS Task DevLog: KHub
e365d66c - ๊ธฐ์กด RPC:
ga4_get_utm_attribution,ga4_get_creative_meta - ๊ธฐ์กด ํ
์ด๋ธ:
lift_utm_attribution_v2(์ฌ์ฌ์ฉ)