Fas 1a: analytics tracker, ingestion endpoint, admin dashboards

This commit is contained in:
Sven (AAMOS AI)
2026-08-05 22:15:37 +07:00
parent d627014425
commit 1250640b1d
16 changed files with 4544 additions and 6450 deletions
+90
View File
@@ -0,0 +1,90 @@
/**
* Typed event builders for the product analytics taxonomy.
* Each builder returns a plain AnalyticsEvent ready for batching.
*/
import type { ProductAnalyticsEventName } from "@app/shared-types";
import type { AnalyticsEvent } from "./types.js";
function builder(name: ProductAnalyticsEventName) {
return (props?: {
occurredAt?: string;
anonymousId?: string;
sessionId?: string;
householdId?: string;
appVersion?: string;
platform?: "ios" | "android" | "web";
locale?: string;
experimentVariant?: string;
properties?: Record<string, unknown>;
}): AnalyticsEvent => ({ name, ...props });
}
// Acquisition & onboarding
export const appInstalled = builder("app_installed");
export const appFirstOpen = builder("app_first_open");
export const onboardingStarted = builder("onboarding_started");
export const onboardingStepCompleted = builder("onboarding_step_completed");
export const onboardingSkipped = builder("onboarding_skipped");
export const accountCreated = builder("account_created");
export const householdCreated = builder("household_created");
export const householdJoined = builder("household_joined");
export const allergySetupCompleted = builder("allergy_setup_completed");
export const cameraPermissionResult = builder("camera_permission_result");
export const notificationPermissionResult = builder("notification_permission_result");
// Inventory
export const scanStarted = builder("scan_started");
export const scanUploaded = builder("scan_uploaded");
export const scanProcessingCompleted = builder("scan_processing_completed");
export const scanProcessingFailed = builder("scan_processing_failed");
export const scanReviewOpened = builder("scan_review_opened");
export const scanItemConfirmed = builder("scan_item_confirmed");
export const scanItemCorrected = builder("scan_item_corrected");
export const scanItemRemoved = builder("scan_item_removed");
export const scanCompleted = builder("scan_completed");
export const inventoryItemAdded = builder("inventory_item_added");
export const inventoryItemConsumed = builder("inventory_item_consumed");
export const inventoryItemDiscarded = builder("inventory_item_discarded");
export const inventoryReconciliationStarted = builder("inventory_reconciliation_started");
export const inventoryReconciliationCompleted = builder("inventory_reconciliation_completed");
export const inventoryConflictCreated = builder("inventory_conflict_created");
export const inventoryConflictResolved = builder("inventory_conflict_resolved");
// Recipes & cooking
export const recommendationsViewed = builder("recommendations_viewed");
export const recommendationOpened = builder("recommendation_opened");
export const recipeSaved = builder("recipe_saved");
export const cookingSessionStarted = builder("cooking_session_started");
export const cookingSessionCompleted = builder("cooking_session_completed");
export const cookingSessionCancelled = builder("cooking_session_cancelled");
export const leftoversCreated = builder("leftovers_created");
export const substitutionConfirmed = builder("substitution_confirmed");
// Shopping
export const shoppingItemAdded = builder("shopping_item_added");
export const shoppingItemChecked = builder("shopping_item_checked");
export const shoppingListShared = builder("shopping_list_shared");
export const receiptScanned = builder("receipt_scanned");
export const purchaseImported = builder("purchase_imported");
// Household
export const householdInviteSent = builder("household_invite_sent");
export const householdInviteAccepted = builder("household_invite_accepted");
export const secondMemberFirstAction = builder("second_member_first_action");
// Subscription
export const paywallViewed = builder("paywall_viewed");
export const trialStarted = builder("trial_started");
export const trialCancelled = builder("trial_cancelled");
export const subscriptionStarted = builder("subscription_started");
export const subscriptionRenewed = builder("subscription_renewed");
export const subscriptionGracePeriod = builder("subscription_grace_period");
export const subscriptionCancelled = builder("subscription_cancelled");
export const subscriptionExpired = builder("subscription_expired");
export const entitlementRestored = builder("entitlement_restored");
// Feedback
export const feedbackSubmitted = builder("feedback_submitted");
export const incorrectInventoryReported = builder("incorrect_inventory_reported");
export const badRecommendationReported = builder("bad_recommendation_reported");
export const supportContactStarted = builder("support_contact_started");