Skip to content

Automations server parts: step statistics, journey counts, messages by automation, exited recount - #533

Merged
pierre-b merged 10 commits into
devfrom
feat/automations-server
Nov 12, 2026
Merged

pierre-b merged 10 commits into
devfrom
feat/automations-server

Conversation

@pierre-b

@pierre-b pierre-b commented Nov 12, 2026 •

Copy link
Copy Markdown
Contributor

Server part 4 of 6 for the console redesign (automation screens). No console change: the screens ship in their own PRs.

What changes

  • automations.nodeStats (new, GET): the statistics of each step of an automation, over a period (since, until) or all time.
    • Per step: visits (distinct journeys), results, skip reasons, the path each split took (filter yes/no, list status branch, A/B variant), journeys waiting or retrying there, failed attempts and failed journeys.
    • For email steps, when the member may read message history: executions, queued, not sent, sent, delivered, opened, clicked, failed, bounced, complained and unsubscribed, with the same filters as the message history analytics measures.
    • Every step of the graph is listed, with its type from the graph; a step never visited has zeros. Six statements in one read-only REPEATABLE READ transaction.
    • 403 without automations read, 404 for an unknown automation, 400 for an invalid period.
  • automations.list takes with_journey_counts and returns journey_counts, each automation's journeys by status ({} for an empty page).
  • messages.list filters by automation_id; the message history analytics get an automation_id dimension.
  • v44: stats.exited of each automation is raised to its number of exited journeys (until 44 a reply exit was not counted there). The recount runs last, after the index builds, so it cannot deadlock with a tracking write. Approved as an addition to v44 (VERSION stays 44.0).
  • Demo data: the seeded journeys write the real executor outputs, the error path's rows on failed journeys, and their emails' messages, so the step statistics show on the demo.
  • OpenAPI: automations.list and automations.nodeStats with their schemas.
  • CHANGELOG under 44.0: one Feature line; Answer 404 from automations.get and count reply exits in stats.exited #522's Fix line now ends "past exits included".

Tests

  • Unit tests per layer: domain (request parsing, response shape), repository (sqlmock: each statement, the period, the read-only snapshot), service (permissions, nodes from the graph, maps never null, 404), handler (both routes), v44 (exact ordered statements), demo (outputs match the path, failed journeys, messages).
  • Integration tests, against PostgreSQL, with Mailpit and the real executor and queue:
    • TestAutomationNodeStats: visits, splits, waiting, retrying, failed attempts, messages.list?automation_id, email counters compared with the analytics count_sent and count_opened, queued and not sent (a duplicate queue entry and another automation's entry included), the period, missing message history read, 403, 404 and 400;
    • TestAutomationJourneyCounts;
    • TestV44ExitedRecount: raised, kept, odd stored values, deleted and non-object stats, a rerun writes nothing;
    • TestDemoAutomationsSeedRealHistory reads the seed through the step statistics.
  • Measured on a throwaway database: no deadlock in 300 migration runs against a loop of opens with the recount last; the email counters take 73 ms on 50,000 executions and 5,000 queue rows.
  • Updated with dev after Broadcasts server parts: status counts, started_after, estimateAudience, open and click time dimensions, start date of scheduled sends #532: the domain, repository, http, migrations and broadcast service tests and the integration tests above pass on the merge. The OpenAPI bundle equals the committed openapi.json.

Plan, with its review corrections and an "As built" section: plans/console-redesign-server-4-automations-plan.md.

Known, not handled

  • Databases already stamped 44 (dev, demo) do not get the recount.
  • waiting compares a delay's delay_until, written with the application clock, with the database's now(): a clock skew moves a journey between waiting and in progress for that long.
  • The EXPLAIN (ANALYZE, BUFFERS) on a 1-million-journey automation is left for the console PR.
  • During the upgrade, the recount waits up to 5 seconds for each automation row held by another transaction, while writes to message_history wait behind it.
  • The demo models no bounce, complaint or failed send, writes no open or click timeline entries, and its messages carry no list_id.
  • No test fails when some statement details are wrong: errors counting every completed execution, completed including errors, queued without the missing-message condition, the A/B key read from variant_name, or the transaction opened without read-only and REPEATABLE READ.

…ast_sent_at, transactional filter, recent failure indexes

- message_history analytics: origin dimension (broadcast, automation or
  transactional) and last_sent_at measure (last send not failed)
- messages.list filters by transactional_notification_id
- v44 adds partial indexes on failed, bounced and complained messages in
  messages.list order; new workspaces get them from init.go
… v44 exited recount

automations.nodeStats counts, for every step of an automation over a period or all time,
the journeys that visited it, its results, the journeys waiting or retrying there and,
for email steps, the messages it sent. automations.list adds journey_counts by status with
with_journey_counts. messages.list filters by automation_id, and the message history
analytics gain an automation_id dimension. v44 raises stats.exited to the exited journeys.
…document the automation routes

The demo's node executions carry what each executor writes, its queued emails have their
messages, and its failed journeys the error rows of their attempts, so automations.nodeStats
shows them. automations.list and automations.nodeStats are in the OpenAPI document, and the
CHANGELOG has the feature.
# Conflicts:
#	CHANGELOG.md
#	internal/domain/analytics_test.go
#	internal/domain/message_history.go
#	internal/domain/message_history_test.go
#	internal/migrations/v44.go
#	internal/migrations/v44_test.go
#	internal/repository/analytics_postgres_test.go
#	internal/repository/message_history_postgre.go
#	internal/repository/message_history_postgre_test.go
@codecov

codecov Bot commented Nov 12, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 79.54545% with 90 lines in your changes missing coverage. Please review.
✅ Project coverage is 88.96%. Comparing base (857e39f) to head (82a9b47).
⚠️ Report is 1 commits behind head on dev.

Files with missing lines Patch % Lines
internal/service/demo_automation_history.go 70.58% 44 Missing and 6 partials ⚠️
internal/repository/automation_stats_postgres.go 72.80% 21 Missing and 13 partials ⚠️
internal/domain/automation_node_stats.go 95.55% 1 Missing and 1 partial ⚠️
internal/http/automation_handler.go 94.59% 1 Missing and 1 partial ⚠️
internal/service/automation_node_stats_service.go 96.29% 1 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##              dev     #533      +/-   ##
==========================================
- Coverage   89.02%   88.96%   -0.06%     
==========================================
  Files         374      377       +3     
  Lines       73402    73836     +434     
==========================================
+ Hits        65345    65691     +346     
- Misses       5369     5437      +68     
- Partials     2688     2708      +20     
Flag Coverage Δ
unit 88.96% <79.54%> (-0.06%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@pierre-b
pierre-b marked this pull request as ready for review November 12, 2026 15:12
@pierre-b
pierre-b merged commit c8256be into dev Nov 12, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant