Help us shape the future of Go! Take the 2026 Go Developer Survey

weekly

package
v0.40.21 Latest Latest
Warning

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

Go to latest
Published: Nov 1, 2026 License: MIT Imports: 13 Imported by: 0

Documentation

Overview

Package weekly is the opt-in weekly recap email: on Monday morning, last week's miles, energy, cost and efficiency, and lease pace if the user tracks a lease. Plain text, no images, no tracking, a signed one-click unsubscribe. A week with no drive and no charge sends nothing.

Every send goes through internal/engage (toggle, budget, once per account and week), so it is safe on every replica and counts toward the monthly budget.

Index

Constants

View Source
const (
	SendFromHour  = 8
	SendUntilHour = 12
	SweepEvery    = 30 * time.Minute
	// BestDriveMinMiles keeps a short hop from being the "best drive".
	BestDriveMinMiles = 5.0
)

The recap goes out on Monday between SendFromHour and SendUntilHour local: a few hours' grace so a restart or an outage at 08:00 does not cost the week (the claim still makes it once).

View Source
const Kind = "weekly_recap"

Kind is the engage kind of the recap.

Variables

This section is empty.

Functions

func Due

func Due(now time.Time, loc *time.Location) bool

Due reports whether it is the sending window for a user in loc.

func IdempotencyKey

func IdempotencyKey(uid uuid.UUID, week string) string

IdempotencyKey is a stable, opaque per-(account, week) key; the raw user id never leaves the server.

func Render

func Render(s Summary, appURL, unsubURL string) (subject, text string)

Render writes the subject and the plain-text body.

func Week

func Week(now time.Time, loc *time.Location) (key string, start, end time.Time)

Week returns the previous full local week (Monday to Monday) before now in loc, and its key "weekly:{ISO year}-W{ISO week}".

Types

type Candidate

type Candidate struct {
	User     uuid.UUID
	Email    string
	Timezone string
	Model    string
}

Candidate is an account that turned the recap on.

type Job

type Job struct {
	Source    Source
	Summarize SummaryFunc
	Mailer    Mailer
	Signer    *statement.Signer
	BaseURL   string
	Engage    *engage.Engage
	Now       func() time.Time
	Logger    *slog.Logger
	// Pause is called between sends (the throttle); nil uses 500 ms.
	Pause func(ctx context.Context)
}

Job sends the recaps.

func (*Job) Run

func (j *Job) Run(ctx context.Context)

Run sweeps shortly after start and then every SweepEvery until ctx ends.

func (*Job) Sweep

func (j *Job) Sweep(ctx context.Context) (Stats, error)

Sweep considers every opted-in account once.

type LeasePace

type LeasePace struct {
	// MilesOver is positive when they are over pace, negative when under.
	MilesOver float64
}

LeasePace is how the user stands against the lease allowance.

type Mailer

type Mailer interface {
	Send(ctx context.Context, m email.Message) error
}

Mailer is the part of the email client the job uses.

type Source

type Source interface {
	Candidates(ctx context.Context) ([]Candidate, error)
	// Enabled reads the live toggle.
	Enabled(ctx context.Context, uid uuid.UUID) (bool, error)
}

Source reads who gets the recap and whether they still want it.

func NewSource

func NewSource(db *sql.DB, skip uuid.UUID) Source

NewSource reads from Postgres. skip (the demo account) is never a candidate.

type Stats

type Stats struct{ Considered, Due, Sent, Skipped, Failed int }

Stats is what one sweep did.

type Summary

type Summary struct {
	Model      string
	Currency   string
	Miles      float64
	Drives     int
	KWhUsed    float64 // 0: unknown
	MiPerKWh   float64 // 0: unknown
	KWhCharged float64
	Cost       float64
	// HomePct is the share of charged energy done at home; nil when no home
	// place is set or nothing was charged.
	HomePct *int
	// BestMiles and BestMiPerKWh describe the most efficient drive; zero when the
	// week had fewer than two drives.
	BestMiles, BestMiPerKWh float64
	Lease                   *LeasePace
	// Charges counts charging sessions in the week.
	Charges int
}

Summary is one week's figures.

func (Summary) Empty

func (s Summary) Empty() bool

Empty is true for a week with no drive and no charge.

type SummaryFunc

type SummaryFunc func(ctx context.Context, c Candidate, start, end time.Time, loc *time.Location) (Summary, error)

SummaryFunc computes the figures for the local week [start, end).

Jump to

Keyboard shortcuts

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