models

package
v0.0.3 Latest Latest
Warning

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

Go to latest
Published: Nov 12, 2026 License: AGPL-3.0 Imports: 4 Imported by: 0

Documentation

Overview

Package models holds the domain types shared by the store, estimator and web layers.

Index

Constants

View Source
const (
	JobQueued    = "queued"
	JobRunning   = "running"
	JobSucceeded = "succeeded"
	JobFailed    = "failed"
	JobCanceled  = "canceled"
	JobExpired   = "expired"
)

The states of a worker job. A job is queued until a worker leases it, then running; it ends as succeeded, failed (given up, kept for the administrator), canceled or expired (never started in time).

View Source
const (
	JobOriginUser     = "user"     // a button in the pages
	JobOriginAPI      = "api"      // the public API
	JobOriginSchedule = "schedule" // the scheduler
	JobOriginAdmin    = "admin"    // an administrator
)

Where a job came from.

View Source
const (
	OutcomeOK    = "ok"    // done
	OutcomeRetry = "retry" // a temporary problem: try again later, while attempts are left
	OutcomeFail  = "fail"  // a permanent problem: do not try again
)

How a worker ended an attempt.

View Source
const (
	MinJobPriority     = 1
	MaxJobPriority     = 100
	DefaultJobPriority = 50
)

Job priorities are 1 (lowest) to 100 (highest); administrators' jobs always go first.

View Source
const (
	MethodScale       = "scale"       // bioimpedance smart scale (Withings, manual entry from a scale)
	MethodHydrostatic = "hydrostatic" // underwater weighing
	MethodBodPod      = "bodpod"      // air displacement plethysmography
	MethodCaliper     = "caliper"     // skinfold calipers
	MethodTape        = "tape"        // tape measure / Navy formula
	MethodVisualAI    = "visual-ai"   // AI estimate from photos
	// MethodManualEntry is a value typed into an app (for example a body fat % entered by hand in
	// the Withings app): how it was measured is unknown, so it ranks last by default.
	MethodManualEntry = "manual-entry"
)

Measurement methods: how a scale/body-composition reading was obtained.

View Source
const (
	RoleUser  = "user"
	RoleAdmin = "admin"
)

User roles.

View Source
const (
	ProviderKindOIDC   = "oidc"   // OpenID Connect with discovery, e.g. Google
	ProviderKindApple  = "apple"  // Sign in with Apple: OIDC with a generated client secret
	ProviderKindOAuth2 = "oauth2" // plain OAuth 2.0 with a userinfo endpoint
)

Kinds of external sign-in provider.

View Source
const (
	MinUsernameLen = 2
	MaxUsernameLen = 32
	// MaxPersonNameLen bounds a first or last name, in characters.
	MaxPersonNameLen = 64
)

MaxUsernameLen and MinUsernameLen bound a username in bytes (it is ASCII).

View Source
const ProviderLocal = "local"

ProviderLocal is the identity provider of username and password sign-in.

View Source
const ProviderPasskey = "passkey"

ProviderPasskey is the pseudo-provider of passkey sign-in. Like ProviderLocal it cannot be used as the short name of an external provider.

View Source
const SourceManual = "manual"

SourceManual is the source of readings entered by hand.

Variables

View Source
var Methods = []MethodInfo{
	{MethodHydrostatic, "Hydrostatic weighing"},
	{MethodBodPod, "BodPod"},
	{MethodCaliper, "Skinfold caliper"},
	{MethodScale, "Smart scale (Withings, manual)"},
	{MethodTape, "Tape / Navy formula"},
	{MethodVisualAI, "Visual AI"},
	{MethodManualEntry, "Typed into an app (unknown method)"},
}

Methods lists all methods in the default accuracy order (most accurate first).

Functions

func CleanPersonName added in v0.0.2

func CleanPersonName(s string) (name string, ok bool)

CleanPersonName trims a first or last name. ok is false when it is longer than MaxPersonNameLen characters or holds a control character. An empty name is fine: both are optional.

func DefaultRanking

func DefaultRanking() []string

DefaultRanking returns the method keys in the default accuracy order.

func JobActive

func JobActive(state string) bool

