The Trinity BeastElastiCache Key Definitions

Complete reference for all key patterns stored in ElastiCache (Valkey). Covers price cache, API key cache, cluster stats, usage log indexes, adaptive governor, rate limiting, public endpoint caches, LRS report counters, real-time usage counters, stress tier cache, KCC dashboard, translation engine state, and deduplication keys.

Engine: Valkey 7.2 Node: cache.r7g.2xlarge Updated: May 30, 2026 Version: v20

Table of Contents

  1. Connection Details
  2. Price Cache
  3. API Key Cache
  4. Application Configuration
  5. Usage Log Indexes
  6. Usage Log Data
  7. Report Usage Logs
  8. Cluster Stats (Metrics Publisher)
  9. Adaptive Governor
  10. Rate Limit Token Buckets
  11. KCC Daily Dashboard
  12. Session Deduplication
  13. Webhook Deduplication
  14. High-Water Marks (Sync Job)
  15. Public Endpoint Caches
  16. LRS Report Counters
  17. Real-Time Usage Counters
  18. Stress Tier Report Cache
  19. Translation Cache (Map Pins)
  20. Translation Engine State
  21. Multi-Lingual Search Index
  22. AutoOps State
  23. Dashboard Authentication & Sessions

1. Connection Details

Node Type
cache.r7g.2xlarge
vCPU
8
Memory
52.8 GB
Engine
Valkey 7.2
TLS
Enabled
Pool / Container
300
PropertyValue
Endpointmaster.trinity-beast-cache.ptsbmm.use2.cache.amazonaws.com:6379
Node Typecache.r7g.2xlarge (8 vCPU, 52.8 GB)
EngineValkey 7.2
TLSEnabled
Client Librarygo-redis UniversalClient (works with both cluster and standalone mode)
Connection Pool300 per container (1,200 total across 4 ECS containers)

2. Price Cache

Cached cryptocurrency prices written by the Kraken prewarm batch and REST fallback path. Read on every LPO price request when the Tier 2 (in-memory) cache misses.

price:{ASSET}

STRING (JSON) TTL: prewarm_interval + 60s
FieldTypeDescription
assetstringCryptocurrency ticker (BTC, ETH, SOL, etc.)
pricefloatCurrent price in USD
timestampstring (ISO 8601)When the price was fetched
readable_timestampstringHuman-readable timestamp
sourcestringPrice source (coinbase-ws, gemini-ws, kraken-ws, gateio-ws, cryptocom-ws, okx-ws, kraken-prewarm)
latency_msintegerSource fetch latency in milliseconds
cachedbooleanAlways false when written; set to true when served from cache
Written by: Kraken prewarm batch, FlushToElastiCache (30s cycle from all 6 WebSocket feeds), REST fallback cache
Read by: LPO price handler (Tier 2 cache miss path), Webhook delivery engine (price resolution)

3. API Key Cache

Full API key records cached as hashes. Populated by the sync job on a regular cycle and on cache miss by the API key store. Every inbound API request reads this key for authentication and rate limit enforcement.

apikey:{api_key}

HASH TTL: 24 hours (set by sync job)
FieldTypeDescription
idstring (uuid)API key record ID
user_idstring (uuid)Owner user ID
namestringSubscriber name
tierstringSubscription tier
query_limitintegerMonthly query limit
current_usageintegerCurrent month's query count
rate_limit_qpsintegerQueries per second limit
burst_limitintegerToken bucket burst capacity
burst_tokensfloatCurrent token balance
api_keystringThe API key string
minimum_wait_secondsfloatMin time between throttled requests
revokedbooleanWhether the key is disabled
lrs_enabledbooleanWhether unlimited LRS reports are enabled
last_usedstring (ISO 8601)Last API call timestamp
created_atstring (ISO 8601)Key creation date
last_successstring (ISO 8601)Last successful API call
Written by: Sync job, API key store on cache miss
Read by: Every API request for key validation
Invalidated by: /admin/invalidate-key endpoint

