Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .claude/skills/gdpr/references/data-map.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
| **Stripe** (Stripe Payments Europe Ltd) | Ирландия + US-аффилиаты | Customer (email, billing name/address), способ оплаты (токен), инвойсы, Subscription с `metadata` (см. §3) | по правилам Stripe; инвойсы — налоговые записи (6–10 лет) |
| **Mux** | США | видеоассеты (контент, не персональное); CDN-логи доставки (IP/UA зрителя на каждом сегменте — инфраструктура Mux); Mux Data (по согласию): cookie viewer-id, QoE, watch time | по правилам Mux |
| **Resend** | США (отправка из eu-west-1) | адрес получателя, тема, тело письма (название шоу/эпизода, логлайн, подписанный URL кадра), события доставки | логи 30 дней (Free/Pro/Scale) |
| **PostHog Cloud EU** | Франкфурт | события с `distinct_id` (анонимный uuid → Clerk id после `identify`), свойства персоны `{email}`, супер-свойства `locale`/`locale_source`, session replay (все input/text замаскированы), `$ip`/geo, referrer/utm; с posthog-js 1.433 (#242) — также Meta `_fbc`/`_fbp` из кук пикселя: `$fbc` и `$fbp` как свойства персоны; `$fbc` может быть выведен из `?fbclid` в URL и без куки пикселя. Реплей пишет и **консольные логи браузера** (`capture_console_log_opt_in: true` — настройка проекта 190233, маска input/text на консоль не действует; сверено 27.09.2026 — отсюда запрет `console.*` в `components/ideas/`, #297); тела и заголовки сетевых запросов **не** пишет (`session_recording_network_payload_capture_config: null`, сверено 27.09.2026) | по плану PostHog (уточнить); при стирании аккаунта person по `distinct_id` = Clerk id удаляется вместе с событиями И записями сессий (`delete_events=true&delete_recordings=true`, `lib/posthog-erase.ts`, best-effort, #180) |
| **PostHog Cloud EU** | Франкфурт | события с `distinct_id` (анонимный uuid → Clerk id после `identify`), свойства персоны `{email}`, супер-свойства `locale`/`locale_source`, session replay (все input/text замаскированы), `$ip`/geo, referrer/utm; с posthog-js 1.433 (#242) — также Meta `_fbc`/`_fbp` из кук пикселя: `$fbc` и `$fbp` как свойства персоны; `$fbc` может быть выведен из `?fbclid` в URL и без куки пикселя; click id рекламных сетей из URL (`?fbclid`, `?gclid`, … — список campaign params SDK) — свойства события и `$initial_*` персоны, с posthog-js 1.435.6 (#434) в списке и `?oppref` — click id ChatGPT Ads (`oppref` / `$initial_oppref`; только из URL, куку `__oppref` SDK не читает). Реплей пишет и **консольные логи браузера** (`capture_console_log_opt_in: true` — настройка проекта 190233, маска input/text на консоль не действует; сверено 27.09.2026 — отсюда запрет `console.*` в `components/ideas/`, #297); тела и заголовки сетевых запросов **не** пишет (`session_recording_network_payload_capture_config: null`, сверено 27.09.2026) | по плану PostHog (уточнить); при стирании аккаунта person по `distinct_id` = Clerk id удаляется вместе с событиями И записями сессий (`delete_events=true&delete_recordings=true`, `lib/posthog-erase.ts`, best-effort, #180) |
| **Meta** (Pixel + CAPI) | Ирландия / США | браузерные события с `_fbp`/`_fbc`, IP/UA запроса; CAPI `Purchase` с SHA-256 email, SHA-256 Clerk id, `_fbp`, `_fbc`, сырой IP, UA | по правилам Meta |
| **Google** (GA4) | Ирландия / США | `page_view` и события gtag, client id `_ga`; user_id/email кодом не передаются | настройка ретеншена событий в свойстве GA4 (2 или 14 мес. — уточнить) |
| **OpenAI** (ChatGPT Ads pixel `oaiq`) | Ирландия / США | `page_viewed`, `registration_completed`/`subscription_created` с `event_id` = `signup:<Clerk id>` или Stripe subscription id, `plan_id`, `amount`, `currency`; cookie `__oppref` (click id), IP/UA запроса | по правилам OpenAI |
Expand Down Expand Up @@ -103,7 +103,7 @@ private details», но исключить этого не может (пере
| **PostHog** (стирание, `lib/posthog-erase.ts`) | вебхук Clerk `user.deleted` / `pnpm erase-user --apply` / `POST /api/v1/account/delete` (#309) / конфликт адреса в `users` (#380) — ПОСЛЕ локальных DELETE | `GET persons/?distinct_id=<Clerk id>` → `DELETE persons/{id}/?delete_events=true&delete_recordings=true` — стираются персона (с `email`), её события и записи сессий (replay в проекте включён); наружу уходит только id; тело ответа не читается и не логируется; 401/403 (нет `person:write`) → `skipped_forbidden`, таймаут/5xx → `failed` — оба в лог + Sentry по id, ручной путь в ранбуке §4 | ст. 17 — исполнение запроса |
| **Meta CAPI** (`lib/meta-capi.ts`) | вебхук Stripe, переход в access-granting | `Purchase`: `em` = SHA-256(email), `external_id` = SHA-256(Clerk id), `fbp`, `fbc`, `client_ip_address` (сырой), `client_user_agent`, `event_id` = sub id, `value`/`currency`, `content_ids` | `capi_consent` из метаданных |
| **Meta Pixel** (браузер) | по странице | `PageView`, `ViewContent`, `Lead`, `InitiateCheckout`, `CompleteRegistration`, `SubmitApplication {content_category: "story_idea"}` (успешная отправка идеи на `/ideas`, #297 — только из клиента, без email/имени/текстов; не `Lead` и без CAPI) + `_fbp`/`_fbc`, IP/UA запроса — самим пикселем. **Automatic Advanced Matching: не сверено** — `meta-pixel.tsx` делает голый `fbq('init', id)`; если AAM включён в Events Manager, пиксель сам читает поля email/имени на странице (`/ideas`, форма напоминаний) и шлёт их хеши в обход гейтов кода. Сверяет владелец для каждого ID из `NEXT_PUBLIC_META_PIXEL_ID` + `NEXT_PUBLIC_META_PIXEL_IDS`; до ответа — `docs/registry.md` (строка AAM / GA4, #297) → #341, реклама на `/ideas` заблокирована | `cookie_consent.marketing` |
| **PostHog** (браузер) | по странице | `$pageview`, `show_viewed`, `trial_play_started`, `signup_wall_shown`, `signup_completed`, `checkout_started`, `idea_submitted {idea_kind, show_slug}` (#297 — только при успешной отправке, `show_slug` только у продолжения; ни email, ни имени, ни текстов, ни их длин), … со свойствами `show_slug`, `episode_number`, `mode`, `auth`, `gate`; супер-свойства `locale`, `locale_source`; `identify(userId, {email})` после входа; session replay с маской всех input/text; UTM нормализуются в `before_send`; с posthog-js 1.433 (#242) SDK читает куки Meta `_fbc` (время клика по рекламе) и `_fbp` → свойства персоны `$fbc` и `$fbp` (`$set` по обоим каналам; `$fbc` SDK может синтезировать из `?fbclid` в URL и без куки пикселя — `fb.1.<ts>.<fbclid>`) — те же куки, что пишет пиксель, под тем же согласием | `cookie_consent.marketing` |
| **PostHog** (браузер) | по странице | `$pageview`, `show_viewed`, `trial_play_started`, `signup_wall_shown`, `signup_completed`, `checkout_started`, `idea_submitted {idea_kind, show_slug}` (#297 — только при успешной отправке, `show_slug` только у продолжения; ни email, ни имени, ни текстов, ни их длин), … со свойствами `show_slug`, `episode_number`, `mode`, `auth`, `gate`; супер-свойства `locale`, `locale_source`; `identify(userId, {email})` после входа; session replay с маской всех input/text; UTM нормализуются в `before_send`; с posthog-js 1.433 (#242) SDK читает куки Meta `_fbc` (время клика по рекламе) и `_fbp` → свойства персоны `$fbc` и `$fbp` (`$set` по обоим каналам; `$fbc` SDK может синтезировать из `?fbclid` в URL и без куки пикселя — `fb.1.<ts>.<fbclid>`) — те же куки, что пишет пиксель, под тем же согласием; с posthog-js 1.435.6 (#434) SDK берёт из URL и `?oppref` (click id ChatGPT Ads) → свойство события `oppref` + `$initial_oppref` персоны, как `fbclid`/`gclid` — тот же click id, что пиксель OpenAI кладёт в `__oppref`, под тем же согласием | `cookie_consent.marketing` |
| **PostHog** (сервер, `lib/posthog-server.ts`) | вебхук Stripe | `subscribe_succeeded`: `distinctId` = Clerk id, `value`, `currency`, `plan`, `utm_*` first-touch | `ph_consent` из метаданных |
| **Google GA4** | по странице | `page_view` + события `trackGA` (без user_id/email в коде), Consent Mode v2. **«User-provided data collection → automatic detection»: не сверено** — если включено, gtag сам ищет email на странице (`/ideas`, форма напоминаний); сверяет владелец (GA4 Admin → Data collection), до ответа — `docs/registry.md` (строка AAM / GA4, #297) → #341 | `cookie_consent.marketing` |
| **OpenAI oaiq** | по странице; регистрация; возврат с оплаты | `page_viewed{type:contents}`; `registration_completed{type:customer_action}` или `subscription_created{plan_id, amount, currency}`; `options.event_id` = `signup:<Clerk id>` / Stripe sub id; cookie `__oppref` — самим SDK | `cookie_consent.marketing` |
Expand Down
32 changes: 16 additions & 16 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,33 +37,33 @@
},
"dependencies": {
"@base-ui/react": "^1.7.0",
"@clerk/localizations": "^4.21.0",
"@clerk/nextjs": "^7.9.8",
"@clerk/localizations": "^4.22.0",
"@clerk/nextjs": "^7.9.11",
"@clerk/themes": "^2.4.57",
"@mux/mux-node": "^15.3.0",
"@mux/mux-player-react": "^3.13.4",
"@mux/mux-video-react": "^0.31.4",
"@mux/mux-node": "^15.5.0",
"@mux/mux-player-react": "^3.14.0",
"@mux/mux-video-react": "^0.31.5",
"@mux/upchunk": "^3.5.0",
"@sentry/nextjs": "^11.1.0",
"@sentry/nextjs": "^11.4.0",
"@stripe/react-stripe-js": "^6.12.0",
"@stripe/stripe-js": "^9.17.0",
"@vercel/blob": "^2.8.0",
"@vercel/blob": "^2.8.1",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"drizzle-orm": "^0.45.3",
"flags": "^4.3.1",
"jsonwebtoken": "^9.0.3",
"lucide-react": "^1.49.0",
"lucide-react": "^1.52.0",
"media-chrome": "^4.19.3",
"next": "^16.3.8",
"postgres": "^3.4.9",
"posthog-js": "^1.435.3",
"posthog-node": "^5.54.1",
"posthog-js": "^1.436.1",
"posthog-node": "^5.55.0",
"react": "^19.3.0",
"react-dom": "^19.3.0",
"resend": "^6.31.0",
"resend": "^6.32.0",
"server-only": "^0.0.1",
"shadcn": "^4.19.1",
"shadcn": "^4.21.3",
"stripe": "^22.6.2",
"tailwind-merge": "^3.7.0",
"tw-animate-css": "^1.4.0"
Expand All @@ -74,27 +74,27 @@
"@testing-library/jest-dom": "^7.0.1",
"@testing-library/react": "^16.3.3",
"@types/jsonwebtoken": "^9.0.10",
"@types/node": "^24.19.0",
"@types/node": "^24.19.1",
"@types/react": "^19",
"@types/react-dom": "^19",
"@vitest/coverage-v8": "^5.0.3",
"dotenv": "^18.0.5",
"drizzle-kit": "^0.31.11",
"eslint": "^10",
"eslint-config-next": "^16.3.8",
"jsdom": "^30.1.1",
"jsdom": "^30.1.2",
"tailwindcss": "^4",
"tsx": "^4.23.15",
"typescript": "^6.0.3",
"vitest": "^5.0.3",
"storybook": "^10.6.1",
"@storybook/nextjs-vite": "^10.6.1",
"@chromatic-com/storybook": "^5.3.1",
"@chromatic-com/storybook": "^5.4.0",
"@storybook/addon-vitest": "^10.6.1",
"@storybook/addon-a11y": "^10.6.1",
"@storybook/addon-docs": "^10.6.1",
"@storybook/addon-mcp": "^10.6.1",
"vite": "^8.3.1",
"vite": "^8.3.3",
"eslint-plugin-storybook": "^10.6.1",
"@vitest/browser-playwright": "5.0.3",
"playwright": "^1.63.0"
Expand Down
Loading
Loading