JobActive reports whether a job in this state can still run.

func NormalizeEmail

func NormalizeEmail(email string) string

NormalizeEmail returns the canonical form of an e-mail address, used to compare addresses.

func NormalizeRanking

func NormalizeRanking(in []string) []string

NormalizeRanking drops unknown and duplicate keys and appends missing methods in default order, so the result always contains every method exactly once.

func ValidMethod

func ValidMethod(key string) bool

ValidMethod reports whether key is a known method.

func ValidUsername added in v0.0.2

func ValidUsername(s string) bool

ValidUsername reports whether s can be a new username: 2 to 32 letters, digits, '.', '_' or '-', starting with a letter or a digit.

Types

type AccessToken

type AccessToken struct {
	ID         int64
	UserID     int64
	Name       string
	Prefix     string // the first characters of the token, to recognise it in lists
	Hash       string
	CreatedAt  time.Time
	LastUsedAt *time.Time
	ExpiresAt  *time.Time
}

AccessToken is a personal access token. Only a hash of the token is stored.

type AuditEvent

type AuditEvent struct {
	ID       int64     `json:"id"`
	At       time.Time `json:"at"`
	ActorID  *int64    `json:"actor_id"`  // who did it; nil for anonymous requests and deleted users
	TargetID *int64    `json:"target_id"` // whose account it concerns; nil when none or deleted
	Action   string    `json:"action"`
	Detail   string    `json:"detail,omitempty"`
	IP       string    `json:"ip,omitempty"` // cleared when the user is deleted, dropped after the retention period
}

AuditEvent records something security-relevant that happened: a sign-in, a change to an account, an export or an administrator's action. Detail never holds credentials or other personal data.

type AuthProvider

type AuthProvider struct {
	Slug         string
	Label        string
	Kind         string
	Issuer       string // OIDC issuer URL
	AuthURL      string // plain OAuth 2.0 endpoints
	TokenURL     string
	UserinfoURL  string
	ClientID     string
	ClientSecret string // for Apple: the PEM private key the client secret is signed with
	AppleTeamID  string
	AppleKeyID   string
	Scopes       string // space separated
	SubjectClaim string // plain OAuth 2.0: the userinfo field that identifies the account
	NameClaim    string // preferred claim for naming new users
	AllowSignup  bool   // create an account on the first sign-in
	CreatedAt    time.Time
}

AuthProvider is an external sign-in provider added by an administrator.

type Completion

type Completion struct {
	Outcome string // OutcomeOK, OutcomeRetry or OutcomeFail
	Result  string
	Error   string
	// RetryAt is when a retry may run; the backend computes it from its backoff settings.
	RetryAt time.Time
}

Completion is how a worker ends an attempt.

type DexaScan

type DexaScan struct {
	ID                int64     `json:"id"`
	UserID            int64     `json:"user_id"`
	MeasuredAt        time.Time `json:"measured_at"`
	WeightKg          *float64  `json:"weight_kg,omitempty"`
	FatRatioPct       *float64  `json:"fat_ratio_pct,omitempty"`
	FatMassKg         *float64  `json:"fat_mass_kg,omitempty"`
	FatFreeMassKg     *float64  `json:"fat_free_mass_kg,omitempty"`
	LeanMassKg        *float64  `json:"lean_mass_kg,omitempty"`
	BoneMassKg        *float64  `json:"bone_mass_kg,omitempty"`
	VisceralFatMassKg *float64  `json:"visceral_fat_mass_kg,omitempty"`
	BMDGCm2           *float64  `json:"bmd_g_cm2,omitempty"`
	TScore            *float64  `json:"t_score,omitempty"`
	ZScore            *float64  `json:"z_score,omitempty"`
	AndroidFatPct     *float64  `json:"android_fat_pct,omitempty"`
	GynoidFatPct      *float64  `json:"gynoid_fat_pct,omitempty"`
	Notes             string    `json:"notes,omitempty"`
	CreatedAt         time.Time `json:"created_at"`
}

DexaScan is a single DEXA scan result.

type Identity