4. Application Configuration

All runtime application parameters from the Aurora application_parameters table, cached as a single hash. No TTL — persists until explicitly overwritten. Read on every config poll cycle by all containers.

app:config

HASH TTL: none (persistent)

Contains all 56+ application parameters from Aurora. Example fields include:

Example FieldDescription
adaptive_max_concurrentMax concurrent requests before adaptive throttling
cache_pool_sizeElastiCache connection pool size per container
coinbase_prewarm_assetsComma-separated list of assets to prewarm from Coinbase
gemini_prewarm_assetsComma-separated list of assets to prewarm from Gemini
kraken_prewarm_assetsComma-separated list of assets to prewarm from Kraken
log_levelApplication log level (debug, info, warn, error)
cache_ttl_secondsDefault cache TTL for price entries
Written by: Sync job, /admin/reload-params, /admin/system-mode
Read by: LoadApplicationParameters on every config poll cycle

5. Usage Log Indexes

Sorted sets that index usage log entries by timestamp. The global index plus per-API-key and per-asset indexes enable fast range queries for LRS reports without scanning the full dataset.

usage_logs:index

SORTED SET TTL: managed by sync job (93-day retention)

Score: Unix timestamp  |  Members: Usage log UUIDs

Global index of all usage log entries. Used by LRS usage report queries for date-range filtering.

usage_logs:api_key:{api_key_id}

SORTED SET TTL: managed by sync job (93-day retention)

Score: Unix timestamp  |  Members: Usage log UUIDs

Per-API-key usage log index. Enables efficient filtering of usage logs by subscriber.

usage_logs:asset:{asset}

SORTED SET TTL: managed by sync job (93-day retention)

Score: Unix timestamp  |  Members: Usage log UUIDs

Per-asset usage log index. Enables efficient filtering of usage logs by cryptocurrency asset.

6. Usage Log Data

Individual usage log entries stored as hashes. Each entry is a complete snapshot of a single LPO API request. Written by the sync job from Aurora and retained for 93 days.

usage_log:{id}

HASH TTL: 93 days
FieldTypeDescription
api_key_idstringAPI key that made the request
assetstringCryptocurrency asset queried
pricefloatPrice returned
sourcestringPrice source
cachedbooleanWhether served from cache
latency_msintegerSource fetch latency
duration_msintegerTotal request processing time
ip_addressstringClient IP address
timestampstring (ISO 8601)When the request occurred
readable_timestampstringHuman-readable timestamp
cache_age_secondsfloatAge of cached price at time of request
cluster_nodestringECS container that handled the request
regionstringAWS region
monthly_usageintegerSubscriber's usage count at time of request
monthly_limitintegerSubscriber's limit at time of request
Written by: Sync job (from Aurora)
Read by: LRS report handlers
Daily aggregates live in Aurora, not Valkey. Per-day rollups (totals, latency percentiles, cache-hit rate, cardinality) are precomputed by the mv_usage_daily materialized view in Aurora and served to the analytics dashboard via /dashboard/api/admin/daily-rollup. The view is refreshed every 5 minutes by the pg_cron job tbi-mv-usage-daily-refresh running natively inside Aurora — no Lambda, no EventBridge. The Valkey usage-log indexes above remain the fast lane for live per-entry LRS report range queries; the materialized view is the efficient source for day-level aggregates. The two complement each other — live per-entry reads from Valkey, day-level rollups from Aurora. See the Aurora Data Dictionary (section 4.5) for the view schema.

7. Report Usage Logs

Indexes and data for LRS report request logs. Mirrors the Aurora report_usage_logs table in ElastiCache for fast report-on-report queries.

report_usage_logs:index

SORTED SET TTL: managed by sync job

Score: Unix timestamp  |  Members: Report usage log UUIDs

Global index of all report usage entries.

report_usage_logs:api_key:{api_key_id}

SORTED SET TTL: managed by sync job

Score: Unix timestamp  |  Members: Report usage log UUIDs

