analytics

package
v1.0.3 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 3, 2026 License: MIT Imports: 8 Imported by: 0

Documentation

Overview

Package analytics runs the milestone-07 aggregate-and-prune job: it rolls the raw event stream up into per-project daily_stats rows (bucketed in each project's rollup timezone) and prunes events older than the project's retention window. The same job runs on an in-process schedule and on demand through moth.admin.v1.AnalyticsService/RunRollup.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Seed

Seed inserts a deterministic, realistic-looking synthetic event history for one project: a slowly growing user base with a weekly usage cycle, mixed providers (password/Google/Apple) and platforms, sampled token refreshes, a base rate of login failures and one elevated-failure incident day. It writes raw events only — run a Rollup afterwards to materialize daily_stats. It returns how many events were inserted.

The synthetic user ids ("seed-user-N") reference no users row, which the schema allows; the data is for dashboards and tests, not for auth.

func SeedSubscriptions

func SeedSubscriptions(ctx context.Context, st store.SubscriptionEventStore, p store.Project, o SeedOptions) (int, error)

SeedSubscriptions inserts a deterministic synthetic subscription-event history for one project: trials and direct purchases that renew month over month, a slice of trials converting to paid, a low rate of cancellations, expiries and refunds, spread across two stores, three tiers and two currencies — plus a small share of sandbox events (excluded from production dashboards). It writes raw events only; run a Rollup afterwards to materialize the monthly stats. It returns how many events were inserted.

The stream is internally consistent with the milestone-14 rollup's exact event consumption (see internal/store/subscription_analytics.go), so tests can cross-check the rollup against independent SQL over these rows.

Types

type Rollup

type Rollup struct {
	// contains filtered or unexported fields
}

Rollup is the aggregate-and-prune job.

func NewRollup

func NewRollup(st Store, log *slog.Logger, now func() time.Time) *Rollup

NewRollup builds the job. now is injectable for tests; nil means time.Now.

func (*Rollup) Run

func (r *Rollup) Run(ctx context.Context, projectID string) (store.RollupRun, error)

Run rolls up one project (or every project when projectID is empty) and records the run in rollup_runs. Only completed local days are processed: for each project it re-aggregates every day from the newest already rolled-up day (re-rolling it is idempotent and catches events flushed across midnight by the async writer) through yesterday in the project's rollup timezone — a first rollup backfills at most the retention window. It then prunes raw events older than the project's retention window, never reaching into a day a later run still re-rolls. Failures on one project do not stop the others; the combined error is recorded on the run and returned.

func (*Rollup) RunPeriodically

func (r *Rollup) RunPeriodically(ctx context.Context, observers ...func(error))

RunPeriodically runs the whole-instance rollup on a jittered hourly ticker until ctx is done. Nightly-at-00:30-project-local scheduling would need one timer per timezone; instead the job simply runs every hour and only ever processes completed local days, so each project's finished day is rolled up within about an hour of its local midnight and intermediate runs just re-roll the newest day (idempotent, one small query). The first run happens after the initial jitter so a restarted instance catches up quickly. Failures are logged, never fatal. observers, when supplied, are notified of each run's outcome (nil error on success) so callers can record it (e.g. a metrics counter).

type SeedOptions

type SeedOptions struct {
	// Days of history to generate, ending yesterday (project-local).
	Days int
	// Seed makes the generated stream deterministic.
	Seed uint64
	// Now anchors "yesterday"; nil means time.Now.
	Now func() time.Time
}

SeedOptions tunes Seed. The zero value seeds 90 days with seed 1.

type Store

type Store interface {
	GetProject(ctx context.Context, id string) (store.Project, error)
	ListProjects(ctx context.Context) ([]store.Project, error)
	DeleteEventsBefore(ctx context.Context, projectID string, cutoff time.Time) (int64, error)
	store.StatsStore
	store.SubscriptionStatsStore
}

Store is everything the rollup job needs from persistence.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL