{
 "id": "7.3",
 "title": "Tracking plan",
 "department": "Data and analytics",
 "department_slug": "data-and-analytics",
 "direction": null,
 "branded": false,
 "status": "needs-you",
 "owner": "Param",
 "last_verified": "Mon Oct 26",
 "holds": "Events, properties, where they fire",
 "urls": {
  "html": "https://handbook.joinsquareup.com/data-and-analytics/tracking-plan",
  "markdown": "https://handbook.joinsquareup.com/data-and-analytics/tracking-plan.md",
  "json": "https://handbook.joinsquareup.com/data-and-analytics/tracking-plan.json"
 },
 "other_directions": [],
 "tldr": {
  "headline": "No analytics today; here are the events to log ourselves",
  "points": [
   {
    "icon": "warn",
    "text": "The product has no usage analytics and no outside trackers."
   },
   {
    "icon": "box",
    "text": "One Postgres table called events, written by the server, never by a third party script."
   },
   {
    "icon": "flag",
    "text": "The v1 events cover reads, hearts, makes, hand-offs and corrected facts."
   },
   {
    "icon": "lock",
    "text": "Staff and demo acts are tagged apart, and a store's customers are never logged."
   }
  ],
  "stat": {
   "value": "21",
   "label": "Event names defined 26 Oct"
  },
  "decide": "Approve the v1 event list, and who builds it?",
  "mood": "waiting"
 },
 "sources": [
  "brew/db/migrations/002_jobs_counters_events.sql",
  "brew/db/migrations/003_access.sql:2-30",
  "brew/sessions.js:19-22",
  "brew/server.js:657-666, 724",
  "brew/member-tuning.js:1-8",
  "brew/brief-status.js:1-12",
  "brew/facts-desk.js:1-5",
  "brew/SCOPE.md:18",
  "brew/reader/stages/site.js:14-26",
  "brand-directions/book/content/j.js j-1 events, onboarding-funnel",
  "memory squareup-tracking-structure, brew-access-rules",
  "handbook content/product/product-metrics.md, content/security-privacy-and-legal/privacy-policy.md"
 ],
 "open_questions": [
  "**Approve the event list?** Proposal: yes, the v1 rows only, built as one change by engineering before the redesign.",
  "**Our own table or an analytics vendor?** Proposal: our own table in Postgres, so no new subprocessor and no cookie banner.",
  "**Track the future public site?** Proposal: the marketing site may use the Setup Analytics pattern; the product itself never does, and the privacy page says which is which."
 ],
 "parts": {
  "Answer": "The product has no usage analytics and no trackers; this plan names the events to log, their fields and where each fires, in our own Postgres table, so the numbers in metric definitions can be counted, and it waits on Param to approve the event list and who builds it.",
  "Today": "### What the product already records\n\n| Record | What it holds | Where | Source |\n|---|---|---|---|\n| Sign ins | Email, start, expiry, browser, sign out time | `sessions` | [src: brew/db/migrations/003_access.sql:2-10] [src: brew/sessions.js:19-22] |\n| Brand opens | Brand, email, first and last open, count, access kind | `access_log` | [src: brew/db/migrations/003_access.sql:19-29] [src: brew/server.js:657-666] |\n| Read progress | A build's progress lines, kept 3 days | `build_events` | [src: brew/db/migrations/002_jobs_counters_events.sql] [src: brew/server.js:724] |\n| Day counters | AI calls by kind and brand, treg dollars, build dollars, per UTC day | `counters` | [src: brew/db/migrations/002_jobs_counters_events.sql] |\n| Hearts, Not for me, saves, feed tuning | Per member, per brand | Member tuning state | [src: brew/member-tuning.js:1-8] |\n| Brief status | Sent, received, in progress, needs info, delivered, with who and when | The work item's history | [src: brew/brief-status.js:1-12] |\n| Fact edits | Who changed which fact, when | `facts-edits.json` | [src: brew/facts-desk.js:1-5] |\n| Jam messages and versions | Who made each | The team's jams | [src: brew/SCOPE.md:18] |\n\n### What does not exist\n\n- No product analytics: no GA4, Meta pixel or any third party script in the product's pages. [src: handbook content/product/product-metrics.md]\n- No one log of acts that the metrics can be counted from. [src: brand-directions/book/content/j.js j-1 events]\n- The reader detects a brand's own pixels and tags on its store; that is a read signal about the brand, not our tracking. [src: brew/reader/stages/site.js:14-26]\n- The company's other products use one Meta dataset and one GA4 property each through the Setup Analytics skill; nothing like that exists for this product's pages. [src: memory squareup-tracking-structure]",
  "Tomorrow": "### The event table, proposed\n\nOne Postgres table, `events`, written by the server, never by a third party script.\n\n| Field | Holds |\n|---|---|\n| `at` | When, UTC |\n| `slug` | The brand |\n| `who` | The member's email, or staff, or guest, or demo |\n| `kind` | The event name below |\n| `card`, `play` | The card or Play, when there is one |\n| `area` | creative, performance, storefront, visibility, crm |\n| `week` | Monday of the brand's week |\n| `props` | A few fields per event, never a store customer's data |\n\n### The events, proposed\n\n| Event | Fires when | Where in code | Version | Tag |\n|---|---|---|---|---|\n| `read_started` | A read starts | the build start | v1 | New |\n| `read_finished`, `read_failed` | A read ends or stops, with the step it stopped at | the build end | v1 | New |\n| `feed_opened` | A member opens the feed | feed open | v1 | New |\n| `heart`, `not_for_me`, `later` | On any card | member tuning | v1 | New |\n| `make_opened` | A card opens the Studio | the jam | v1 | New |\n| `version_made` | A new version is made | the Studio | v1 | New |\n| `paid_make_confirmed` | A paid make is confirmed, with its price | finals and makes | v1 | New |\n| `handed_off` | A brief is shared or sent, with who it is for | Share the brief | v1 | New |\n| `brief_status` | A sent brief moves | brief status | v1 | New |\n| `fact_corrected` | A to confirm fact is corrected | the fact desk | v1 | New |\n| `email_sent`, `email_opened` | Team emails | mail | v1 | New |\n| `post_scheduled`, `post_published` | A post the team approved | v2 posting | v2 | New |\n| `launch_recorded`, `result_read` | A shipped Play and its reads | v3 engine | v3 | New |\n| `rule_run`, `rule_undone` | An ad rule acts or is undone | v4 rules | v4 | New |\n\n### Rules\n\n- Demo visits and staff acts are tagged and counted apart. [src: brand-directions/book/content/j.js j-1 onboarding-funnel]\n- Never log what a store's customer does.\n- The privacy page says what we log; a new kind of event means a check against it.",
  "How we do it": "1. Add an event by adding a row above first, then one `events` insert at the server point named.\n2. Never send an event to an outside service.\n3. Check events arrive after a deploy:\n\n```bash\ngcloud run jobs execute brew-ops --region=asia-south1 --wait\n```\n\n`db/status.mjs` prints table sizes; add `events` to its list when the table lands.",
  "Numbers": "| Metric | Definition | Where measured | Status |\n|---|---|---|---|\n| Events defined | Rows in the events table above | This page | 21 names on 26 Oct |\n| Events live | Event kinds seen in `events` in the last 7 days | `events` table | 0, Proposed |",
  "Open": "1. **Approve the event list?** Proposal: yes, the v1 rows only, built as one change by engineering before the redesign.\n2. **Our own table or an analytics vendor?** Proposal: our own table in Postgres, so no new subprocessor and no cookie banner.\n3. **Track the future public site?** Proposal: the marketing site may use the Setup Analytics pattern; the product itself never does, and the privacy page says which is which."
 }
}