Per-API-key report usage index for subscriber-scoped report queries.

report_usage_log:{id}

HASH TTL: managed by sync job
FieldTypeDescription
api_key_idstringAPI key that requested the report
report_typestringReport type (usage/summary/report-usage/report-summary)
formatstringOutput format (json/csv/tsv/text)
filtersstring (JSON)Query filters applied
row_countintegerNumber of rows returned
duration_msintegerProcessing time
ip_addressstringClient IP address
timestampstring (ISO 8601)When the report was requested
readable_timestampstringHuman-readable timestamp
cluster_nodestringECS container that handled the request
regionstringAWS region
protocolstringTCP or UDP
status_codeintegerHTTP status returned
Written by: Sync job (from Aurora)
Read by: LRS report-usage and report-summary handlers

8. Cluster Stats (Metrics Publisher)

Each ECS container publishes a JSON snapshot of its runtime metrics to ElastiCache every 3 seconds. Read by /admin/cluster-stats and /public/status for cluster-wide aggregation.

cluster:stats:{node_name}

STRING (JSON) TTL: 30 seconds

Node names: BeastMain, BeastMirror, BeastLRS, BeastWebhook

FieldTypeDescription
uptime_secondsfloatContainer uptime in seconds
tcp_requestsintegerTotal TCP requests handled
udp_requestsintegerTotal UDP requests handled
lrs_requestsintegerTotal LRS report requests
total_rpsfloatRequests per second (all protocols)
syncmap_hitsintegerTier 1 (local sync.Map) cache hits
elasticache_hitsintegerTier 2 (ElastiCache) cache hits
cache_missesintegerFull cache misses (REST fallback)
errors_5xxintegerServer error count
errors_4xxintegerClient error count
rate_limit_hitsintegerRate limit rejections
bg_work_droppedintegerBackground tasks dropped (pool full)
Written by: Metrics publisher goroutine (every 3 seconds per container)
Read by: /admin/cluster-stats, /public/status, KCC daily dashboard

9. Adaptive Governor

Distributed counters and flags used by the adaptive governor to coordinate throttling decisions across all three ECS containers. Uses a hash tag {adaptive:lpo} to ensure all keys land on the same shard for atomic operations.

{adaptive:lpo}:successes

STRING (integer) TTL: managed by governor cycle
Distributed success counter across all containers. Incremented on each successful price fetch. Reset at the start of each governor evaluation window.

{adaptive:lpo}:total

STRING (integer) TTL: managed by governor cycle
Distributed total request counter across all containers. Incremented on every price request (success or failure). Used with successes to calculate the success rate.

{adaptive:lpo}:throttle

STRING (boolean) TTL: managed by governor cycle
Distributed throttle flag. When set to true, all containers reduce outbound requests to protect upstream price sources. Evaluated on every inbound request.

10. Rate Limit Token Buckets

Per-API-key rate limit state stored in ElastiCache for cluster-wide enforcement. The token bucket algorithm tracks remaining tokens and last refill time. Read and updated on every API request.

ratelimit:{api_key}

STRING (JSON) TTL: 5 minutes (public tiers) / 60 minutes (partner)
FieldTypeDescription
tokensfloatCurrent token balance in the bucket
last_refillfloat (unix)Timestamp of last token refill
Written by: Rate limiter middleware on every API request
Read by: Rate limiter middleware for token check
TTL policy: 5 minutes for public tiers (free, pro, enterprise, unlimited, lifetime), 60 minutes for partner and stress tiers

11. KCC Daily Dashboard

Stores the collected daily infrastructure metrics as a single JSON blob. Written by bash scripts/kcc.sh daily-collect and read by the CLI daily command and the KCC Live Dashboard.

kcc:daily

STRING (JSON) TTL: 24 hours

Contains a comprehensive snapshot of all infrastructure metrics: service health, ECS cluster stats, Valkey metrics, Lambda status, nightly sync results, SQS queue depth, and 7-day website analytics.

