You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Segment dispatch is disabled pending alignment with the analytics team. The $track call in frontend/composables/useTrackEvent.ts is commented out; events continue to persist to the internal events table via /api/events. Re-enable Segment by uncommenting the $track block and the two commented imports in the composable.
This pull request introduces a comprehensive event tracking system to the Insights app, focusing on Community Collections features. It adds an event catalog, a database schema for event storage, and integrates event tracking calls throughout the main collection-related Vue components. The tracking is implemented using the new useTrackEvent composable and catalog-driven event definitions, ensuring consistent analytics for user actions such as creating, updating, deleting, and sharing collections.
Event Tracking Infrastructure
Added .claude/skills/event-tracking/SKILL.md, documenting the workflow, file structure, and usage patterns for event tracking in the Insights app. This includes detailed instructions for adding and instrumenting events using the useTrackEvent composable and catalog-driven enums.
Introduced .claude/skills/event-tracking/references/events-catalog.md, which catalogs all approved events, their keys, types, and allowed properties for Community Collections. This serves as the source of truth for event instrumentation.
Added a new SQL migration V1775900000__createEventsTable.sql to create a normalized events table for tracking user interactions, including indexes for efficient querying.
Instrumentation of Collection Features
Integrated trackEvent calls into all major Community Collections flows:
Added tracking for creating, duplicating, updating, deleting, and sharing collections, as well as adding projects to collections, using the correct event keys and properties as defined in the catalog. [1][2][3][4][5][6]
Tracked abandonment events for collection creation, duplication, and editing when modals are closed with unsaved changes. [1][2]
Ensured all tracking calls are placed after successful operations and only use catalog-approved properties, following best practices outlined in the documentation. [1][2]
Component and Codebase Updates
Updated relevant Vue components (add-to-collection-modal.vue, create-collection-modal.vue, edit-collection-modal.vue, details/header.vue) to import and use the new event tracking infrastructure. [1][2][3][4][5][6][7]
Minor code cleanup (e.g., fixed duplicated class in list/header.vue).
This foundational work enables robust analytics and paves the way for consistent, catalog-driven event tracking across the Insights frontend.
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This PR adds a catalog-driven analytics/event tracking system for the Insights “Community Collections” feature set, including a new events API endpoint + DB persistence, plus instrumentation across the main collection flows in the Nuxt/Vue frontend.
Changes:
Added server-side infrastructure to accept and persist tracked events (/api/events, repository, DB migration).
Introduced a frontend composable (useTrackEvent) and an event catalog/enum definitions to standardize event metadata.
Instrumented collection pages and components (view/share/create/update/delete/like/add-to-collection + abandonment events).
Reviewed changes
Copilot reviewed 22 out of 22 changed files in this pull request and generated 8 comments.
Show a summary per file
File
Description
frontend/server/repo/events.repo.ts
New repository to insert tracked events into Postgres
frontend/server/middleware/database.ts
Allows DB pool injection for the new /api/events route
frontend/server/api/events/index.post.ts
New POST endpoint to receive and store events
frontend/composables/useTrackEvent.ts
New client-side composable to fire catalog-defined events
$track is provided only after the analytics plugin waits for window.load, downloads the CDN script, and initializes it. The new onMounted page events run earlier, so this optional call silently drops their Segment copy. Queue events until analytics is ready or expose a synchronous buffering function.
Validate request field types before calling trim
frontend/server/api/events/index.post.ts:52
The TypeScript annotation does not validate request JSON. A numeric key, type, or name makes .trim() throw before the try, producing a 500 instead of the documented 400. Add runtime type guards before trimming.
The code defines ADD_REPO_TO_COLLECTION, but the catalog omits it even though this document is declared the source of truth. Add the event and its allowed repository property shape, then use it for the repository branch of the add-to-collection modal.
- Derive userId from server session instead of client-supplied body
- Suppress DB error details from 500 HTTP response
- Track VIEW_COLLECTION with real collection id via watch({once:true})
instead of onMounted with slug
- Emit ADD_REPO_TO_COLLECTION (not ADD_PROJECT_TO_COLLECTION) for
repository additions in add-to-collection modal
- Remove sourceCollectionId from ABANDONED_COLLECTION_DUPLICATION
(catalog allows no properties for this event)
- Track ABANDONED_COLLECTION_EDITION in closeModal() before form reset
so Cancel/close buttons capture the event
- Add projects/repositories to changedFields on UPDATE_COLLECTION
- Emit SHARE_COLLECTION after share action fires, not before modal opens
- Fix analytics reset: only call reset() on auth->unauth transition,
not on every unauthenticated page load
- Type $track without eslint-disable any suppression
- Fix SKILL.md: remove description field, fix import path and
EventFeature location for new-feature workflow
- Add ADD_REPO_TO_COLLECTION to events catalog
Signed-off-by: Joana Maia <jmaia@contractor.linuxfoundation.org>
readBody<T> does not enforce these types at runtime. A public request with numeric source or entrySource reaches .trim() and returns a 500; validate both optional fields and return 400 before normalizing them.
Align catalog event name with persisted definition
The catalog still names this event “Duplicate collections,” while COLLECTIONS_EVENT_DEFINITIONS now uses the singular “Duplicate collection.” Since the catalog is documented as the source of truth, align it with the value actually persisted.
…n IN-1025
Use newCollectionId (not collectionId) in SKILL.md examples for
CREATE_COLLECTION — collectionId is stripped server-side by the
allowlist filter. Update the events API JSDoc to reflect that
properties are catalog-filtered, not arbitrary.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Joana Maia <jmaia@contractor.linuxfoundation.org>
typeof null is 'object', so this check accepts properties: null despite the documented object contract. Explicitly reject null to keep runtime validation aligned with the endpoint type.
Validate optional source fields are strings before trimming
frontend/server/api/events/index.post.ts:72
The generic passed to readBody does not validate JSON at runtime. A valid-key request with numeric/object source or entrySource reaches .trim() and returns a 500; reject non-string optional values with a 400 first.
Update module layout to reference base.ts
.claude/skills/event-tracking/SKILL.md:28
This tree says the enums and interface live in index.ts, but they were moved to base.ts. Update the structure so future event work starts from the actual module layout.
Correct EventKey extension and definition aggregation guidance
.claude/skills/event-tracking/SKILL.md:33
index.ts does not re-export the feature enum or definitions; it imports them and aggregates the definitions. Update this instruction to describe extending EventKey and spreading the definitions, otherwise a future feature may follow a nonexistent export pattern.
Include required allowedProperties in the example
.claude/skills/event-tracking/SKILL.md:207
EventDefinition requires allowedProperties, so following this new-feature example produces a TypeScript error. Include the required field in the sample.
The reason will be displayed to describe this comment to others. Learn more.
Copilot review overview
🔵 Needs a closer look
The public endpoint has runtime validation gaps, and several skill examples conflict with the implemented event contract.
Review effort: Balanced Findings: None
Previously missed (12)
In code that hasn't changed since last review
Validate URL fields at runtime before trimming
frontend/server/api/events/index.post.ts:72
Because this public route only has compile-time body types, numeric or object source values reach .trim() and return a 500. Runtime-check both URL fields and return 400 before trimming them.
Add runtime schemas for event property values
frontend/server/api/events/index.post.ts:77
Allowlisting property names does not validate their values. Public callers can persist objects as collectionId, arbitrary strings as shareMethod, or malformed arrays, corrupting analytics. Add per-event runtime schemas for property value types.
Include required imports and type in re-enable instructions
.claude/skills/event-tracking/SKILL.md:15
This re-enable instruction is incomplete: the composable also requires its commented useNuxtApp import and TrackFn type. Following the skill as written produces unresolved names.
Correct the shared types file tree
.claude/skills/event-tracking/SKILL.md:28
This tree incorrectly says index.ts defines the shared enums/interface and omits base.ts. That conflicts with the implementation and will direct future changes to the wrong file.
Clarify imports and aggregation in the workflow
.claude/skills/event-tracking/SKILL.md:33
This says to re-export both symbols, but index.ts only imports them for the union/aggregate and callers import feature enums directly. Say “import and aggregate” so the workflow matches the shown code.
Use approved fields in an immediate guarded watcher example
.claude/skills/event-tracking/SKILL.md:138
This example sends viewerType, which is absent from VIEW_COLLECTION.allowedProperties and is silently stripped, and its non-immediate watcher misses SSR-hydrated data. Show a guarded immediate watcher using catalog-approved fields.
Include allowedProperties in every event definition example
.claude/skills/event-tracking/SKILL.md:207
EventDefinition requires allowedProperties, so following this new-feature example fails TypeScript compilation. Include the required allowlist in every definition sample.
The catalog still calls this event “Duplicate collections,” while COLLECTIONS_EVENT_DEFINITIONS now emits “Duplicate collection.” Keep the source of truth aligned so dashboards and future instrumentation use the actual name.
Clarify callback-order constraint without an em dash
The repository convention forbids em dashes in code comments (CLAUDE.md:182). This can state the callback-order constraint more directly.
Document all required changes to re-enable the block
frontend/composables/useTrackEvent.ts:22
Uncommenting only this block leaves useNuxtApp and TrackFn commented, so the documented re-enable step will not compile. Mention all three required changes.
Clarify server-side constraint without an em dash
frontend/composables/useTrackEvent.ts:38
The repository convention forbids em dashes in code comments (CLAUDE.md:182), and this comment should explain the server-side constraint rather than narrate the request.
Remove em dash from route-contract comment
frontend/server/api/events/index.post.ts:33
The repository convention forbids em dashes in code comments (CLAUDE.md:182). Rephrase this route-contract explanation without one.
This issue also appears on line 39 of the same file.
The reason will be displayed to describe this comment to others. Learn more.
Copilot review overview
🔵 Needs a closer look
The public endpoint mishandles malformed URL fields, and several tracking instructions conflict with the implemented catalog.
Review effort: Balanced Findings: None
Previously missed (4)
In code that hasn't changed since last review
Validate source and entrySource runtime types before trimming
frontend/server/api/events/index.post.ts:84
source and entrySource are only statically typed. A public caller can send a number or object, causing .trim() to throw and return 500 instead of the documented 400. Validate both runtime types before trimming.
Include useNuxtApp and TrackFn declarations when re-enabling the block
.claude/skills/event-tracking/SKILL.md:15
Re-enabling only this block leaves useNuxtApp and TrackFn commented, so the composable will not compile. Include the two supporting declarations in the instruction, matching the PR status guidance.
This issue also appears in the following locations of the same file:
line 24
line 121
line 129
line 204
Align the catalog name with the singular event definition
The catalog name remains plural while COLLECTIONS_EVENT_DEFINITIONS now uses the singular Duplicate collection. Keep the source-of-truth entry aligned with the emitted metadata.
Rewrite the comment to explain the trust boundary
frontend/composables/useTrackEvent.ts:38
Per CLAUDE.md:178-182, this comment narrates the next request and uses a prohibited em dash. Explain the trust boundary instead of restating the call.
When the selection partially overlaps the collection, the update deduplicates URLs but this event reports every selected URL, including repositories already present. Send only URLs actually added so analytics does not overcount additions.
Validate source fields before calling trim
frontend/server/api/events/index.post.ts:84
source and entrySource are only statically typed. A public caller can send a number or object, causing .trim() to throw and return a 500 instead of the documented 400. Validate both fields before trimming.
Include omitted declarations in rollout instructions
.claude/skills/event-tracking/SKILL.md:15
This rollout instruction also omits the commented useNuxtApp import and TrackFn declaration. Following it literally makes the re-enabled block fail type checking.
Align documented file tree with implementation
.claude/skills/event-tracking/SKILL.md:28
The documented tree assigns the enums and interface to index.ts, but they now live in base.ts. This contradicts the implementation and can send future contributors to the wrong file.
Include required allowedProperties in the example
.claude/skills/event-tracking/SKILL.md:207
EventDefinition requires allowedProperties, so the documented new-feature example does not type-check when copied. Include the required field to keep the workflow executable.
The catalog says Duplicate collections, while the executable definition records Duplicate collection. Since this file is the stated source of truth, align the name to prevent conflicting analytics documentation.
Repository comments explicitly prohibit em dashes. Rephrase this placement rationale without one.
Include all declarations in the re-enable instruction
frontend/composables/useTrackEvent.ts:22
The re-enable instruction is incomplete: uncommenting only the $track block leaves useNuxtApp and TrackFn commented, so the composable will not compile. Include both declarations in the instruction.
Remove em dash from server responsibility comment
frontend/composables/useTrackEvent.ts:38
Repository comments explicitly prohibit em dashes. This can state the server-side responsibility directly.
Remove em dash from anonymous event comment
frontend/server/api/events/index.post.ts:34
Repository comments explicitly prohibit em dashes. Rephrase this comment while preserving the reason that anonymous events are accepted.
Remove em dash from fallback explanation
frontend/server/api/events/index.post.ts:58
Repository comments explicitly prohibit em dashes. Rephrase this fallback explanation without one.
- Enforce 20 KB body limit while reading request stream, returning 413
before JSON parse so oversized payloads never buffer to memory
- Fix em dashes in comments (prohibited by CLAUDE.md)
- Update SKILL.md file tree: base.ts holds enums, index.ts is aggregator
- Add allowedProperties to new-feature EventDefinition example in SKILL.md
- Fix events-catalog.md: DUPLICATE_COLLECTION display name is singular
Signed-off-by: Joana Maia <jmaia@contractor.linuxfoundation.org>
The reason will be displayed to describe this comment to others. Learn more.
Copilot review overview
🟡 Changes recommended
Malformed inputs can cause server errors, repository events can over-report additions, and production Segment identification conflicts with the stated rollout status.
Get a fresh assessment by requesting another Copilot review.
This high-volume telemetry table stores every event indefinitely, and no retention or partitioning mechanism exists in the repository. The table and all five indexes therefore grow continuously; define a retention/archival or partition strategy before production rollout.
When some selected repositories already belong to the collection, the update deduplicates them but this event still reports every selected URL as newly added. Filter out existingRepoUrls so the analytics property reflects only repositories added by this operation.
Reject null properties in payload validation
frontend/server/api/events/index.post.ts:89
JSON null passes this typeof === 'object' check and is silently treated as absent later, although the endpoint contract says properties must be an object. Reject null so malformed payloads receive the documented 400 response.
Validate source fields are strings before trimming
frontend/server/api/events/index.post.ts:104
source and entrySource come from an untrusted JSON body, so the TypeScript annotation does not validate them. A payload such as { "source": 42 } throws at .trim() and produces a 500 instead of a validation response; reject non-string values first.
Include all required uncommented prerequisites
.claude/skills/event-tracking/SKILL.md:15
This rollout instruction omits the commented useNuxtApp import and TrackFn type alias. Following it literally makes the composable fail type-checking, so list all three pieces that must be uncommented.
Document all prerequisites for re-enabling the block
frontend/composables/useTrackEvent.ts:22
This instruction is incomplete: uncommenting only the block leaves useNuxtApp and TrackFn undefined because lines 3 and 7 remain commented. Include both prerequisites so the documented re-enable procedure compiles.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Status
Segment dispatch is disabled pending alignment with the analytics team. The
$trackcall infrontend/composables/useTrackEvent.tsis commented out; events continue to persist to the internaleventstable via/api/events. Re-enable Segment by uncommenting the$trackblock and the two commented imports in the composable.This pull request introduces a comprehensive event tracking system to the Insights app, focusing on Community Collections features. It adds an event catalog, a database schema for event storage, and integrates event tracking calls throughout the main collection-related Vue components. The tracking is implemented using the new
useTrackEventcomposable and catalog-driven event definitions, ensuring consistent analytics for user actions such as creating, updating, deleting, and sharing collections.Event Tracking Infrastructure
.claude/skills/event-tracking/SKILL.md, documenting the workflow, file structure, and usage patterns for event tracking in the Insights app. This includes detailed instructions for adding and instrumenting events using theuseTrackEventcomposable and catalog-driven enums..claude/skills/event-tracking/references/events-catalog.md, which catalogs all approved events, their keys, types, and allowed properties for Community Collections. This serves as the source of truth for event instrumentation.V1775900000__createEventsTable.sqlto create a normalizedeventstable for tracking user interactions, including indexes for efficient querying.Instrumentation of Collection Features
trackEventcalls into all major Community Collections flows:Component and Codebase Updates
add-to-collection-modal.vue,create-collection-modal.vue,edit-collection-modal.vue,details/header.vue) to import and use the new event tracking infrastructure. [1] [2] [3] [4] [5] [6] [7]list/header.vue).This foundational work enables robust analytics and paves the way for consistent, catalog-driven event tracking across the Insights frontend.