Repository navigation
Conversation
`PUT /api/projects/:id/messaging_templates/by_key/:key/` creates or updates the template with that key from HTML kept in a repository. The first upload makes it transactional with the project's default verified sender; later uploads publish changed content at once, answer `unchanged` for the same content and, with `if_not_superseded`, `superseded` for content a newer upload replaced. Code sends under a key move to the template's workflow once an upload claims the key. The upload sits behind `workflows-email-from-code`, keeps the PSAK bypass and workflow access checks of the send route, gets its own rate limits, and reports a usage event. The MCP tool `workflows-upload-email-template` calls it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ode sends Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…plate-uploads # Conflicts: # products/messaging/frontend/generated/api.schemas.ts # products/messaging/frontend/generated/api.zod.ts # services/mcp/src/api/generated.ts # services/mcp/src/generated/email_templates/api.ts # services/mcp/tests/unit/__snapshots__/tool-schemas/workflows-send-email.json
…ode sends paused An upload counts as unchanged only when the template's workflow still sends the uploaded content, so a re-upload repairs a workflow edited elsewhere. A first upload under a key whose code sends are paused is refused, because taking the key over would start those sends again. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A code send under the key of a template no upload claimed stays on the key's own workflow, and a test now pins that. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
An upload compared only the email's content with the workflow's, so a workflow edited to send elsewhere still reported "unchanged". It now compares the workflow's whole email step with the one the upload writes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… its content Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
🤖 CI report
|
| File | Size | Δ vs base |
|---|---|---|
posthog-app/src/lib/components/CommandKSearch/CommandKSearch.js |
63.0 KiB | 🟢 -1.2 KiB (-1.9%) |
Posted automatically by build-bundle-size-report · uncompressed bytes from dist-report
✅ Eager graph — within budget
How much code each root ships on the eager path — downloaded and parsed before the surface is interactive. Measured from the esbuild output chunks (post-tree-shake, static imports only); lazy import() / React.lazy chunks are not counted.
| Root | Eager (shipped) | Δ vs base | Budget |
|---|---|---|---|
entry (logged-out pages, app bootstrap)src/index.tsx |
1.03 MiB · 25 files | no change | █████████░ 89.6% of 1.14 MiB |
logged-out boot: index + App + bootApp (preloaded by every page, including /login)src/index.tsx + src/scenes/App.tsx + src/scenes/bootApp.ts |
3.00 MiB · 623 files | 🔺 +1.2 KiB (+0.0%) | ██████████ 99.0% of 3.03 MiB |
authenticated shell (every logged-in page)src/scenes/AuthenticatedShell.tsx |
3.82 MiB · 1,222 files | 🔺 +1.2 KiB (+0.0%) | ██████████ 95.4% of 4.01 MiB |
dashboard scenesrc/scenes/dashboard/Dashboard.tsx |
7.58 MiB · 2,930 files | 🔺 +1.2 KiB (+0.0%) | ████████░░ 77.1% of 9.84 MiB |
today home pathsrc/scenes/AuthenticatedShell.tsx + src/scenes/project-homepage/ProjectHomepage.tsx + src/scenes/project-homepage/today/TodayHome.tsx |
4.69 MiB · 1,749 files | 🔺 +1.2 KiB (+0.0%) | ██████████ 95.0% of 4.93 MiB |
AI-first home pathsrc/scenes/AuthenticatedShell.tsx + src/scenes/project-homepage/ProjectHomepage.tsx + src/scenes/project-homepage/ai-first/AiFirstHomepage.tsx |
5.98 MiB · 2,256 files | 🔺 +1.2 KiB (+0.0%) | ██████████ 95.3% of 6.27 MiB |
events scenesrc/scenes/activity/explore/EventsScene.tsx |
6.66 MiB · 2,508 files | 🔺 +1.2 KiB (+0.0%) | ███████░░░ 70.8% of 9.41 MiB |
web analytics scenesrc/scenes/web-analytics/WebAnalyticsScene.tsx |
7.68 MiB · 2,870 files | 🔺 +1.2 KiB (+0.0%) | ███████░░░ 73.2% of 10.49 MiB |
replay detail scenesrc/scenes/session-recordings/detail/SessionRecordingDetail.tsx |
6.89 MiB · 2,599 files | 🔺 +709 B (+0.0%) | ████████░░ 84.8% of 8.13 MiB |
🟢 node_modules/monaco-editor/ stays out of src/index.tsx
🟢 products/product_analytics/frontend/insights/activityDescriptions stays out of src/index.tsx
🟢 node_modules/@posthog/brand/dist/generated/hoggies/svg/ stays out of src/index.tsx
🟢 node_modules/@posthog/brand/dist/generated/hoggies/components/ stays out of src/index.tsx
🟢 node_modules/monaco-editor/ stays out of src/index.tsx + src/scenes/App.tsx + src/scenes/bootApp.ts
🟢 src/layout/navigation-3000/navigationLogic.tsx stays out of src/index.tsx + src/scenes/App.tsx + src/scenes/bootApp.ts
🟢 src/scenes/dashboard/dashboardLogic.tsx stays out of src/index.tsx + src/scenes/App.tsx + src/scenes/bootApp.ts
🟢 src/lib/lemon-ui/LemonMarkdown/ stays out of src/index.tsx + src/scenes/App.tsx + src/scenes/bootApp.ts
🟢 src/lib/components/RichContentEditor/ stays out of src/index.tsx + src/scenes/App.tsx + src/scenes/bootApp.ts
🟢 src/lib/components/CodeSnippet/ stays out of src/index.tsx + src/scenes/App.tsx + src/scenes/bootApp.ts
🟢 src/taxonomy/core-filter-definitions-by-group.json stays out of src/index.tsx + src/scenes/App.tsx + src/scenes/bootApp.ts
🟢 node_modules/zod/ stays out of src/index.tsx + src/scenes/App.tsx + src/scenes/bootApp.ts
🟢 src/lib/logic/billing/billingLogic.tsx stays out of src/index.tsx + src/scenes/App.tsx + src/scenes/bootApp.ts
🟢 src/lib/components/ProductEmptyState/productSetupPreloadLogic.ts stays out of src/index.tsx + src/scenes/App.tsx + src/scenes/bootApp.ts
🟢 node_modules/kea-test-utils/ stays out of src/index.tsx + src/scenes/App.tsx + src/scenes/bootApp.ts
🟢 node_modules/monaco-editor/ stays out of src/scenes/AuthenticatedShell.tsx
🟢 products/product_analytics/frontend/insights/activityDescriptions stays out of src/scenes/AuthenticatedShell.tsx
🟢 node_modules/kea-test-utils/ stays out of src/scenes/AuthenticatedShell.tsx
🟢 products/dashboards/frontend/widgets/previews/ stays out of src/scenes/AuthenticatedShell.tsx
🟢 src/scenes/session-recordings/player/sessionRecordingPlayerLogic.ts stays out of src/scenes/AuthenticatedShell.tsx
🟢 src/layout/panel-layout/ProjectTree/menus/SessionReplayMenuItems.tsx stays out of src/scenes/AuthenticatedShell.tsx
🟢 src/taxonomy/core-filter-definitions-by-group.json stays out of src/scenes/AuthenticatedShell.tsx
🟢 src/layout/navigation/projectNoticeLogic.tsx stays out of src/scenes/AuthenticatedShell.tsx
🟢 src/layout/navigation/ImpersonationNotice/ImpersonationNotice.tsx stays out of src/scenes/AuthenticatedShell.tsx
🟢 src/scenes/cohorts/cohortSavedToast.ts stays out of src/scenes/AuthenticatedShell.tsx
🟢 products/wizard/frontend/runs/WizardRunDetailsDrawer.tsx stays out of src/scenes/AuthenticatedShell.tsx
🟢 src/layout/today/TodayShell.tsx stays out of src/scenes/AuthenticatedShell.tsx
🟢 src/layout/today/TodayContextPanelFloating.tsx stays out of src/scenes/AuthenticatedShell.tsx
🟢 src/layout/today/TodaySidePanel.tsx stays out of src/scenes/AuthenticatedShell.tsx
🟢 src/layout/today/TodayTopBar.tsx stays out of src/scenes/AuthenticatedShell.tsx
🟢 src/layout/today/todayRailItems.tsx stays out of src/scenes/AuthenticatedShell.tsx
🟢 products/subscriptions/frontend/components/Subscriptions/exportNudge/exportNudgeLogic.ts stays out of src/scenes/AuthenticatedShell.tsx
🟢 src/scenes/billing/paymentEntryLogic.ts stays out of src/scenes/AuthenticatedShell.tsx
🟢 products/conversations/frontend/components/SidePanel/sidepanelTicketsLogic.ts stays out of src/scenes/AuthenticatedShell.tsx
🟢 node_modules/zod/ stays out of src/scenes/AuthenticatedShell.tsx
🟢 src/scenes/authentication/auth/loginLogic.ts stays out of src/scenes/AuthenticatedShell.tsx
🟢 src/scenes/authentication/shared/passkeyLogic.ts stays out of src/scenes/AuthenticatedShell.tsx
🟢 src/scenes/cohorts/CohortFilters/constants.tsx stays out of src/scenes/AuthenticatedShell.tsx
🟢 products/persons/frontend/logics/personsLogic.tsx stays out of src/scenes/AuthenticatedShell.tsx
🟢 src/scenes/surveys/constants.tsx stays out of src/scenes/AuthenticatedShell.tsx
🟢 node_modules/@tiptap/ stays out of src/scenes/AuthenticatedShell.tsx
🟢 node_modules/prosemirror- stays out of src/scenes/AuthenticatedShell.tsx
🟢 node_modules/re2js/ stays out of src/scenes/AuthenticatedShell.tsx
🟢 node_modules/react-markdown/ stays out of src/scenes/AuthenticatedShell.tsx
🟢 src/lib/components/Command/Command.tsx stays out of src/scenes/AuthenticatedShell.tsx
🟢 packages/quill/packages/ stays out of src/scenes/AuthenticatedShell.tsx
🟢 zod/v4/locales/de.js stays out of src/scenes/AuthenticatedShell.tsx
🟢 node_modules/@posthog/brand/dist/generated/hoggies/svg/ stays out of src/scenes/AuthenticatedShell.tsx
🟢 node_modules/@posthog/brand/dist/generated/hoggies/components/ stays out of src/scenes/AuthenticatedShell.tsx
🟢 packages/quill/packages/quill/dist/ stays out of src/scenes/dashboard/Dashboard.tsx
🟢 node_modules/@tiptap/ stays out of src/scenes/dashboard/Dashboard.tsx
🟢 node_modules/prosemirror- stays out of src/scenes/dashboard/Dashboard.tsx
🟢 node_modules/marked/ stays out of src/scenes/dashboard/Dashboard.tsx
🟢 node_modules/frimousse/ stays out of src/scenes/dashboard/Dashboard.tsx
🟢 src/scenes/session-recordings/playlist/SessionRecordingsPlaylist.tsx stays out of src/scenes/dashboard/Dashboard.tsx
🟢 src/scenes/web-analytics/tiles/WebAnalyticsTile.tsx stays out of src/scenes/dashboard/Dashboard.tsx
🟢 src/queries/validators.js stays out of src/scenes/dashboard/Dashboard.tsx
🟢 src/queries/web-analytics-validators.js stays out of src/scenes/dashboard/Dashboard.tsx
🟢 node_modules/re2js/ stays out of src/scenes/dashboard/Dashboard.tsx
🟢 node_modules/kea-test-utils/ stays out of src/scenes/dashboard/Dashboard.tsx
🟢 src/scenes/debug/HogDebug.tsx stays out of src/scenes/dashboard/Dashboard.tsx
🟢 src/queries/QueryEditor/QueryEditor.tsx stays out of src/scenes/dashboard/Dashboard.tsx
🟢 packages/quill/packages/quill/dist/ stays out of src/scenes/AuthenticatedShell.tsx + src/scenes/project-homepage/ProjectHomepage.tsx + src/scenes/project-homepage/today/TodayHome.tsx
🟢 src/scenes/project-homepage/ai-first/AiFirstHomepage.tsx stays out of src/scenes/AuthenticatedShell.tsx + src/scenes/project-homepage/ProjectHomepage.tsx + src/scenes/project-homepage/today/TodayHome.tsx
🟢 src/scenes/project-homepage/today/TodayReportPage.tsx stays out of src/scenes/AuthenticatedShell.tsx + src/scenes/project-homepage/ProjectHomepage.tsx + src/scenes/project-homepage/today/TodayHome.tsx
🟢 src/queries/Query/Query.tsx stays out of src/scenes/AuthenticatedShell.tsx + src/scenes/project-homepage/ProjectHomepage.tsx + src/scenes/project-homepage/today/TodayHome.tsx
🟢 packages/quill/packages/charts/ stays out of src/scenes/AuthenticatedShell.tsx + src/scenes/project-homepage/ProjectHomepage.tsx + src/scenes/project-homepage/today/TodayHome.tsx
🟢 packages/quill/packages/quill/dist/ stays out of src/scenes/AuthenticatedShell.tsx + src/scenes/project-homepage/ProjectHomepage.tsx + src/scenes/project-homepage/ai-first/AiFirstHomepage.tsx
🟢 products/posthog_ai/frontend/components/tool/widgets/VisualizationWidget.tsx stays out of src/scenes/AuthenticatedShell.tsx + src/scenes/project-homepage/ProjectHomepage.tsx + src/scenes/project-homepage/ai-first/AiFirstHomepage.tsx
🟢 products/posthog_ai/frontend/components/tool/widgets/RecordingsWidget.tsx stays out of src/scenes/AuthenticatedShell.tsx + src/scenes/project-homepage/ProjectHomepage.tsx + src/scenes/project-homepage/ai-first/AiFirstHomepage.tsx
🟢 src/queries/Query/Query.tsx stays out of src/scenes/AuthenticatedShell.tsx + src/scenes/project-homepage/ProjectHomepage.tsx + src/scenes/project-homepage/ai-first/AiFirstHomepage.tsx
🟢 products/posthog_ai/frontend/api/primitives.ts stays out of src/scenes/AuthenticatedShell.tsx + src/scenes/project-homepage/ProjectHomepage.tsx + src/scenes/project-homepage/ai-first/AiFirstHomepage.tsx
🟢 src/scenes/notebooks/Notebook/notebookLogic.ts stays out of src/scenes/AuthenticatedShell.tsx + src/scenes/project-homepage/ProjectHomepage.tsx + src/scenes/project-homepage/ai-first/AiFirstHomepage.tsx
🟢 packages/quill/packages/quill/dist/ stays out of src/scenes/activity/explore/EventsScene.tsx
🟢 node_modules/@tiptap/ stays out of src/scenes/activity/explore/EventsScene.tsx
🟢 node_modules/prosemirror- stays out of src/scenes/activity/explore/EventsScene.tsx
🟢 node_modules/marked/ stays out of src/scenes/activity/explore/EventsScene.tsx
🟢 node_modules/frimousse/ stays out of src/scenes/activity/explore/EventsScene.tsx
🟢 src/scenes/session-recordings/playlist/SessionRecordingsPlaylist.tsx stays out of src/scenes/activity/explore/EventsScene.tsx
🟢 src/scenes/web-analytics/tiles/WebAnalyticsTile.tsx stays out of src/scenes/activity/explore/EventsScene.tsx
🟢 src/queries/validators.js stays out of src/scenes/activity/explore/EventsScene.tsx
🟢 src/queries/web-analytics-validators.js stays out of src/scenes/activity/explore/EventsScene.tsx
🟢 node_modules/re2js/ stays out of src/scenes/activity/explore/EventsScene.tsx
🟢 node_modules/kea-test-utils/ stays out of src/scenes/activity/explore/EventsScene.tsx
🟢 src/queries/nodes/InsightViz/InsightViz.tsx stays out of src/scenes/activity/explore/EventsScene.tsx
🟢 src/queries/nodes/DataVisualization/DataVisualization.tsx stays out of src/scenes/activity/explore/EventsScene.tsx
🟢 src/queries/nodes/WebOverview/WebOverview.tsx stays out of src/scenes/activity/explore/EventsScene.tsx
🟢 src/scenes/debug/HogDebug.tsx stays out of src/scenes/activity/explore/EventsScene.tsx
🟢 src/queries/QueryEditor/QueryEditor.tsx stays out of src/scenes/activity/explore/EventsScene.tsx
🟢 packages/quill/packages/quill/dist/ stays out of src/scenes/web-analytics/WebAnalyticsScene.tsx
🟢 node_modules/@tiptap/ stays out of src/scenes/web-analytics/WebAnalyticsScene.tsx
🟢 node_modules/prosemirror- stays out of src/scenes/web-analytics/WebAnalyticsScene.tsx
🟢 node_modules/marked/ stays out of src/scenes/web-analytics/WebAnalyticsScene.tsx
🟢 node_modules/frimousse/ stays out of src/scenes/web-analytics/WebAnalyticsScene.tsx
🟢 src/scenes/web-analytics/LiveMetricsDashboard/LiveWebAnalyticsMetrics.tsx stays out of src/scenes/web-analytics/WebAnalyticsScene.tsx
🟢 products/product_analytics/frontend/insights/trends/WorldMap/countryVectors.tsx stays out of src/scenes/web-analytics/WebAnalyticsScene.tsx
🟢 src/queries/validators.js stays out of src/scenes/web-analytics/WebAnalyticsScene.tsx
🟢 node_modules/re2js/ stays out of src/scenes/web-analytics/WebAnalyticsScene.tsx
🟢 node_modules/kea-test-utils/ stays out of src/scenes/web-analytics/WebAnalyticsScene.tsx
🟢 src/scenes/debug/HogDebug.tsx stays out of src/scenes/web-analytics/WebAnalyticsScene.tsx
🟢 src/queries/QueryEditor/QueryEditor.tsx stays out of src/scenes/web-analytics/WebAnalyticsScene.tsx
🟢 packages/quill/packages/quill/dist/ stays out of src/scenes/session-recordings/detail/SessionRecordingDetail.tsx
🟢 node_modules/@tiptap/ stays out of src/scenes/session-recordings/detail/SessionRecordingDetail.tsx
🟢 node_modules/prosemirror- stays out of src/scenes/session-recordings/detail/SessionRecordingDetail.tsx
🟢 node_modules/marked/ stays out of src/scenes/session-recordings/detail/SessionRecordingDetail.tsx
🟢 src/scenes/settings/SettingsMap.tsx stays out of src/scenes/session-recordings/detail/SessionRecordingDetail.tsx
🟢 @jspm/core/nodelibs/browser/fs stays out of src/scenes/session-recordings/detail/SessionRecordingDetail.tsx
🟢 node_modules/re2js/ stays out of src/scenes/session-recordings/detail/SessionRecordingDetail.tsx
🟢 node_modules/kea-test-utils/ stays out of src/scenes/session-recordings/detail/SessionRecordingDetail.tsx
🟢 node_modules/d3/src/ stays out of src/scenes/session-recordings/detail/SessionRecordingDetail.tsx
Largest files eagerly shipped from src/index.tsx
| Size | File |
|---|---|
| 126.8 KiB | ../node_modules/.pnpm/react-dom@18.3.1_react@18.3.1/node_modules/react-dom/cjs/react-dom.production.min.js |
| 24.6 KiB | ../node_modules/.pnpm/buffer@6.0.3/node_modules/buffer/index.js |
| 6.3 KiB | ../node_modules/.pnpm/react@18.3.1/node_modules/react/cjs/react.production.min.js |
| 4.7 KiB | ../node_modules/.pnpm/@jspm+core@2.1.0/node_modules/@jspm/core/nodelibs/browser/process.js |
| 4.0 KiB | ../node_modules/.pnpm/scheduler@0.23.2/node_modules/scheduler/cjs/scheduler.production.min.js |
| 1.9 KiB | src/lib/utils/bootTiming.ts |
| 1.7 KiB | src/index.tsx |
| 1.7 KiB | ../node_modules/.pnpm/base64-js@1.5.1/node_modules/base64-js/index.js |
| 1.2 KiB | src/RootErrorBoundary.tsx |
| 1.1 KiB | src/lib/utils/deferredAppContext.ts |
Largest files eagerly shipped from src/index.tsx + src/scenes/App.tsx + src/scenes/bootApp.ts
| Size | File |
|---|---|
| 359.8 KiB | ../node_modules/.pnpm/posthog-js@1.447.1_@types+react@18.3.27_react@18.3.1/node_modules/posthog-js/dist/module.mjs |
| 224.1 KiB | ../node_modules/.pnpm/@posthog+icons@0.39.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@posthog/icons/dist/posthog-icons.es.js |
| 126.8 KiB | ../node_modules/.pnpm/react-dom@18.3.1_react@18.3.1/node_modules/react-dom/cjs/react-dom.production.min.js |
| 105.6 KiB | src/products.tsx |
| 87.4 KiB | src/lib/api.ts |
| 68.7 KiB | src/lib/lemon-ui/icons/icons.tsx |
| 41.9 KiB | ../node_modules/.pnpm/@dnd-kit+core@6.0.8_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/core.esm.js |
| 36.4 KiB | ../node_modules/.pnpm/kea@4.0.0-pre.6_patch_hash=139b8d1f1304f9d9da452a9a1244c94ea679dbcb85687d8999563146879fb6f5_react@18.3.1/node_modules/kea/lib/index.cjs.js |
| 28.3 KiB | src/lib/constants.tsx |
| 24.6 KiB | ../node_modules/.pnpm/buffer@6.0.3/node_modules/buffer/index.js |
Largest files eagerly shipped from src/scenes/AuthenticatedShell.tsx
| Size | File |
|---|---|
| 359.8 KiB | ../node_modules/.pnpm/posthog-js@1.447.1_@types+react@18.3.27_react@18.3.1/node_modules/posthog-js/dist/module.mjs |
| 224.1 KiB | ../node_modules/.pnpm/@posthog+icons@0.39.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@posthog/icons/dist/posthog-icons.es.js |
| 126.8 KiB | ../node_modules/.pnpm/react-dom@18.3.1_react@18.3.1/node_modules/react-dom/cjs/react-dom.production.min.js |
| 105.6 KiB | src/products.tsx |
| 87.4 KiB | src/lib/api.ts |
| 68.7 KiB | src/lib/lemon-ui/icons/icons.tsx |
| 41.9 KiB | ../node_modules/.pnpm/@dnd-kit+core@6.0.8_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/core.esm.js |
| 36.4 KiB | ../node_modules/.pnpm/kea@4.0.0-pre.6_patch_hash=139b8d1f1304f9d9da452a9a1244c94ea679dbcb85687d8999563146879fb6f5_react@18.3.1/node_modules/kea/lib/index.cjs.js |
| 32.3 KiB | src/lib/utils/eventUsageLogic.ts |
| 28.3 KiB | src/lib/constants.tsx |
Largest files eagerly shipped from src/scenes/dashboard/Dashboard.tsx
| Size | File |
|---|---|
| 359.8 KiB | ../node_modules/.pnpm/posthog-js@1.447.1_@types+react@18.3.27_react@18.3.1/node_modules/posthog-js/dist/module.mjs |
| 224.1 KiB | ../node_modules/.pnpm/@posthog+icons@0.39.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@posthog/icons/dist/posthog-icons.es.js |
| 126.8 KiB | ../node_modules/.pnpm/react-dom@18.3.1_react@18.3.1/node_modules/react-dom/cjs/react-dom.production.min.js |
| 115.8 KiB | ../node_modules/.pnpm/posthog-js@1.447.1_@types+react@18.3.27_react@18.3.1/node_modules/posthog-js/dist/surveys-preview.js |
| 110.8 KiB | ../packages/quill/packages/primitives/dist/index.js |
| 105.6 KiB | src/products.tsx |
| 96.1 KiB | ../packages/quill/packages/components/dist/index.js |
| 87.4 KiB | src/lib/api.ts |
| 79.0 KiB | src/scenes/dashboard/dashboardLogic.tsx |
| 68.7 KiB | src/lib/lemon-ui/icons/icons.tsx |
Largest files eagerly shipped from src/scenes/AuthenticatedShell.tsx + src/scenes/project-homepage/ProjectHomepage.tsx + src/scenes/project-homepage/today/TodayHome.tsx
| Size | File |
|---|---|
| 359.8 KiB | ../node_modules/.pnpm/posthog-js@1.447.1_@types+react@18.3.27_react@18.3.1/node_modules/posthog-js/dist/module.mjs |
| 224.1 KiB | ../node_modules/.pnpm/@posthog+icons@0.39.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@posthog/icons/dist/posthog-icons.es.js |
| 126.8 KiB | ../node_modules/.pnpm/react-dom@18.3.1_react@18.3.1/node_modules/react-dom/cjs/react-dom.production.min.js |
| 110.8 KiB | ../packages/quill/packages/primitives/dist/index.js |
| 105.6 KiB | src/products.tsx |
| 87.4 KiB | src/lib/api.ts |
| 68.7 KiB | src/lib/lemon-ui/icons/icons.tsx |
| 68.0 KiB | ../products/posthog_ai/frontend/logics/runStreamLogic.ts |
| 41.9 KiB | ../node_modules/.pnpm/@dnd-kit+core@6.0.8_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/core.esm.js |
| 36.4 KiB | ../node_modules/.pnpm/kea@4.0.0-pre.6_patch_hash=139b8d1f1304f9d9da452a9a1244c94ea679dbcb85687d8999563146879fb6f5_react@18.3.1/node_modules/kea/lib/index.cjs.js |
Largest files eagerly shipped from src/scenes/AuthenticatedShell.tsx + src/scenes/project-homepage/ProjectHomepage.tsx + src/scenes/project-homepage/ai-first/AiFirstHomepage.tsx
| Size | File |
|---|---|
| 359.8 KiB | ../node_modules/.pnpm/posthog-js@1.447.1_@types+react@18.3.27_react@18.3.1/node_modules/posthog-js/dist/module.mjs |
| 224.1 KiB | ../node_modules/.pnpm/@posthog+icons@0.39.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@posthog/icons/dist/posthog-icons.es.js |
| 126.8 KiB | ../node_modules/.pnpm/react-dom@18.3.1_react@18.3.1/node_modules/react-dom/cjs/react-dom.production.min.js |
| 110.8 KiB | ../packages/quill/packages/primitives/dist/index.js |
| 105.6 KiB | src/products.tsx |
| 87.4 KiB | src/lib/api.ts |
| 68.7 KiB | src/lib/lemon-ui/icons/icons.tsx |
| 68.0 KiB | ../products/posthog_ai/frontend/logics/runStreamLogic.ts |
| 41.9 KiB | ../node_modules/.pnpm/@dnd-kit+core@6.0.8_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@dnd-kit/core/dist/core.esm.js |
| 41.7 KiB | src/scenes/hog-functions/sub-templates/sub-templates.ts |
Largest files eagerly shipped from src/scenes/activity/explore/EventsScene.tsx
| Size | File |
|---|---|
| 359.8 KiB | ../node_modules/.pnpm/posthog-js@1.447.1_@types+react@18.3.27_react@18.3.1/node_modules/posthog-js/dist/module.mjs |
| 224.1 KiB | ../node_modules/.pnpm/@posthog+icons@0.39.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@posthog/icons/dist/posthog-icons.es.js |
| 126.8 KiB | ../node_modules/.pnpm/react-dom@18.3.1_react@18.3.1/node_modules/react-dom/cjs/react-dom.production.min.js |
| 110.8 KiB | ../packages/quill/packages/primitives/dist/index.js |
| 105.6 KiB | src/products.tsx |
| 96.1 KiB | ../packages/quill/packages/components/dist/index.js |
| 87.4 KiB | src/lib/api.ts |
| 79.0 KiB | src/scenes/dashboard/dashboardLogic.tsx |
| 68.7 KiB | src/lib/lemon-ui/icons/icons.tsx |
| 68.0 KiB | ../products/posthog_ai/frontend/logics/runStreamLogic.ts |
Largest files eagerly shipped from src/scenes/web-analytics/WebAnalyticsScene.tsx
| Size | File |
|---|---|
| 359.8 KiB | ../node_modules/.pnpm/posthog-js@1.447.1_@types+react@18.3.27_react@18.3.1/node_modules/posthog-js/dist/module.mjs |
| 224.1 KiB | ../node_modules/.pnpm/@posthog+icons@0.39.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@posthog/icons/dist/posthog-icons.es.js |
| 126.8 KiB | ../node_modules/.pnpm/react-dom@18.3.1_react@18.3.1/node_modules/react-dom/cjs/react-dom.production.min.js |
| 115.8 KiB | ../node_modules/.pnpm/posthog-js@1.447.1_@types+react@18.3.27_react@18.3.1/node_modules/posthog-js/dist/surveys-preview.js |
| 110.8 KiB | ../packages/quill/packages/primitives/dist/index.js |
| 105.6 KiB | src/products.tsx |
| 96.1 KiB | ../packages/quill/packages/components/dist/index.js |
| 87.4 KiB | src/lib/api.ts |
| 79.0 KiB | src/scenes/dashboard/dashboardLogic.tsx |
| 68.7 KiB | src/lib/lemon-ui/icons/icons.tsx |
Largest files eagerly shipped from src/scenes/session-recordings/detail/SessionRecordingDetail.tsx
| Size | File |
|---|---|
| 359.8 KiB | ../node_modules/.pnpm/posthog-js@1.447.1_@types+react@18.3.27_react@18.3.1/node_modules/posthog-js/dist/module.mjs |
| 321.1 KiB | ../node_modules/.pnpm/posthog-js@1.447.1_@types+react@18.3.27_react@18.3.1/node_modules/posthog-js/dist/rrweb.js |
| 224.1 KiB | ../node_modules/.pnpm/@posthog+icons@0.39.0_react-dom@18.3.1_react@18.3.1__react@18.3.1/node_modules/@posthog/icons/dist/posthog-icons.es.js |
| 126.8 KiB | ../node_modules/.pnpm/react-dom@18.3.1_react@18.3.1/node_modules/react-dom/cjs/react-dom.production.min.js |
| 110.8 KiB | ../packages/quill/packages/primitives/dist/index.js |
| 105.6 KiB | src/products.tsx |
| 96.1 KiB | ../packages/quill/packages/components/dist/index.js |
| 87.4 KiB | src/lib/api.ts |
| 68.7 KiB | src/lib/lemon-ui/icons/icons.tsx |
| 68.0 KiB | ../products/posthog_ai/frontend/logics/runStreamLogic.ts |
Posted automatically by check-eager-graph · sizes are eager output bytes (shipped, post-tree-shake) from the esbuild metafile · part of #32479
✅ Frontend layers — no new upward imports, 0 removed
Static imports from a lower frontend layer into a higher one (layers, lowest first: kernel, shell, query, features). Compared with the base branch, so an import that a PR also adds to layer-baseline.txt still shows here. Sizes are the source bytes on the eager path of every logged-in page.
| Layer | Eager source bytes | Δ vs base |
|---|---|---|
| kernel | 2.97 MiB | 🟢 -184 B (-0.0%) |
| shell | 2.35 MiB | no change |
| query | 56.2 KiB | no change |
| features | 273.6 KiB | no change |
Download the interactive layer graph for this PR.
Posted automatically by check-layers
✅ Toolbar bundle — eager 2.42 MiB within budget
What the toolbar ships to customer pages, measured from the esbuild output (minified, post-tree-shake). The eager set is the entry plus everything statically imported from it — fetched before any feature runs; deferred chunks load lazily. The eager guardrail is 5.72 MiB. Each output file must also stay below 10 MB, where CloudFront stops compressing it. The module boundary is enforced separately by check-toolbar-graph.
| Metric | Size | Δ vs base | Budget |
|---|---|---|---|
| Eager (shipped) entry + static imports |
2.42 MiB · 19 files | 🔺 +1.2 KiB (+0.0%) | ████░░░░░░ 42.3% of 5.72 MiB |
| Deferred (lazy) | 2.61 MiB · 42 files | no change | n/a — loads on demand |
Loader dist/toolbar.js |
1.2 KiB | no change | █░░░░░░░░░ 6.0% of 19.5 KiB |
Largest eagerly-shipped chunks
| Size | File |
|---|---|
| 961.3 KiB | dist/toolbar/toolbar-app-F4WAIZ6W.css |
| 731.7 KiB | dist/toolbar/chunk-chunk-N27OD2N3.js |
| 290.5 KiB | dist/toolbar/chunk-chunk-B4EIGQIG.js |
| 131.8 KiB | dist/toolbar/chunk-chunk-FQJO25M6.js |
| 130.4 KiB | dist/toolbar/chunk-chunk-3F26PAMR.js |
| 75.7 KiB | dist/toolbar/toolbar-app-KS35NDNZ.js |
| 69.0 KiB | dist/toolbar/chunk-chunk-BFAXZMC5.js |
| 33.8 KiB | dist/toolbar/chunk-chunk-43ZVAZS7.js |
| 21.7 KiB | dist/toolbar/chunk-chunk-F6URCRZB.js |
| 6.8 KiB | dist/toolbar/chunk-chunk-RVLGRPCH.js |
Posted automatically by check-toolbar-size · sizes are toolbar output bytes (shipped, post-tree-shake) from the esbuild metafile
✅ Dist folder size — 🔺 +12.8 KiB (+0.0%)
Total size of the built frontend/dist folder (all assets), compared against the base branch.
Total: 985.20 MiB · 🔺 +12.8 KiB (+0.0%)
ℹ️ MCP UI apps size — 35 app(s), 29268.6 KB JS
Built size of each MCP UI app (main.js + styles.css).
| App | JS | CSS |
|---|---|---|
| debug | 848.8 KB | 220.9 KB |
| explain-chart | 1122.9 KB | 220.9 KB |
| action | 771.5 KB | 220.9 KB |
| action-list | 839.8 KB | 220.9 KB |
| cohort | 770.5 KB | 220.9 KB |
| cohort-list | 838.8 KB | 220.9 KB |
| email-template | 770.4 KB | 220.9 KB |
| error-details | 775.4 KB | 220.9 KB |
| error-issue | 772.5 KB | 220.9 KB |
| error-issue-list | 841.0 KB | 220.9 KB |
| experiment | 836.9 KB | 220.9 KB |
| experiment-list | 840.5 KB | 220.9 KB |
| experiment-results | 838.7 KB | 220.9 KB |
| feature-flag | 839.2 KB | 220.9 KB |
| feature-flag-list | 842.9 KB | 220.9 KB |
| feature-flag-testing | 773.8 KB | 220.9 KB |
| inline-scan | 771.0 KB | 220.9 KB |
| insight-actors | 838.3 KB | 220.9 KB |
| llm-costs | 835.6 KB | 220.9 KB |
| session-recording | 772.8 KB | 220.9 KB |
| survey | 772.1 KB | 220.9 KB |
| survey-global-stats | 835.6 KB | 220.9 KB |
| survey-list | 840.5 KB | 220.9 KB |
| survey-stats | 835.6 KB | 220.9 KB |
| trace-span | 770.9 KB | 220.9 KB |
| trace-span-list | 839.7 KB | 220.9 KB |
| vision-observation-list | 838.9 KB | 220.9 KB |
| workflow | 770.9 KB | 220.9 KB |
| workflow-list | 839.1 KB | 220.9 KB |
| workflow-setup-status | 770.6 KB | 220.9 KB |
| query-results | 1094.4 KB | 220.9 KB |
| render-ui | 1198.6 KB | 220.9 KB |
| visual-review-snapshots | 775.4 KB | 220.9 KB |
| workflow-data-suggestions | 773.2 KB | 220.9 KB |
| workflow-sending-rules | 771.9 KB | 220.9 KB |
ℹ️ MCP agent API — agent-facing tool changes
What this PR changes for agents, from the tool schema snapshots and tool definitions.
Tools added (1): workflows-upload-email-template (2,038 chars)
Tools changed (1):
| Tool | Params | Scopes | Annotations | Schema chars |
|---|---|---|---|---|
workflows-send-email-prepare |
2,394 -> 2,551 |
✅ Django migration risk — migration analysis complete
We've analyzed your migrations for potential risks.
Summary: 1 Safe | 0 Needs Review | 0 Blocked
✅ Safe
Brief or no lock, backwards compatible
messaging.0017_messagetemplate_code_managed_fields
└─ #1 ✅ AddField
Adding nullable field requires brief lock
model: messagetemplate, field: content_hash
└─ #2 ✅ AddField
Adding nullable field requires brief lock
model: messagetemplate, field: managed_by
└─ #3 ✅ AddField
Adding nullable field requires brief lock
model: messagetemplate, field: source_path
└─ #4 ✅ AddField
Adding nullable field requires brief lock
model: messagetemplate, field: source_ref
└─ #5 ✅ AddField
Adding nullable field requires brief lock
model: messagetemplate, field: source_repository
└─ #6 ✅ AddField
Adding nullable field requires brief lock
model: messagetemplate, field: superseded_content_hashes
📚 How to Deploy These Changes Safely
AddField:
This operation acquires a brief lock but doesn't rewrite the table.
Deployment uses lock timeouts with automatic retries, so lock contention will cause retries rather than connection pile-up.
Last updated: 2026-11-06 09:20 UTC (ec48ef8)
There was a problem hiding this comment.
PostHog Review · Standard · reviewed 9e0c2ea: 2 Should fix. This pull request is large, so the review ran in 4 parts with less depth than usual.
This is the only automatic review while this pull request is a draft. Comment @posthog review to review new changes sooner. Otherwise, a review of the new changes runs when you mark it ready for review.
See this review and its findings in PostHog Review. Comment @posthog review --deep for a Deep review. A Deep review takes longer and looks deeper than a Standard review.
| sent_email = _email_value(actions or []) | ||
| sender_id = content.from_integration_id or (sent_email.get("from") or {}).get("integrationId") | ||
| return bool(sent_email) and sent_email == _email_value(transactional_email_actions(content, sender_id)) |
There was a problem hiding this comment.
P2 · Compare execution settings when detecting workflow drift
When a workflow edit changes inputs.email.templating but preserves its value, this comparison still returns true. An identical upload then answers unchanged and skips synchronization, leaving Liquid placeholders—including the recipient—incorrectly rendered by HogInputsService. Compare the execution-relevant email step settings as well as its value.
|
|
||
|
|
||
| def _template_an_upload_claimed(team_id: int, key: str) -> MessageTemplate | None: | ||
| return MessageTemplate.objects.filter(team_id=team_id, key=key, deleted=False, managed_by__isnull=False).first() |
There was a problem hiding this comment.
P2 · Restrict the code-send lookup to the identifiers it needs
For code sends using an uploaded template, this replaces an ID-only lookup with a full row fetch, transferring and decoding content and draft_content before _transactional_workflow_id fetches them again. Large HTML and editor designs now add database traffic and JSON parsing to every send. Select only id and transactional_hog_flow_id here.
…load tests Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…l api page Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The template code fields layer now sits on master, so this merge keeps master's code and re-applies only this layer's change: uploading email templates from code by key. Master moved on in a few places this layer touches, and the merge keeps master's shape there: - the code send sender helper is code_send_sender_id - a key's workflow lookup takes the template, not its id - send and make_transactional declare their scopes on the action, so only upload joins the write actions list - make_transactional still drops content for a send-scoped key OpenAPI types, MCP tools and tool snapshots are regenerated. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Patch the workflow reload where master's hog flow model calls it, and expect a key workflow's email step to carry its key when no upload claimed the template that shares it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Moved from Silthus#573.
Part of the code-first rebuild of the email send stack; replaces parts of #118924 (template keys, owners and hashes; upload, lock and adopt).
Problem
Impact
Pays into Grow Workflows through billed
workflows_emailsactions per paying org, once code-managed templates send. In scope: Messaging, transactional email templates. Expected move: up, after the flag turns on.Merge Danger
Warning
🟡 Merge risk: medium · two-way door: a revert removes the upload route; uploaded templates stay as ordinary templates
workflows-email-from-code. This PR adds no migration; feat(messaging): add code-managed fields to message templates #127168 adds the columns.Changes
What a caller can now do
PUT /api/projects/:id/messaging_templates/by_key/{key}/uploads a template kept as an HTML file: name, subject, html, optional text, preheader and source (repository, path, ref).unchanged.if_not_supersededkeeps an older copy of the file from replacing newer content; that answer issuperseded, and nothing changes. The check covers the last 100 different contents the template replaced.unchanged, because it compares content hashes.400 transactional_email_pausedand names the key workflow to resume.why,fix,docs_url).workflows-upload-email-template.How it works
content_hashisv1:plus a SHA-256 of the canonical content, so a client can tell which copy PostHog holds.products/messaging/backend/services/.Mechanical: the regenerated OpenAPI, frontend and MCP types and the tool snapshots.
How did you test this code?
Test seams: the upload route through the DRF client (
test_template_upload.py), the code send route next to it (test_transactional_email.py), and the hash (test_content_hash.py, in #127168).Test rationale:
if_not_superseded.test_an_upload_repairs_what_no_longer_matches_the_uploaded_content: a workflow whose body, recipient or sender someone edited outside the template, which an unchanged upload leaves as it is.test_refuses_a_first_upload_under_a_key_whose_code_sends_are_paused: an upload that silently resumes paused code sends.workflows-transactional-email-apion.Proofs on this head
6df2894(saved withfleet proof):f9abed0, maildev as the sink. 21 requests through the public API: uploads by key (created, unchanged, updated, superseded), an upload under the key of a template made in PostHog, sends by id and by key, and code sends.43333f8. The upload answers, the new template fields and the upload usage events differ, as the goal names. An edit in PostHog of a code-managed template still answers200here; feat(messaging): lock code-managed templates and adopt templates into code #127172 locks it.Earlier proofs, at 3e24e8b before the split into #127168, #127169 and #127172
Live run at
3e24e8b, cdp-api and workers from feat(cdp): deliver a code send's content on its own transactional email route #127122 at24644bc, curl into maildev. The workflow that ran each job comes from a row-level audit of the job queue (saved withfleet proof):createdunchangedcreated, 202PATCH, then a code sendBase-written data: code sends under two keys and a template made in PostHog with Django at feat(workflows): send an email with inline html from an MCP tool #127167, then Django at
3e24e8bafter its migration:created, 202, deliveredcreatedProd shape: a gap until read-only production access exists on 2026-11-02.
Release status
Docs update
None in this PR. The send API docs follow when the flag opens.
🤖 Agent context
Autonomy: Human-driven (agent-assisted)
Agent: Claude Code, Claude Opus 5.5 (claude-opus-5-5)
srv2of map Map: send code-managed email templates with one PostHog call Silthus/posthog#461 from the reviewed stack's forks feat(messaging): add template keys, owners and content hashes Silthus/posthog#547 and feat(messaging): upload, send and lock code-managed email templates Silthus/posthog#548, without the template send (feat(messaging): send a stored template by key on send/email #127176) and the editor (feat(workflows): show code-managed email templates read-only #127179).979d1e0repairs a drifted workflow on upload and refuses a first upload under a paused key;8c9fa9fmoves an unused key lookup to feat(messaging): send a stored template by key on send/email #127176;e852cd9names the paused workflow;df50152compares the whole email step. Two nits rejected: the 403 text names the access the member lacks, and feat(messaging): send a stored template by key on send/email #127176 reads the other hash states.qa-swarm,tdd,django-migrations,improving-drf-endpoints,implementing-mcp-tools,writing-tests,writing-dataclasses,writing-user-facing-copy,pr-description,writing-pr-descriptions.managed_bynullable?transactional_email_keys?workflows-email-from-code, per organization400 transactional_email_pausedand names the workflow to resume, instead of resuming code sendsmanaged_byset); a release keeps them on the templateOpen: may the hog_flow update, graph, action-email and publish paths change a code-managed template's workflow? Recommended: a follow-up PR refuses those writes with
immutable, and an upload repairs any drift.Involvement: one brief from Michael with decisions; one review round (GPT-6.1 Sol: review, design and Michael's lens; Opus fresh eyes) with its fixes; QA swarm on 2026-11-01 with two panel rounds and two final reads, the last clean: 7 findings fixed, 2 rejected; live and shadow-diff proof captured.
🤖 Generated with Claude Code