Written by: KCC daily-collect command (via /admin/valkey endpoint)
Read by: KCC daily command, KCC Live Dashboard (docs/dashboard.html)

12. Session Deduplication

Prevents double-processing of Stripe checkout session completion events. The receipt Lambda writes the full response after processing and checks for existence before re-processing.

receipt:session:{session_id}

STRING (JSON) TTL: 1 hour

Contains: Full Lambda response JSON from the receipt processing

Written by: Receipt Lambda after processing a checkout session
Read by: Receipt Lambda to prevent double-processing of the same session

13. Webhook Deduplication

Prevents duplicate processing of Stripe webhook events. Stripe may deliver the same event multiple times; this key ensures idempotent handling.

webhook:event:{event_id}

STRING TTL: 24 hours
Written by: Webhook handler after processing a Stripe event
Read by: Webhook handler to skip duplicate Stripe events

14. High-Water Marks (Sync Job)

Tracks the last-synced timestamp for incremental data synchronization from Aurora to ElastiCache. The sync job reads these marks to determine which new records need to be copied.

sync:hwm:usage_logs

STRING (ISO timestamp) TTL: none (persistent)
Last synced usage_logs timestamp. The sync job queries Aurora for all usage_logs with timestamp > this value.

sync:hwm:report_usage_logs

STRING (ISO timestamp) TTL: none (persistent)
Last synced report_usage_logs timestamp. The sync job queries Aurora for all report_usage_logs with timestamp > this value.

15. Public Endpoint Caches

Cached responses for the public observability endpoints. These avoid repeated AWS API calls (CloudWatch, S3) by caching the aggregated results in Valkey with short TTLs.

public:infrastructure

STRING (JSON) TTL: 60 seconds
Cached response for GET /public/infrastructure. Contains CloudFront requests/bandwidth, WAF blocked counts, SQS queue depth, Lambda invocations/errors, GuardDuty findings, and CloudWatch alarm states. Refreshed every 60 seconds (CloudWatch metrics have 5-minute granularity anyway).

public:site-assets

STRING (JSON) TTL: 1 hour
Cached response for GET /public/site-assets. Contains S3 bucket file counts by type (pages, docs, images, videos, total). Refreshed every hour — file counts only change on website deploys.

16. LRS Report Counters

Per-API-key report limit tracking cached in Valkey for fast enforcement without Aurora queries on every report request.

report_count:{api_key_uuid}

HASH TTL: none (persistent)

Mirrors the Aurora report_count table for a single API key. Fields: monthly_limit, monthly_count, daily_count, daily_limit, reset_month, last_report_date. Read on every LRS report request to check limits before querying data. Written by the LRS counter after each successful report generation.

17. Real-Time Usage Counters

Per-API-key daily usage counters incremented on every price request. Used for the usage warning system (green/yellow/red thresholds) and the monthly_usage field in price responses.

usage:counter:{api_key}

HASH TTL: 48 hours

Tracks daily request counts per API key. Hash field is the date (YYYY-MM-DD), value is the count. Incremented atomically via HINCRBY on every price request. Read to compute monthly_usage by summing all date fields in the current month. 48-hour TTL ensures old date fields expire naturally.

18. Stress Tier Report Cache

Pre-computed LRS report responses cached for stress-tier API keys. Avoids expensive ElastiCache range queries during stress testing — the stress tier gets instant cached responses while production tiers always run the real query pipeline.

stress:report:summary:{api_key}

STRING (JSON) TTL: 2 hours
Cached LRS summary report response for a stress-tier key. Auto-seeded on first real query or manually via POST /admin/seed-stress-report.

stress:report:usage:{api_key}

STRING (JSON) TTL: 2 hours
Cached LRS usage report response for a stress-tier key. Auto-seeded on first real query or manually via POST /admin/seed-stress-report.

19. Translation Cache (Map Pins)

Caches translations from AWS Translate for Impact Map pin captions. Used when users view map pins in non-English languages — the pin caption text is translated on-the-fly and cached to avoid repeat API calls. This is the only remaining use of AWS Translate in the system (document translation uses the custom Bedrock-powered engine).