type Identity struct {
	UserID   int64
	Provider string
	// Subject identifies the account at the provider. For ProviderLocal it is the user id.
	Subject string
	// Secret holds the password hash for ProviderLocal and is empty otherwise.
	Secret    string
	CreatedAt time.Time
}

Identity is one way a user can sign in, independent of the user record itself.

type Job

type Job struct {
	ID       int64
	PublicID string // the identifier used outside the database
	UserID   int64
	Kind     string // "<provider>.<action>", such as "withings.import"
	Origin   string
	// Interactive jobs are waited for by a person, so they go before background ones of the same priority.
	Interactive bool
	// DedupeKey allows one active (queued or running) job per key; empty means no limit.
	DedupeKey string
	State     string
	// Payload holds the job's parameters, and Result what it produced. The store encrypts both.
	// Payload is cleared when the job ends, because it can hold a credential.
	Payload     string
	Progress    string
	Result      string
	Error       string
	Attempts    int
	MaxAttempts int
	Timeout     time.Duration // the hard limit of one attempt

	CreatedAt  time.Time
	RunAfter   time.Time
	ExpiresAt  *time.Time // a queued job still waiting after this is expired instead of run late
	StartedAt  *time.Time
	FinishedAt *time.Time
	UpdatedAt  time.Time

	LeaseOwner      string
	LeaseUntil      *time.Time
	DeadlineAt      *time.Time
	CancelRequested bool
}

Job is one unit of work for a worker, such as importing a user's Withings measurements. The backend owns the queue; a worker only ever sees a job inside a lease.

type JobFilter

type JobFilter struct {
	UserID int64    // 0: every user
	Kinds  []string // empty: every kind
	States []string // empty: every state
	Limit  int      // 0: 100
}

JobFilter selects jobs for a listing, newest first.

type JobKindStats

type JobKindStats struct {
	Kind    string
	Queued  int
	Running int
	Failed  int // that ended as failed in the period asked for
}

JobKindStats counts the jobs of one kind.

type JobSchedule

type JobSchedule struct {
	UserID              int64
	Kind                string
	LastEnqueuedAt      *time.Time
	ConsecutiveFailures int
	// PausedReason is set when the scheduler stopped enqueuing for the user after repeated failures.
	PausedReason string
}

JobSchedule is the scheduler's memory about one user and kind.

type LeaseRequest

type LeaseRequest struct {
	Kinds     []string
	Owner     string        // the worker's name, for the administrator
	TokenHash string        // hash of the secret that proves later calls come from the leaseholder
	LeaseFor  time.Duration // how long the lease lasts without a heartbeat
	// MaxRunning limits how many jobs of a kind run at once, in all workers together; a kind that is
	// missing is not limited. Paused kinds are never leased.
	MaxRunning map[string]int
	Paused     []string
}

LeaseRequest asks for the next job a worker may run.

type MethodInfo

type MethodInfo struct {
	Key   string
	Label string
}

MethodInfo describes a measurement method for forms.

type NewJob

type NewJob struct {
	UserID      int64
	Kind        string
	Origin      string
	Interactive bool
	DedupeKey   string
	Payload     string
	MaxAttempts int
	Timeout     time.Duration
	RunAfter    time.Time  // zero means now
	ExpiresAt   *time.Time // nil means never
}

NewJob describes a job to queue.

type Passkey

type Passkey struct {
	CredentialID string // base64url
	UserID       int64
	Name         string
	Credential   string // JSON of the WebAuthn credential: public key, transports, flags
	SignCount    uint32
	CreatedAt    time.Time
	LastUsedAt   *time.Time
}

Passkey is a WebAuthn credential of a user, used to sign in without a password.

type ScaleReading

type ScaleReading struct {
	ID               int64     `json:"id"`
	UserID           int64     `json:"user_id"`
	MeasuredAt       time.Time `json:"measured_at"`
	WeightKg         *float64  `json:"weight_kg,omitempty"`
	FatRatioPct      *float64  `json:"fat_ratio_pct,omitempty"`
	FatMassKg        *float64  `json:"fat_mass_kg,omitempty"`
	FatFreeMassKg    *float64  `json:"fat_free_mass_kg,omitempty"`
	MuscleMassKg     *float64  `json:"muscle_mass_kg,omitempty"`
	HydrationKg      *float64  `json:"hydration_kg,omitempty"`
	BoneMassKg       *float64  `json:"bone_mass_kg,omitempty"`
	VisceralFatIndex *float64  `json:"visceral_fat_index,omitempty"`
	Source           string    `json:"source"`
	Method           string    `json:"method"`
	AthleteMode      bool      `json:"athlete_mode"`
	ExternalID       *string   `json:"external_id,omitempty"`
	Notes            string    `json:"notes,omitempty"`
	CreatedAt        time.Time `json:"created_at"`
}

