Add a job-level gate to the scheduler. When set, the gate is consulted
on every popped job; if it returns false, the job is skipped and
re-enqueued for its next interval without invoking the engine.
A new UserGater builds such a gate from a user resolver and an
inactivity threshold:
- users with UserQuota.SchedulingPaused are always blocked (admin
kill switch);
- users whose LastSeen is older than their effective inactivity
horizon (UserQuota.InactivityPauseDays, falling back to a system
default) are blocked until they log in again;
- lookups are cached for 5 minutes so the scheduler hot path stays
cheap, with an Invalidate hook for use on user updates.
This addresses the "free trial then forgotten" failure mode described
in the design notes.
Wire up the checker system to the HTTP layer:
- API controllers for checker operations, options, plans, and results
- Scoped routes at domain and service level
- Admin controllers for checker config and scheduler management
- App initialization: create usecases, start/stop scheduler
- Zone controller updated to include per-service check status
Scan -plugins-directory paths at startup, open each .so via plugin.Open,
look up the NewCheckerPlugin symbol from checker-sdk-go, and register the
returned definition and observation provider in the global checker
registries. A pluginLoader indirection keeps the door open for future
plugin kinds.
Integrates optional bot protection on the registration endpoint (always
required when a provider is configured) and the login endpoint (triggered
after N consecutive failures for the same IP or email address).
Supported providers: hCaptcha, reCAPTCHA v2, Cloudflare Turnstile.