translate:{lang}:{text_hash}

STRING TTL: 30 days
Cached translation result from AWS Translate. Key is composed of the target language code and a hex hash of the source English text. Value is the translated text string. Once cached, subsequent requests for the same text+language combination are served from ElastiCache with no AWS Translate API call.
ComponentDescription
{lang}Target language code (e.g., ur, es, hi, ar)
{text_hash}Hex-encoded representation of the source English text

Example: translate:ur:46616d696c7920467265656420..."فیملی فریڈ - لیجر ہمیشہ کے لئے عبور ہوگیا"

Writer: POST /translate endpoint (on cache miss)

Reader: POST /translate endpoint (on cache hit — returns immediately)

Estimated Keys: ~100 pins × 11 non-English languages = ~1,100 keys maximum

20. Translation Engine State

Keys used by the custom Bedrock-powered document translation engine. Tracks active and completed jobs, per-pair progress, job history, idempotency deduplication, and daily spend caps. These keys provide real-time status for the /admin/translate/status endpoint and the dashboard SPA translation panel.

tx:job:{job_id}

HASH TTL: None (persistent)
FieldTypeDescription
statestringJob state: queued, running, succeeded, failed, cancelled
docsstring (JSON array)Document filenames being translated
langsstring (JSON array)Target language codes
submitted_atstring (ISO 8601)When the job was submitted
started_atstring (ISO 8601)When processing began
completed_atstring (ISO 8601)When processing finished
step_function_arnstringARN of the Step Function execution
progress:{doc}:{lang}stringPer-pair progress (dynamic fields, one per doc-language pair being processed)
Live job state for real-time status polling. The hash contains static fields (state, docs, langs, timestamps) plus dynamic progress:{doc}:{lang} fields that update as each pair completes. Status endpoint reads this first — falls back to Aurora only for aged-out completed jobs.

Writer: Translation admin handler (on submit), Step Function callbacks (on progress/completion)

Reader: GET /admin/translate/status/{job_id}, GET /dashboard/api/translate/history

Estimated Keys: ~50 jobs retained (all completed jobs persist until manual cleanup)

tx:active

LIST TTL: None
List of currently active (running) job IDs. Used to enforce the max 3 concurrent jobs limit. Jobs are added on start and removed on completion/failure/cancellation.

Writer: Translation admin handler (on job start/complete)

Reader: POST /admin/translate (concurrency check), GET /admin/translate/queue

tx:history

LIST TTL: None (capped at 200 entries)
Reverse-chronological list of completed job summaries. Each entry is a pipe-delimited string: {completed_at:ISO,doc_count:N,failed:N,job_id:ID,lang_count:N,state:STATE,succeeded:N}. Used by the history endpoint for fast listing without hitting Aurora. Capped at 200 entries — oldest trimmed on insert.

Writer: Finalize Lambda (on job completion)

Reader: GET /admin/translate/history, GET /dashboard/api/translate/history

tx:idempotency:{key}

STRING TTL: 24 hours
Idempotency deduplication for translation job submissions. Value is the job_id of the original submission. If a request arrives with the same X-Idempotency-Key header within 24 hours, the existing job_id is returned instead of creating a duplicate.

Writer: POST /admin/translate (on first submission with idempotency key)

Reader: POST /admin/translate (deduplication check)

autoops:bedrock:spend:daily

STRING (float) TTL: 24 hours (auto-resets daily)
Running total of Bedrock translation spend in USD for the current day. Incremented after each successful translation pair. When this value reaches $600, new translation jobs are blocked (soft safety cap). Auto-resets via TTL expiry — no manual intervention needed.

Writer: Translation worker (ECS Fargate task, after each pair)

Reader: POST /admin/translate (spend cap check), GET /admin/translate/health

Kill switch: Set autoops:bedrock:kill to 1 to halt all translation regardless of spend

21. Multi-Lingual Search Index

