Commit 5fec46d
Schema (Drizzle migration 0006)
-------------------------------
- page_views: composite PK on (date, path), kind enum, optional
refId, integer count. UPSERT path so we get one row per day per
path with atomic increments.
- search_log: anonymized {term, noResults, date} only. No IP, no UA,
no fingerprint.
Tracker
-------
- $lib/server/analytics/index.ts:
- trackView(db, { path, kind, refId }, consent) — gated on
consent.analytics from the v1.7a cookie record. UPSERT bumps
the counter atomically. Best-effort: errors never break a public
page render.
- logSearch(db, term, noResults) — always written when /blog?q= is
used. Search is functional, not analytics-gated.
- AnalyticsService: topPaths / topArticles / topSearchTerms /
topNoResultTerms / sparkline / totalViews. All scoped to a
trailing N days (default 30). Sparkline densifies missing days
to 0 so the chart line stays continuous.
Instrumentation
---------------
- Public home, blog index, blog slug, page catch-all all call
trackView. Blog index also calls logSearch when ?q= is set, with
noResults flagged when articles.items.length === 0.
Dashboard
---------
- "Top articles (30 days)" tile: resolves refId → article title +
link to the editor. Falls back to the raw path when refId is
null (e.g. blog index).
- "Search insights (30 days)" tile: split into Most-searched terms
(clickable through to /blog?q=…) and Searches with no results
(content-gap list). Both surface a non-scary "no data yet" empty
state.
Per-article sparkline
---------------------
- Article edit page loads a 30-day series for /{locale}/blog/{slug}
across every supported locale, merges by date, renders a tiny SVG
sparkline + 30-day total. Hidden when total = 0 so a fresh article
doesn't show a flatline.
Cloudflare Web Analytics (optional)
-----------------------------------
- /cms/settings gets a "Cloudflare Web Analytics token" field.
- When set AND data.consent.analytics, the (www) layout injects the
official beacon. Off by default. The first-party D1 counter runs
regardless of this setting.
Also includes a small svelte-check-only typing workaround on
/cms/blocks for the cms_blocks_help paraglide message (build was
already green; the cast just silences the per-message-types noise).
i18n: 9 new keys (EN + TH).
Closes #33
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
1 parent d653e42 commit 5fec46d
22 files changed
Lines changed: 2600 additions & 13 deletions
File tree
- docs
- drizzle
- meta
- messages
- src
- lib
- components/analytics
- server
- analytics
- content
- routes
- (cms)/cms
- articles/[id]
- dashboard
- settings
- (www)
- [locale]
- [...slug]
- blog
- [slug]
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
282 | 282 | | |
283 | 283 | | |
284 | 284 | | |
285 | | - | |
| 285 | + | |
286 | 286 | | |
287 | 287 | | |
288 | 288 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
208 | 208 | | |
209 | 209 | | |
210 | 210 | | |
211 | | - | |
| 211 | + | |
212 | 212 | | |
213 | | - | |
| 213 | + | |
214 | 214 | | |
215 | | - | |
| 215 | + | |
216 | 216 | | |
217 | | - | |
| 217 | + | |
218 | 218 | | |
219 | | - | |
| 219 | + | |
| 220 | + | |
| 221 | + | |
| 222 | + | |
| 223 | + | |
| 224 | + | |
| 225 | + | |
| 226 | + | |
| 227 | + | |
220 | 228 | | |
221 | 229 | | |
222 | 230 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
0 commit comments