Feat/ga4 mp#71
Conversation
- Rename helpers to match GA4-Data-Taxonomy.md naming convention
- sendTabChange → sendNavigationTabSelect
- sendLinkClick → sendLinkOpen (+ linkGroup, sameHostVariant params)
- sendGAEvent("search") → sendSearchSubmit
- sendSettingChange → sendSettingsCredentialsSaved / Deleted
- sendButtonClick("google_login/logout") → sendAuthLoginStart / sendAuthLogout
- sendError → sendSystemError
- Add sendExtensionOpen: single call emits extension_first_open (최초 1회),
extension_session_start (새 세션 시), extension_open (매번) in one fetch
- getOrCreateSessionId now returns { sessionId, isNewSession } to support
session_start detection without an extra storage read
- Restore and add JSDoc for all exported functions
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- sendButtonClick("google_login") → sendAuthLoginStart("google", ...)
- sendButtonClick("google_logout") → sendAuthLogout(...)
- sendSettingChange("credentials", "saved") → sendSettingsCredentialsSaved()
- sendSettingChange("credentials", "deleted") → sendSettingsCredentialsDeleted()
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Auth: sendAuthLoginSuccess, sendAuthLoginFail,
sendAuthEmailVerificationStart, sendAuthEmailVerificationSuccess
Template (editor): sendTemplateEditorOpen, sendTemplateItemAdd,
sendTemplateSaveSuccess/Fail, sendTemplateSyncSuccess/Fail,
sendTemplatePublishSuccess/Fail, sendTemplateApply
Template (gallery): sendTemplateGalleryOpen, sendTemplateGallerySearch,
sendTemplateGallerySortChange, sendTemplateCloneSuccess/Fail,
sendTemplateLikeToggle
Alerts: sendAlertsViewOpen, sendAlertsItemOpen
Todo: sendTodoViewOpen, sendTodoItemCreate, sendTodoItemComplete, sendTodoItemDelete
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
EditorHeader: save/sync/publish success+fail events with templateId, origin (owned|cloned), itemCount, errorCode, errorMessage EditorPage: extension_editor_open on mount (origin derived from route params), template_item_add on staging→canvas drag TemplateListPage: template_apply with origin (default|owned|cloned) and isDefault flag Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
SettingsDialog: auth_login_success (with is_guest flag) and auth_login_fail (error_code: login_failed | exception) after startGoogleLogin resolves EmailVerificationDialog: auth_email_verification_start when dialog opens, auth_email_verification_success after verifyEmailCode succeeds Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Alerts: alerts_view_open on mount (viewMode, category resolved from storage) AlertItem: alerts_item_open on click (alertId, category, source: general|department) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
TodoList: todo_view_open after initial load (1회, useRef guard), todo_item_complete and todo_item_delete on custom todo actions TodoAddDialog: todo_item_create after addCustomTodo succeeds (source: "dialog", has_due_date: always true by form validation) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- template_gallery_open on mount (entry_point: "popup") - template_gallery_search on debounced query (query_length, sort_option) - template_gallery_sort_change on sort dropdown select - template_clone_success (posted_template_id, author_id_present) after clone - template_clone_fail (posted_template_id, error_code) on error - template_like_toggle (posted_template_id, liked) after like resolves Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…or call sites
ItemPropertiesPanel: sendTemplateItemAdd('button', templateItemId) in
handleMoveToCanvas — covers the button path alongside the existing drag path
App: connect sendSystemError to ErrorBoundary onError so uncaught React
errors are reported as system_error events (error_code: react_error_boundary)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
'sort'를 useEffect 의존성에 추가해 stale 클로저로 인한 잘못된 sort_option 전송 방지 및 eslint exhaustive-deps 경고 제거. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
sendTodoViewOpen 전송을 별도 useEffect로 분리해 loadTodoList의 useCallback deps에서 allTodos.length를 제거함. 기존 구조에서는 setECampusTodos → allTodos 변경 → loadTodoList 재계산 → useEffect 재실행으로 eCampus API가 불필요하게 재호출되는 문제가 있었음. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
standardCategories 집합으로 category 필드를 검사해 학과명이 들어온 경우를 학과 공지(source=department)로 정확히 분류함. 기존에는 department 필드 유무만 확인해 category에 학과명이 들어온 형태를 general로 잘못 보고했음. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
sendTemplateCloneFail에 errorMessage 선택 파라미터를 추가해 sendTemplateSaveFail, sendTemplateSyncFail 등 다른 fail 헬퍼와 시그니처를 통일함. 호출부에서 error.message를 errorCode로 넘기던 잘못된 패턴도 수정. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ments taxonomy 강제를 위해 sendGAEvent의 export를 제거함. 모든 이벤트 정의는 이 파일 안에서만 이루어지므로 외부에서 직접 호출할 이유가 없음. 모듈 상단 JSDoc에 설계 원칙·도메인 헬퍼 목록·전송 흐름 추가. getOrCreateSessionId, sendGAEvent, sendExtensionOpen 세 함수에 비자명한 동작(세션 fallback 부작용, engagement_time_msec 이유, lifecycle 이벤트 배열 누적 조건)에 대한 인라인 주석 추가. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
/debug/mp/collect는 페이로드 유효성 검증만 하고 GA4에 기록하지 않아 DebugView에 이벤트가 나타나지 않는 문제가 있었음. DebugView 표시는 엔드포인트가 아닌 debug_mode: 1 파라미터로 제어되므로 항상 /mp/collect(production endpoint)로 전송하도록 수정함. GA_DEBUG_ENDPOINT 상수도 함께 제거. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
모든 이벤트 상태를 '신규 제안' 대신 '구현됨' / '미구현'으로 명확히 표기. 주요 변경사항: - 구현된 이벤트 전체를 '구현됨'으로 업데이트 - template_clone_fail 파라미터에 error_message? 추가 반영 - navigation_tab_select에서 ui_location 미전송 명시 - button_click을 Core Product Events에 추가 - 'Current Event Mapping'을 'Migration History'로 대체 (구 이벤트는 이미 모두 제거됐으므로 이력 표로 정리) - MVP Recommendation 표에 상태 컬럼 추가 - Identity Model에 DebugView 동작 방식 설명 추가 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
MV3에서 popup close 시 async fetch 신뢰성 문제로 수집 불가. 세션 종료 추정은 session_id 30분 타임아웃으로 충분하며 정의된 Explore Reports에서도 사용처가 없어 제거. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
/mp/collect는 204 No Content를 반환하므로 response.json() 호출 시 SyntaxError가 throw되어 catch 블록으로 빠지면서 실제 전송은 성공했음에도 [GA] Error sending event 로그가 찍히는 문제 수정. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
미구현 상태였던 이벤트들의 헬퍼 함수 추가: - template_create_start, template_name_edit, template_item_update, template_item_delete, template_delete - settings_open - banner_open - alerts_subscription_change - labs_view_open, labs_feature_use Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…e events - banner_open: ImageCarousel 배너 클릭 시 img/alt/position 전송 - settings_open: MainLayout 설정 아이콘 클릭 시 전송 - template_create_start: 기본/빈 템플릿 생성 진입 시 origin 구분 전송 - template_delete: 로컬/서버 삭제 성공 후 origin·sync_status 전송 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- template_name_edit: 1초 debounce 후 전송 (keystroke 과다 방지) - template_item_update: 아이템 속성 저장 성공 시 전송 - template_item_delete: 영구삭제(staging) / 캔버스→임시저장(canvas) 구분 전송 templateId를 ItemPropertiesPanelForm props로 추가해 이벤트 맥락 제공. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- labs_view_open: LabsDialog 진입 시 전송 - labs_feature_use: QR 생성 성공/실패, 도서관 열람실 클릭 시 전송 - alerts_subscription_change: 학과 구독/취소 성공 시 category·result 전송 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
banner_open, template_create_start, template_name_edit, template_item_update, template_item_delete, template_delete, settings_open, alerts_subscription_change, labs_view_open, labs_feature_use 모두 구현 완료. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
구현된 전체 47개 이벤트를 알파벳 순으로 정리한 레퍼런스 표 추가. 이벤트명 / 수집 목적 / 수집 속성 / 사용 코드 / 잔존이슈 포함. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 897efb1776
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| const handleMoveToCanvas = () => { | ||
| if (!isFromStaging) return; | ||
| dispatch({ type: 'MOVE_TO_CANVAS', payload: selectedItem.templateItemId }); | ||
| sendTemplateItemAdd('button', selectedItem.templateItemId); |
There was a problem hiding this comment.
Send template ID, not item ID, in template_item_add
This call passes selectedItem.templateItemId as the second argument, but sendTemplateItemAdd maps that argument to GA4 template_id. In the staging→canvas button flow, that records an item identifier as a template identifier, so template_item_add data from this path is mis-keyed and cannot be reliably analyzed with template-level events like save/apply.
Useful? React with 👍 / 👎.
| if (!firstOpenSent) { | ||
| events.push({ name: "extension_first_open", params: baseParams }); | ||
| await setStorage({ firstOpenSent: true }); |
There was a problem hiding this comment.
Persist first-open marker only after lifecycle send succeeds
firstOpenSent is stored before the lifecycle payload is posted. If the first popup open occurs while offline (or the fetch fails), the marker remains set and extension_first_open will never be retried for that client, permanently undercounting first-open cohorts and retention baselines.
Useful? React with 👍 / 👎.
| const origin = templateId ? 'owned' : startFrom === 'default' ? 'default' : 'local_only'; | ||
| sendTemplateEditorOpen(origin, templateId ? parseInt(templateId) : undefined); |
There was a problem hiding this comment.
Derive editor-open origin from real template source
When templateId exists, origin is hardcoded to 'owned'. Cloned templates are also opened via /editor/:templateId, so those sessions will be reported as owned and distort template_editor_open breakdowns by origin. This should use actual template metadata (or explicit navigation state) instead of inferring from presence of an ID.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Code Review
This pull request implements a comprehensive GA4 Measurement Protocol taxonomy for the LinKU Chrome Extension, replacing generic event tracking with structured, domain-specific event helpers. It includes a new taxonomy documentation file and updates various components to use these specific helpers for lifecycle, navigation, search, authentication, template management, and other product features. A critical issue was identified in src/components/Tabs/Alerts/AlertItem.tsx where standardCategories is used but not defined, which will cause a runtime error. Additionally, the use of eslint-disable-next-line in EditorPage.tsx and the hardcoded engagement_time_msec in analytics.ts were noted as areas for potential improvement.
| import type { Alert, AlertCategory } from "@/types/api"; | ||
| import { ExternalLink, Calendar } from "lucide-react"; | ||
| import { cn } from "@/lib/utils"; | ||
| import { sendAlertsItemOpen } from "@/utils/analytics"; |
There was a problem hiding this comment.
The variable standardCategories is used in the handleClick function but is not defined or imported in this file. This will cause a ReferenceError at runtime when an alert item is clicked. Please define it locally or import it from a shared constants file.
import { sendAlertsItemOpen } from "@/utils/analytics";
const standardCategories = new Set(["일반", "학사", "학생", "장학", "취창업", "국제"]);
…, remove duplicates and noise
- 레거시 이벤트 5건 복구 (v1.5.46 연속성 유지)
· link_open → link_click (sendLinkOpen → sendLinkClick)
· navigation_tab_select → tab_change (sendNavigationTabSelect → sendTabChange)
· system_error → error (sendSystemError → sendError)
· page_view 재도입 (App.tsx에서 sendExtensionOpen과 함께 호출)
· setting_change 재도입 (sendSettingsCredentialsSaved/Deleted 내부에서 병렬 발송)
- 신규 이벤트 41건에 MP_ prefix + camelCase 컨벤션 적용
· 이벤트명 형식: MP_{object}_{action}
· 복합어 camelCase: MP_authLogin_start, MP_templateEditor_view 등
· 파라미터 정합성: author_id_present → is_author_id_present, liked → is_liked,
subscription result → subscription_result
- 중복 트래킹 3건 제거
· settings_icon 클릭: sendSettingsOpen 제거 (button_click 레거시로 대체, 직접 중복)
· labs_icon 클릭: sendButtonClick 제거 (labs_open이 다이얼로그 진입 시점 포착, 간접 중복)
· open_template_editor 클릭: sendButtonClick 제거 (editor_view가 진입 포착, 간접 중복)
- P3 이벤트 2건 제거 (분석 가치 낮음)
· template_name_edit (결과는 template_save_success에 함축됨)
· template_gallery_sort_change (gallery_search의 sort_option 파라미터에 포함됨)
- EditorHeader.tsx에서 debounce ref 제거 (template_name_edit 제거에 따라)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ention - GA4-Data-Taxonomy.md · Migration History 2단계로 분리 (v1.5.46→GA4-MP, 컨벤션 정립) · 이벤트 레퍼런스 표를 레거시/신규 두 그룹으로 재구성 · 신규 이벤트 39개 MP_ prefix 및 새 이름 반영 · 제거된 이벤트 2건(template_name_edit, template_gallery_sort_change) 명시 - GA4-Taxonmy_Conventioning.md · 동일 구조로 레거시/신규 분리 재작성 · 항목 컬럼 유지 (트래킹 시점 단문 설명) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
@gemini-code-assist review this PR |
There was a problem hiding this comment.
Code Review
This pull request establishes a comprehensive GA4 Data Taxonomy and implements it using the Measurement Protocol to enable product and retention analysis within the Chrome Extension. Key changes include a refactored analytics utility with session management and lifecycle tracking, alongside the integration of domain-specific event helpers across the application's core features like templates, authentication, and user interactions. Feedback focuses on resolving inconsistencies between the taxonomy documentation and the actual implementation, correcting a filename typo, and ensuring that gallery sort changes are captured even when no search query is present.
| @@ -0,0 +1,309 @@ | |||
| # GA4 Data Taxonomy | |||
There was a problem hiding this comment.
이 택소노미 문서와 실제 구현 사이에 몇 가지 불일치하는 부분이 보입니다. 유지보수성을 높이기 위해 문서를 코드와 일치시키는 것을 권장합니다.
template_clone_success이벤트: 문서(133행)에는author_id_present파라미터로, 구현된 레퍼런스(293행)와 코드에는is_author_id_present로 되어 있습니다.template_like_toggle이벤트: 문서(135행)에는liked파라미터로, 구현된 레퍼런스(291행)와 코드에는is_liked로 되어 있습니다.MP_settingsCredentials_save/delete이벤트(186행): '과거형 제거'가 사유로 언급되었지만, 코드의 함수명은...Saved/...Deleted로 과거형을 사용하고 있어 혼란을 줄 수 있습니다.MP_templateEditor_view이벤트(294행):clonedorigin이 미분류된다는 비고가 있지만,EditorPage.tsx의 구현을 보면clonedorigin을 잘 처리하고 있는 것으로 보입니다. 문서 업데이트가 필요해 보입니다.
| @@ -0,0 +1,61 @@ | |||
| ## 구현된 이벤트 전체 레퍼런스 | |||
| if (searchQuery.trim()) { | ||
| sendTemplateGallerySearch(searchQuery.trim().length, sort); | ||
| } |
There was a problem hiding this comment.
현재 구현에서는 검색어(searchQuery)가 있을 때만 sendTemplateGallerySearch 이벤트가 전송됩니다. 이로 인해 사용자가 검색어 없이 정렬 옵션만 변경하는 경우에는 분석 이벤트가 누락될 수 있습니다.
template_gallery_sort_change 이벤트를 이 이벤트에 통합하려는 본래 의도를 살리려면, 검색어가 없더라도 정렬 옵션 변경 시 이벤트를 보내는 것이 좋아 보입니다.
setTimeout 콜백 내에서 searchQuery 확인 조건을 제거하여 항상 이벤트를 전송하도록 수정하는 것을 고려해 보세요.
sendTemplateGallerySearch(searchQuery.trim().length, sort);
Turtle-Hwan
left a comment
There was a problem hiding this comment.
thanks for attach GA4 taxonomy
No description provided.