Stores pre-built full-text search indexes for all 32 technical documents across 12 languages (384 total documents). Each language has its own index key containing a JSON array of section entries (doc title, section heading, URL, and ~500 chars of content per section). Built nightly by the /admin/build-search-index endpoint and queried by the public /search endpoint. The search API reads the index matching the user's language, returning results with native-language titles, snippets, and URLs.

search:index:{lang}

STRING TTL: None (persistent, rebuilt nightly)
Per-language search index. Keys: search:index:en, search:index:es, search:index:pt, search:index:fr, search:index:de, search:index:ru, search:index:hi, search:index:ur, search:index:pa, search:index:ar, search:index:ja, search:index:zh. Each is a JSON-encoded array of SearchIndexEntry objects containing: doc_title, section (heading text), url (language-specific path), and content (plain text excerpt, max 500 chars).

Writer: POST /admin/build-search-index (admin endpoint, triggered by KCC build-search command or nightly sync job)

Reader: GET /search?q=term&lang=ja (public endpoint — reads search:index:{lang}, scores matches, returns top 20 results with native-language snippets)

Size: ~500 KB per language × 12 = ~6 MB total (~1,000+ sections per language)

Rebuild Time: ~30 seconds (fetches 384 docs from CloudFront across 12 languages, parses HTML, extracts text, stores 12 index keys)

search:index

STRING TTL: None (legacy, backward compatibility)
Legacy English-only search index. Maintained for backward compatibility — identical to search:index:en. Will be removed in a future version once all clients use the per-language keys.

22. AutoOps State

State keys used by the autonomous operations system (Layer 1–5). These keys track threat analysis results, self-heal counts, action logs, notification cooldowns, and weekly release notes for the subscriber newsletter.

autoops:threats:daily

STRING (JSON) TTL: None (overwritten every 5 min)
Current threat assessment from Bedrock analysis. JSON object with fields: severity, summary, patterns (array), recommendations (array), auto_actions (array). Rebuilt every 5 minutes by tbi-ops-bedrock-analyze Lambda. Empty/missing when infrastructure is quiet (analysis skipped).

Writer: tbi-ops-bedrock-analyze Lambda (every 5 min via EventBridge)

Reader: tbi-ops-digest Lambda (daily/weekly summaries), KCC threat commands

autoops:actions:log

SORTED SET TTL: None (persistent)
Chronological log of all autonomous actions taken. Score is Unix timestamp, member is a pipe-delimited string: action-type|severity|description. Used by the daily digest to summarize what AutoOps did in the last 24 hours.

Writer: All AutoOps Lambdas (on every action taken)

Reader: tbi-ops-digest Lambda

autoops:self-heal:count

STRING (integer) TTL: None (reset monthly)
Counter of self-heal actions taken this month. Incremented by tbi-ops-self-heal Lambda each time it restarts a task or force-deploys a service. Used in daily reports and threat analysis context.

autoops:last-digest

STRING (Unix timestamp) TTL: None
Timestamp of the last digest generation. Used to prevent duplicate digests and track operational cadence.

autoops:digest:daily

STRING (JSON) TTL: 24 hours
Today's operational digest generated by Bedrock. JSON with digest (narrative text), generated_at, and type fields. Overwritten each morning at 6 AM EST.

autoops:digest:weekly

STRING (JSON) TTL: 7 days
This week's "Week in Review" digest. Same structure as daily. Generated Monday at 7 AM EST. Also used as the source material for the subscriber newsletter.

report:text:{YYYY-MM-DD}

STRING (Plain Text) TTL: 30 days
Consolidated plain-text extraction of all session reports for a given date. Generated nightly by the sync job — fetches HTML reports from S3, strips tags, and concatenates all sessions into one text block. Used by the tbi-ops-digest Lambda as primary context for the weekly newsletter (last 7 days of reports fed to Bedrock). Typical size: 20–50 KB per day depending on session count.

Writer: trinity-beast-sync-job (nightly, backfills all dates from manifest)

