Trial engine — lifecycle + nudges
PROD-03 introduced a shared trial engine at packages/trial-engine/. Every commercial product reuses it.
What it does
Section titled “What it does”- Provisions a trial tenant on
/trial?product=<slug>with the manifest’sdefault_tier,seed_dataset, andfirst_action_route. - Schedules an 8-stage lifecycle of emails offset from
trial_started: welcome, day-1 nudge, day-3 spotlight, day-7 check-in, day-11 trial-ends-soon, day-13 final reminder, day-14 trial-ended, day-21 survey. - Detects failure-to-launch via an hourly job — fires
trial_help_neededPulse + a help-offer email when the user is stuck (no first-action after 4 hours, no login after 24 hours). - Honors consent — every send is gated through
consent.ts. CAN-SPAM unsubscribe + GDPR consent reset.
Per-product config (in packages/naming/manifest.json)
Section titled “Per-product config (in packages/naming/manifest.json)”"onboarding": { "first_action_route": "/scan/new", "first_action_event": "scan_started", "first_action_prompt": "Run your first AEGIS scan", "seed_dataset": "aegis-demo-tenant", "default_tier": "pro"}Pulse events fired
Section titled “Pulse events fired”trial_started, trial_first_action_started, trial_first_action_completed, trial_help_needed, trial_converted, trial_downgraded_to_free, trial_expired_no_action. Documented in Pulse.
Pitfalls
Section titled “Pitfalls”- Don’t fork the lifecycle per product — extend the shared schedule and stamp per-product copy at render.
- Don’t bypass
consent.tsin templates — every send routes through it. - Don’t manipulate
trial_started_atto re-trigger emails — the scheduler is idempotent on(tenant_id, stage).
See packages/trial-engine/README.md for the API + test fixtures.