ghost 6.0.3 → 6.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/components/tryghost-i18n-6.0.5.tgz +0 -0
  2. package/core/built/admin/assets/admin-x-activitypub/admin-x-activitypub.js +1 -1
  3. package/core/built/admin/assets/admin-x-activitypub/{index-DzkhcDJy.mjs → index-DBxGycCG.mjs} +9263 -9215
  4. package/core/built/admin/assets/admin-x-activitypub/{index-BGpQ-bIj.mjs → index-Db9aLAi4.mjs} +2 -2
  5. package/core/built/admin/assets/admin-x-settings/{CodeEditorView-CFP3ZKm2.mjs → CodeEditorView-B4W7CQcA.mjs} +2 -2
  6. package/core/built/admin/assets/admin-x-settings/admin-x-settings.js +1 -1
  7. package/core/built/admin/assets/admin-x-settings/{index-qJnVka7B.mjs → index-CuwMM9FM.mjs} +6603 -6565
  8. package/core/built/admin/assets/admin-x-settings/{index-CNPz6XrY.mjs → index-jv9DN3ZO.mjs} +2 -2
  9. package/core/built/admin/assets/admin-x-settings/{modals-CZ910p4i.mjs → modals-CUGEPPYA.mjs} +6 -6
  10. package/core/built/admin/assets/{chunk.397.f965bec6bb556d2750de.js → chunk.397.1904882a4a78e2922f07.js} +2 -2
  11. package/core/built/admin/assets/{chunk.524.9820d2bf73b62bb7dba9.js → chunk.524.0e2bff9b664f925d7af7.js} +6 -6
  12. package/core/built/admin/assets/{chunk.582.0ed287001a73163b5634.js → chunk.582.a8f6c436bbec6f9ba678.js} +9 -9
  13. package/core/built/admin/assets/{ghost-dfaf1657ee466f4f397c27bbae0759bc.js → ghost-2b02de85a93ec9a5623180b373cece35.js} +10 -10
  14. package/core/built/admin/assets/{ghost-a0676bad4687584c2c1b3b6b8bed5b31.css → ghost-2c537ee89c36199137eafc1768fd7de8.css} +1 -1
  15. package/core/built/admin/assets/{ghost-dark-65295e8112b12fc9b301111e1c446c51.css → ghost-dark-ad23efc1d702e3643a8ee90d089df5d6.css} +1 -1
  16. package/core/built/admin/assets/posts/posts.js +19784 -19750
  17. package/core/built/admin/assets/stats/stats.js +20512 -20477
  18. package/core/built/admin/index.html +5 -5
  19. package/core/frontend/helpers/facebook_url.js +3 -0
  20. package/core/frontend/helpers/ghost_head.js +2 -1
  21. package/core/frontend/helpers/twitter_url.js +3 -0
  22. package/core/frontend/public/ghost-stats.min.js +1 -1
  23. package/core/frontend/public/member-attribution.min.js +1 -1
  24. package/core/frontend/src/ghost-stats/ghost-stats.js +1 -8
  25. package/core/frontend/src/member-attribution/member-attribution.js +4 -2
  26. package/core/frontend/web/middleware/error-handler.js +45 -7
  27. package/core/server/data/tinybird/README.md +38 -10
  28. package/core/server/services/koenig/node-renderers/header-v2-renderer.js +74 -4
  29. package/core/shared/config/defaults.json +2 -2
  30. package/core/shared/labs.js +2 -1
  31. package/ghost.js +0 -1
  32. package/package.json +9 -9
  33. package/tsconfig.tsbuildinfo +1 -1
  34. package/yarn.lock +909 -717
  35. package/components/tryghost-i18n-6.0.3.tgz +0 -0
  36. package/core/server/data/tinybird/DOCS.md +0 -423
  37. /package/core/built/admin/assets/{chunk.397.f965bec6bb556d2750de.js.LICENSE.txt → chunk.397.1904882a4a78e2922f07.js.LICENSE.txt} +0 -0
Binary file
@@ -1,423 +0,0 @@
1
- # Ghost Traffic Analytics Data Model Explainer
2
-
3
- This document explains the comprehensive data architecture behind Ghost's traffic analytics features, covering both the MySQL database schema and Tinybird event streams, their relationships, and how they work together to provide real-time analytics.
4
-
5
- ## Table of Contents
6
-
7
- 1. [Overview](#overview)
8
- 2. [MySQL Schema (Ghost Database)](#mysql-schema-ghost-database)
9
- 3. [Tinybird Event Schema](#tinybird-event-schema)
10
- 4. [Data Flow & Relationships](#data-flow--relationships)
11
- 5. [API Endpoints](#api-endpoints)
12
- 6. [Mock Data Considerations](#mock-data-considerations)
13
-
14
- ## Overview
15
- Ghost's traffic analytics system has two datasources: MySQL and Tinybird
16
-
17
- # Ghost Analytics Architecture
18
-
19
- ```mermaid
20
- graph TD
21
- A[Ghost Admin<br/>Frontend] --> B[Ghost<br/>Main Server]
22
- A --> C[Tinybird<br/>Analytics DB]
23
- B --> D[MySQL<br/>Database]
24
- B --> C
25
- ```
26
-
27
- - **MySQL Database**: Stores content, members, newsletters, and member attribution events
28
- - **Tinybird**: Real-time analytics database that processes page views and visitor sessions
29
- - **Cross-system Integration**: UUID-based relationships between Ghost entities and Tinybird events
30
-
31
- The system tracks:
32
- - **Web Traffic**: Page views, sessions, referrers, device info (via Tinybird)
33
- - **Member Growth**: Signups, conversions, attribution to content (via MySQL)
34
- - **Newsletter Performance**: Sends, opens, clicks, revenue attribution (via MySQL + Tinybird)
35
- - **Content Performance**: Views, member conversions, revenue impact (hybrid)
36
-
37
- ## MySQL Schema (Ghost Database)
38
-
39
- ### Core Content Tables
40
-
41
- #### `posts`
42
- Primary content table storing all posts and pages.
43
-
44
- **Key fields for analytics:**
45
- - `id` (string, 24 chars) - Primary key, used in attribution events
46
- - `uuid` (string, 36 chars) - UUID for Tinybird correlation
47
- - `title` - Content title
48
- - `slug` - URL slug
49
- - `type` - 'post' or 'page'
50
- - `status` - 'published', 'draft', 'scheduled', 'sent'
51
- - `published_at` - Publication timestamp
52
- - `newsletter_id` - Associated newsletter (if sent via email)
53
-
54
- #### `posts_meta`
55
- Extended metadata for posts.
56
-
57
- **Relevant fields:**
58
- - `post_id` - Foreign key to posts.id
59
- - `meta_title`, `meta_description` - SEO metadata
60
- - `email_subject` - Newsletter subject line
61
- - `email_only` - Whether post is email-exclusive
62
-
63
- ### Member & Subscription Tables
64
-
65
- #### `members`
66
- Core member accounts.
67
-
68
- **Key fields:**
69
- - `id` (string, 24 chars) - Primary key
70
- - `uuid` (string, 36 chars) - UUID for Tinybird correlation
71
- - `email` - Member email address
72
- - `status` - 'free', 'paid', 'comped'
73
- - `created_at` - Signup timestamp
74
-
75
- #### `newsletters`
76
- Newsletters are series of emails. Sites can have multiple different newsletters, each with its own name & branding. Sites may have a "Daily newsletter" and a "Weekly roundup" newsletter, for example.
77
-
78
- **Key fields:**
79
- - `id` (string, 24 chars) - Primary key
80
- - `name` - Newsletter name
81
- - `status` - 'active', 'archived'
82
-
83
- #### `products` (tiers)
84
- Subscription tiers/products that members can sign up for with Stripe
85
-
86
- **Key fields:**
87
- - `id` (string, 24 chars) - Primary key
88
- - `name` - Tier name
89
- - `type` - 'free', 'paid'
90
- - `monthly_price`, `yearly_price` - Pricing
91
-
92
- ### Attribution & Event Tables
93
-
94
- #### `members_created_events`
95
- Tracks member signups and their attribution.
96
-
97
- **Key fields:**
98
- - `id` - Primary key
99
- - `member_id` - Foreign key to members.id
100
- - `created_at` - Signup timestamp
101
- - `attribution_id` - ID of attributed resource (post.id, etc.)
102
- - `attribution_type` - 'post', 'page', 'url', 'tag', 'author'
103
- - `attribution_url` - Full URL that drove signup
104
- - `referrer_source` - Domain that referred the member
105
- - `referrer_medium` - Marketing medium
106
- - `referrer_url` - Full referrer URL
107
- - `source` - 'member', 'import', 'system', 'api', 'admin'
108
-
109
- #### `members_subscription_created_events`
110
- Tracks paid subscription starts and their attribution.
111
-
112
- **Key fields:**
113
- - `id` - Primary key
114
- - `member_id` - Foreign key to members.id
115
- - `subscription_id` - Associated subscription
116
- - `created_at` - Conversion timestamp
117
- - `attribution_id` - ID of attributed resource
118
- - `attribution_type` - 'post', 'page', 'url', 'tag', 'author'
119
- - `attribution_url` - URL that drove conversion
120
- - `referrer_source` - Domain that drove conversion
121
- - `referrer_medium` - Marketing medium
122
- - `referrer_url` - Full referrer URL
123
-
124
- #### `members_paid_subscription_events`
125
- Tracks MRR changes from subscription events.
126
-
127
- **Key fields:**
128
- - `member_id` - Foreign key to members.id
129
- - `subscription_id` - Associated subscription
130
- - `mrr_delta` - Monthly recurring revenue change
131
- - `created_at` - Event timestamp
132
-
133
- ### Email & Newsletter Tables
134
-
135
- #### `emails`
136
- When a post is sent as an email, a row is added to this table
137
-
138
- **Key fields:**
139
- - `id` - Primary key
140
- - `post_id` - Associated post (unique)
141
- - `newsletter_id` - Associated newsletter
142
- - `status` - 'pending', 'submitted', 'failed'
143
- - `email_count` - Total recipients
144
- - `delivered_count` - Successfully delivered
145
- - `opened_count` - Total opens
146
- - `failed_count` - Failed deliveries
147
- - `submitted_at` - Send timestamp
148
-
149
- #### `email_recipients`
150
- A row for every member who received a particular email. Tracks which members received each email, and when it was delivered, opened, failed, etc.
151
-
152
- **Key fields:**
153
- - `email_id` - Foreign key to emails.id
154
- - `member_id` - Foreign key to members.id
155
- - `member_email` - Recipient email
156
- - `delivered_at` - Delivery timestamp
157
- - `opened_at` - Open timestamp
158
- - `failed_at` - Failure timestamp
159
-
160
- #### `redirects`
161
- All links in an email are replaced with tracking links to Ghost so we can track clicks in emails
162
-
163
- **Key fields:**
164
- - `id` - Primary key
165
- - `from` - Short redirect URL
166
- - `to` - Destination URL
167
- - `post_id` - Associated post (if applicable)
168
-
169
- #### `members_click_events`
170
- Email click tracking - each time a member clicks a link in an email
171
-
172
- **Key fields:**
173
- - `member_id` - Foreign key to members.id
174
- - `redirect_id` - Foreign key to redirects.id
175
- - `created_at` - Click timestamp
176
-
177
- ### Newsletter Subscription Tables
178
-
179
- #### `members_newsletters`
180
- Many-to-many relationship for newsletter subscriptions. Sites can have multiple newsletters, members can be subscribed to 0 or more newsletters
181
-
182
- **Key fields:**
183
- - `member_id` - Foreign key to members.id
184
- - `newsletter_id` - Foreign key to newsletters.id
185
-
186
- #### `members_subscribe_events`
187
- Newsletter subscription/unsubscription events. Members can choose to subscribe/unsubscribe to any of a site's newsletters at any time
188
-
189
- **Key fields:**
190
- - `member_id` - Foreign key to members.id
191
- - `newsletter_id` - Foreign key to newsletters.id
192
- - `subscribed` - true/false for subscribe/unsubscribe
193
- - `created_at` - Event timestamp
194
- - `source` - Event source
195
-
196
- ## Tinybird Event Schema
197
-
198
- ### Analytics Events Datasource
199
-
200
- #### `analytics_events`
201
- Raw page view events streamed from the frontend.
202
-
203
- **Schema:**
204
- ```sql
205
- `timestamp` DateTime
206
- `session_id` String
207
- `action` LowCardinality(String) -- Usually 'page_hit'
208
- `version` LowCardinality(String) -- Event schema version
209
- `payload` JSON(max_dynamic_types=4, max_dynamic_paths=32)
210
- `site_uuid` LowCardinality(String) -- Extracted from payload
211
- ```
212
-
213
- **Payload Structure:**
214
- ```json
215
- {
216
- "site_uuid": "string",
217
- "member_uuid": "string|undefined", // member.uuid in MySQL
218
- "member_status": "free|paid|comped|undefined", // member.status in MySQL
219
- "post_uuid": "string|undefined", // post.uuid in MySQL
220
- "post_type": "post|page|empty", //post.type in MySQL
221
- "user-agent": "string",
222
- "locale": "string",
223
- "location": "string", // Country code
224
- "referrer": "string", // used for member attribution
225
- "pathname": "string",
226
- "href": "string", // Full URL
227
- }
228
- ```
229
-
230
- ### Materialized View: _mv_hits
231
-
232
- #### `_mv_hits`
233
- Processed and structured page view data.
234
-
235
- **Schema:**
236
- ```sql
237
- `site_uuid` LowCardinality(String)
238
- `timestamp` DateTime
239
- `action` LowCardinality(String)
240
- `version` LowCardinality(String)
241
- `session_id` String
242
- `member_uuid` String
243
- `member_status` String
244
- `post_uuid` String
245
- `post_type` String
246
- `location` String -- Country code
247
- `source` String -- Referrer domain
248
- `pathname` String -- URL path
249
- `href` String -- Full URL
250
- `device` String -- Device type
251
- `os` String -- Operating system
252
- `browser` String -- Browser name
253
- ```
254
-
255
- ### Tinybird Endpoints (Pipes)
256
-
257
- - `api_active_visitors` - Real-time visitor counts
258
- - `api_kpis` - Site-wide KPI metrics
259
- - `api_post_visitor_counts` - Visitor counts by post UUID
260
- - `api_top_browsers` - Top browsers by visits
261
- - `api_top_devices` - Top devices by visits
262
- - `api_top_locations` - Top countries by visits
263
- - `api_top_os` - Top operating systems by visits
264
- - `api_top_pages` - Top pages by visits
265
- - `api_top_sources` - Top referrer sources by visits
266
-
267
- ## Data Flow & Relationships
268
-
269
- ### 1. Page View Tracking
270
-
271
- ```
272
- Frontend → Tinybird analytics_events → _mv_hits materialized view
273
- ```
274
-
275
- **Key Relationships:**
276
- - `payload.site_uuid` identifies the Ghost site
277
- - `payload.post_uuid` correlates to `posts.uuid` in MySQL
278
- - `payload.member_uuid` correlates to `members.uuid` in MySQL
279
-
280
- ### 2. Member Attribution Flow
281
-
282
- ```
283
- Member Signup → members_created_events (with attribution_*)
284
- Member Conversion → members_subscription_created_events (with attribution_*)
285
- ```
286
-
287
- **Attribution Logic:**
288
- - `attribution_id` contains `posts.id` when attributed to specific content
289
- - `attribution_type` categorizes the attribution source
290
- - `attribution_url` stores the full URL that drove the action
291
- - `referrer_source` tracks the referring domain
292
-
293
- ### 3. Newsletter Performance Flow
294
-
295
- ```
296
- Post Creation → Email Send (emails table) → Individual Recipients (email_recipients)
297
- Click Tracking → redirects → members_click_events
298
- ```
299
-
300
- ### 4. Cross-System Data Correlation
301
-
302
- **Post Performance Analysis:**
303
- 1. Get page views from Tinybird using `posts.uuid`
304
- 2. Get member attribution from MySQL using `posts.id`
305
- 3. Get email performance from MySQL using `posts.id`
306
- 4. Combine for comprehensive post analytics
307
-
308
- **Member Journey Tracking:**
309
- 1. Tinybird tracks anonymous page views
310
- 2. MySQL tracks member signup with attribution
311
- 3. MySQL tracks paid conversion with attribution
312
- 4. Combined view shows complete funnel
313
-
314
- ### Core Stats Endpoints
315
-
316
- ```javascript
317
- // Member growth
318
- GET /stats/member_count
319
- GET /stats/mrr
320
- GET /stats/subscriptions
321
-
322
- // Content performance
323
- GET /stats/top-posts // Attribution-based rankings
324
- GET /stats/top-posts-views // View-based rankings (Tinybird)
325
- GET /stats/top-content // Combined content performance
326
-
327
- // Post-specific analytics
328
- GET /stats/posts/:id/stats // Individual post performance
329
- GET /stats/posts/:id/growth // Member attribution for post
330
- GET /stats/posts/:id/top-referrers // Referrer breakdown for post
331
-
332
- // Newsletter analytics
333
- GET /stats/newsletter-stats // Full newsletter performance
334
- GET /stats/newsletter-basic-stats // Basic stats (faster)
335
- GET /stats/newsletter-click-stats // Click-through data
336
- GET /stats/subscriber-count // Subscriber growth
337
-
338
- // Traffic sources
339
- GET /stats/referrers // Historical referrer data
340
- GET /stats/top-sources-growth // Source performance over time
341
-
342
- // Batch endpoints
343
- POST /stats/posts-visitor-counts // Bulk visitor counts (Tinybird)
344
- POST /stats/posts-member-counts // Bulk member attribution (MySQL)
345
- ```
346
-
347
- ### Request/Response Patterns
348
-
349
- Most endpoints support:
350
- - `date_from` / `date_to` - Date range filtering
351
- - `limit` - Result count limiting
352
- - `order` - Sort field and direction
353
- - `newsletter_id` - Newsletter-specific filtering
354
-
355
- Response format:
356
- ```json
357
- {
358
- "data": [...],
359
- "meta": {
360
- "totals": {...}
361
- }
362
- }
363
- ```
364
-
365
- ## Mock Data Considerations
366
-
367
- ### Data Volume & Relationships
368
-
369
- For realistic testing, mock data should maintain proper ratios:
370
-
371
- **Content:**
372
- - ~100-500 posts across 6-month period
373
- - ~10-20 pages (about, contact, etc.)
374
- - 1-3 newsletters
375
-
376
- **Members:**
377
- - ~1000-5000 total members
378
- - ~70% free, ~25% paid, ~5% comped
379
- - ~50-100 new signups per month
380
- - ~10-20% conversion rate from free to paid
381
-
382
- **Page Views (Tinybird):**
383
- - ~10-50 views per post (varies widely)
384
- - ~100-500 daily total page views
385
- - ~60% direct/type-in, ~25% search, ~10% social, ~5% other referrers
386
-
387
- **Email Performance:**
388
- - ~50-80% delivery rate
389
- - ~20-40% open rate
390
- - ~2-5% click rate
391
- - Newsletter sends 1-4x per month
392
-
393
- ### Key Constraints
394
-
395
- **UUID Relationships:**
396
- - `posts.uuid` must match Tinybird `post_uuid` values
397
- - `members.uuid` must match Tinybird `member_uuid` values
398
- - UUIDs should be valid v4 format
399
-
400
- **Attribution Data:**
401
- - `attribution_id` must reference valid `posts.id`
402
- - `attribution_url` should be realistic Ghost URLs
403
- - `referrer_source` should be realistic domains
404
-
405
- **Temporal Consistency:**
406
- - Member created events before subscription events
407
- - Posts published before attribution events
408
- - Email sends after post publication
409
- - Page views distributed realistically over time
410
-
411
- ### Performance Considerations
412
-
413
- **Indexes:**
414
- - Date-based queries need temporal indexing
415
- - Attribution queries need member_id + attribution_id indexes
416
- - Cross-table joins need proper foreign key indexes
417
-
418
- **Query Patterns:**
419
- - Most analytics queries filter by date ranges
420
- - Post-specific queries join on post IDs/UUIDs
421
- - Member attribution queries are complex with multiple CTEs
422
-
423
- This data model enables comprehensive traffic analytics while maintaining performance through strategic use of both MySQL and Tinybird for their respective strengths.