Reader: tbi-ops-digest Lambda (weekly newsletter generation)

autoops:notify-cooldown:{severity}

STRING TTL: 1 hour
Notification deduplication. Set when a threat notification is sent for a given severity level (HIGH, CRITICAL). Prevents repeated emails for the same ongoing condition. Auto-expires after 1 hour, allowing the next notification through.

Writer: tbi-ops-notify Lambda (on notification send)

Reader: tbi-ops-bedrock-analyze Lambda (checks before invoking notify)

autoops:release-notes:week

LIST TTL: None (cleared after newsletter sends)
Accumulated release notes for the current week's newsletter. Each entry is a pipe-delimited string: {ISO-timestamp}|{note text}. Appended via KCC release-notes command at the end of each development session. Read by tbi-ops-digest Lambda on Monday morning and passed to Bedrock to generate the "What's New" section of the weekly subscriber newsletter. Cleared automatically after the newsletter sends successfully.

Writer: KCC release-notes command (RPUSH)

Reader: tbi-ops-digest Lambda (weekly newsletter pipeline)

Cleared by: tbi-ops-digest Lambda (after successful newsletter send) or KCC release-notes-clear command

23. Dashboard Authentication & Sessions

Keys used by the customer dashboard (/dashboard) for passwordless magic link authentication, session management, rate limiting, email change verification, and audit logging.

session:{sha256(token)}

STRING (JSON) TTL: 24h sliding
Active dashboard session. JSON object with fields: email, roles (array), created_at, last_seen, ip, user_agent, impersonated_by (set when admin is impersonating). TTL slides on every authenticated request. Key is the SHA-256 hash of the raw Bearer token — the raw token is never stored server-side.

Writer: ConfirmMagicLinkHandler (on successful magic link validation)

Reader: RequireSession middleware (every authenticated API call)

Deleted by: LogoutHandler, invalidateSessionsByEmail (on email change)

magic:{sha256(token)}

STRING (JSON) TTL: 15 minutes
Pending magic link token. JSON payload: email, requested_at, ip, user_agent. Consumed atomically via GETDEL on first use — cannot be replayed. Auto-expires after 15 minutes if unused.

Writer: RequestMagicLinkHandler (on magic link request)

Reader: ConfirmMagicLinkHandler (atomic GETDEL — single use)

ratelimit:magic:email:{email}

STRING (integer) TTL: 1 hour
Rate limit counter for magic link requests per email address. Max 3 requests per hour. Prevents brute-force enumeration and email spam.

ratelimit:magic:ip:{ip}

STRING (integer) TTL: 1 hour
Rate limit counter for magic link requests per IP address. Max 10 requests per hour. Prevents a single IP from flooding magic link requests across multiple email addresses.

email-change:{sha256(token)}

STRING (JSON) TTL: 30 minutes
Pending email change verification token. JSON payload: old_email, new_email, requested_at, ip. Consumed atomically via GETDEL when the user clicks the confirmation link. On confirmation, updates users.email in Aurora, updates Stripe customer email, and invalidates all sessions for the old email.

Writer: EmailChangeHandler (on email change request)

Reader: ConfirmEmailChangeHandler (atomic GETDEL — single use)

ratelimit:email-change:{email}

STRING (integer) TTL: 1 hour
Rate limit counter for email change requests. Max 3 per hour per account. Prevents abuse of the email change verification flow.

audit:dashboard:{email}

SORTED SET TTL: 90 days
Chronological audit trail of dashboard actions for a given account. Score is Unix millisecond timestamp, member is a descriptive string (e.g., login ip=1.2.3.4, api-key-revealed, email-changed from=old@x.com to=new@x.com). Max 500 entries — oldest trimmed on insert. Events logged: login, logout, magic-link-requested, api-key-revealed, billing-portal-opened, impersonation-start, impersonation-end, email-change-requested, email-changed, profile-updated.

Writer: All dashboard handlers (via auditLog() helper)

Reader: Admin support tools, future ticket history panel