ScaleReading is a single smart-scale measurement. Fields are aligned with Withings measure types. Source and ExternalID make imports idempotent (e.g. Source "withings", ExternalID = grpid).

type Session

type Session struct {
	UserID    int64
	Method    string // how the user signed in: ProviderLocal, ProviderPasskey or a provider slug
	CreatedAt time.Time
	ExpiresAt time.Time
}

Session is a signed-in browser session. The token itself is never stored, only its hash.

type TOTP

type TOTP struct {
	UserID      int64
	Secret      string // the shared secret, decrypted
	LastStep    int64  // newest 30-second step that was accepted
	Confirmed   bool   // false while the user is still setting it up
	ConfirmedAt time.Time
	CreatedAt   time.Time
}

TOTP is a user's time-based one-time password setup (two-step verification).

type User

type User struct {
	ID int64 `json:"id"`
	// Username is the unique handle of the account (see ValidUsername); it is compared without regard
	// to case. People sign in with their e-mail address, not with it.
	Username string `json:"username"`
	// FirstName and LastName are optional personal details; they are not used to sign in.
	FirstName string    `json:"first_name"`
	LastName  string    `json:"last_name"`
	Role      string    `json:"role"`
	CreatedAt time.Time `json:"created_at"`
	// Email signs the user in and identifies them, unique per user. It is empty for accounts that
	// only sign in through a provider that did not vouch for an address. External providers never
	// match accounts by it.
	Email    string   `json:"email"`
	HeightCm *float64 `json:"height_cm,omitempty"`
	// Timezone is an IANA time zone name such as "Europe/Amsterdam". It decides which calendar
	// day a reading belongs to and how manual date-times are read and shown. Empty means UTC.
	Timezone string `json:"timezone"`
	// AthleteDefault presets athlete mode for new readings and imports.
	AthleteDefault bool `json:"athlete_default"`
	// MethodRanking lists methods most accurate first. Always contains every method.
	MethodRanking []string `json:"method_ranking"`
	// HiddenColumns lists the daily table columns the user has hidden.
	HiddenColumns []string `json:"-"`
	// StrengthLevelAuto is set by an administrator. It lets the user store their Strength Level
	// login and sync body readings to it automatically.
	StrengthLevelAuto bool `json:"-"`
	// StrengthLevelBulk additionally allows the multi-day sync on the settings page. It needs
	// StrengthLevelAuto.
	StrengthLevelBulk bool `json:"-"`
	// JobPriority (1-100) orders the user's worker jobs among those of other users: a higher number
	// goes first. Administrators' jobs always go before everyone's. Set by an administrator.
	JobPriority int `json:"-"`
	// DataVersion changes whenever the scans, readings or settings that estimates are computed
	// from change, in any way and from any process. Cached results are valid for one version.
	DataVersion int64 `json:"-"`
}

User is a person whose measurements are tracked.

func (User) DisplayName added in v0.0.2

func (u User) DisplayName() string

DisplayName is what the app calls the user: the first name when there is one, else the username.

func (User) FullName added in v0.0.2

func (u User) FullName() string

FullName is the first and last name together, or the username when neither is set.

func (User) IsAdmin

func (u User) IsAdmin() bool

IsAdmin reports whether the user has the administrator role.

func (User) Location

func (u User) Location() *time.Location

Location returns the user's time zone, or UTC when none is set or it cannot be loaded.

type WorkerInstance

type WorkerInstance struct {
	ID       string
	Kinds    []string
	Version  string
	LastSeen time.Time
}

WorkerInstance is a worker process that recently asked for work.

Jump to

Keyboard shortcuts

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