feat(status): auto-expiring custom status (LC-319) #336
Loading…
Reference in a new issue
No description provided.
Delete branch "feat/lc-319-auto-expiring-status"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
What
Auto-expiring custom status: a user can schedule their custom status to clear itself after a chosen interval ("clear my status in 1 hour"). Implements LC-319 / LC-320.
The status picker gains a Clear after select below the custom-status input: Don't clear (default), 30 minutes, 1 hour, 4 hours, 1 day, 1 week. After the interval the custom text auto-clears; the presence value (active/idle/away/dnd) is left untouched, and the change fans out live to other viewers exactly like a manual clear.
How
auth/0028_custom_status_expiry.sqladds nullableusers.custom_status_expires_at(NULL = never). Deliberately kept out of every existingSELECT/row_to_user_record, so the sharedUser/UserRecordmodel and its ~20 read sites are untouched.db::auth::set_user_statusgains anexpires_modifier: Option<&str>param (a SQLite relative modifier like+1 hours) applied via a singleCASE WHEN ? IS NULL THEN NULL ELSE datetime('now', ?) END. The modifier comes from a fixed allowlist inroutes::status::expiry_modifier, never raw input. Clearing the custom text forces the expiry to NULL.db::auth::clear_expired_custom_statusesis a singleRETURNINGUPDATE that nulls text + expiry for past-due rows and returns(id, status). Newspawn_status_expiry_scanner(60s tick, modeled onspawn_idle_scanner) broadcastsChatEvent::UserStatusChanged { custom_status: None }per cleared row so avatars/hovercards drop the stale text live. 60s granularity matches the idle-flip tolerance; no per-request lazy clearing, so the read path stays write-free (consistent with thetouch_user_activitycontention note).clear_afterselect (default "Don't clear", disabled while the custom input is empty); when an expiry is active, a muted localized "auto-clears" hint via<time data-lc-ts>reusing the LC-314Intl.RelativeTimeFormatscanner. The select is authoritative (re-saving with "Don't clear" removes any existing expiry, Slack-style).status.ftlkeys with en/es parity.Testing
just check(clippy standalone + saas, fmt) clean.just testandjust test-saasgreen. Newdb_status.rscases cover expiry scheduling, empty-custom forcing NULL expiry, the sweep clearing past-due rows only while preserving presence, and the no-op-when-nothing-expired path.Operator impact
None. No new env var, config, or contract change; no
[operator-action]marker.🤖 Generated with Claude Code