Skip to content

Redis Keys

Inventory of every Redis key pattern the backend reads or writes. Keys are grouped by domain. Patterns use {var} for runtime-substituted values.

This list is reconstructed by auditing backend/internal/services/redis_service.go and every caller. If you add a new key, add it here too — drift makes incident response painful.

Asynq queues

The background-task queues used by hibiken/asynq (asynq:* keys, including queue lists, scheduled sets, processing zsets, and unique-task locks) are managed internally by the library. They are not enumerated below — treat them as opaque. The library's own dashboard tools (asynq stats) are the right inspection path.

Authentication & sessions

Key Pattern Type TTL Purpose Set By Read By
refresh_token:{token} STRING refresh token expiry Maps a refresh-token string to its owning user_id. Deleted on logout. services/session_service.go services/session_service.go
register_device:{fingerprint} STRING 30 days Count of registrations from a device fingerprint. Throttles bulk-account abuse. services/auth_service.go services/auth_service.go
webauthn:reg:{user_id} STRING (JSON) 5 min WebAuthn registration session data (challenge + options). handlers/auth_handler.go handlers/auth_handler.go
webauthn:login:{user_id} STRING (JSON) 5 min WebAuthn login session data (challenge + options). handlers/auth_handler.go handlers/auth_handler.go
apple_public_keys STRING (JSON) 24 h Cached Apple JWKS used to verify Sign-in-with-Apple identity tokens. services/auth_service.go services/auth_service.go
user:privacy:{user_id} STRING ("0"/"1") 24 h Cached is_location_shared flag — avoids a DB hit on every location update. Invalidated when user toggles sharing. services/friend_service.go services/friend_service.go, services/auth_service.go (invalidate)

Rate limiting & abuse

All rate-limit keys are written by the Lua INCR + EXPIRE script in services/redis_service.go::RateLimit. The shape is {prefix}:{identifier} where identifier is usually the client IP.

Key Pattern Type TTL Purpose Set By Read By
register_ip:{ip} INT 1 h Registration attempts per IP (default limit: 5/h). middleware/rate_limiter.go middleware/rate_limiter.go
login_ip:{ip} INT 15 min Login attempts per IP (default limit: 10/15 min). middleware/rate_limiter.go middleware/rate_limiter.go
api_ip:{ip} INT 1 min Baseline API requests per IP on /api/v1/* (limit: 600/min). middleware/rate_limiter.go middleware/rate_limiter.go
reset_password_ip:{ip} INT 1 h Password-reset token attempts per IP (limit: 5/h, prevents brute force). middleware/rate_limiter.go middleware/rate_limiter.go
places:ratelimit:{user_id} INT per-user window Throttles Google Places API calls per user. services/places_service.go services/places_service.go
blocked_ip:{ip} STRING (blocked:{reason}) configurable Hard-blocked IPs (set by IP-blocker middleware). middleware/ip_blocker.go middleware/ip_blocker.go
violations:{ip} INT configurable Cumulative violation counter — graduated response before hard-blocking. middleware/ip_blocker.go middleware/ip_blocker.go

Presence & active location

Key Pattern Type TTL Purpose Set By Read By
presence:{user_id} STRING ("1") 3 min Heartbeat marker — user is online if key exists. Refreshed by client ping. services/presence_service.go services/chat_service.go, services/friend_service.go (via MGet)
active_location:{user_id} STRING (JSON) configurable User's currently-active shared location (the live pin). Deleted when user toggles off. services/presence_service.go services/presence_service.go, services/friend_service.go (via MGet)
user:location:{user_id} STRING (JSON: {lat, lng, updated_at, arrived_at}) 24 h Latest location + stay-duration tracking. Backbone of nearby-friends discovery. services/friend_service.go services/friend_service.go, services/discovery_service.go, sim workers

Chat & messaging

Key Pattern Type TTL Purpose Set By Read By
chat:messages:{chat_room_id} LIST 24 h Cached recent messages for a chat room (trimmed to 100). Read-through on hit, DB fallback on miss. services/chat_service.go services/chat_service.go
chat:online:{chat_room_id}:{user_id} STRING 1 h Marker that {user_id} is currently active in {chat_room_id}. Deleted on offline. services/chat_service.go services/chat_service.go
chat:event:{chat_room_id} Pub/Sub channel n/a Cross-pod chat fanout channel. Envelope {opid, xuid?, p}: opid is the publishing pod's UUID (subscriber drops own echoes), xuid skips a UserID on receive, p is the raw WS payload. websocket.Hub.publishRemote (internal/websocket/hub.go) websocket.Hub.runSubscriber (PSUBSCRIBE chat:event:* on every pod)

Friends

Key Pattern Type TTL Purpose Set By Read By
user:friends:{user_id} STRING (JSON) friendListCacheTTL Cached accepted-friend list for a user. Invalidated on accept/remove. services/friend_service.go services/friend_service.go

Geo discovery

Key Pattern Type TTL Purpose Set By Read By
events:geo GEO (ZSET) none Geospatial index of all event locations. Backs GetNearbyEventIDs via GEORADIUS. services/redis_service.go::AddEventLocation(s) services/redis_service.go::GetNearbyEventIDs

H3 indexing

H3 hex indices are stored in Postgres (locations.h3_index), not Redis. Redis only holds the raw lat/lng geo set above. H3-based clustering happens in SQL inside services/discovery_service.go.

Utility caches

Key Pattern Type TTL Purpose Set By Read By
link-preview:{sha256(url)} STRING (JSON) configurable OpenGraph metadata cache for outbound URL previews. Keyed by SHA-256 of the URL. handlers/link_preview_handler.go handlers/link_preview_handler.go

Scheduler (distributed task queue)

The custom Redis-backed scheduler in backend/internal/scheduler runs on every backend instance. Constants live in internal/scheduler/client.go and internal/scheduler/scheduler.go.

Key Pattern Type TTL Purpose Set By Read By
tasks:scheduled ZSET none Scheduled tasks. Score = epoch timestamp, member = task_id. scheduler/client.go::ScheduleTask scheduler leader
tasks:payload HASH none Task payloads. Field = task_id, value = JSON. scheduler/client.go scheduler workers
tasks:queue:default LIST none Ready queue — tasks waiting to be picked up by a worker. scheduler leader scheduler workers (BRPOPLPUSH)
tasks:processing LIST none Reliable processing queue — tasks currently executing. Populated atomically with the LIST pop. scheduler workers reclaimer (on worker crash)
tasks:active:{task_id} STRING task lease Active lock / heartbeat for a running task. Reclaimer uses absence to detect stalled workers. scheduler/worker.go scheduler/reclaimer.go
scheduler:leader STRING leader lease Leader-election lock. Only the holder polls tasks:scheduled. Prevents duplicate enqueues. scheduler/scheduler.go all backend instances

Cleanup keys

Used by the test-data seeder (cmd/test/data/main.go) to wipe state between simulation runs:

presence:*
user:location:*
active_location:*
user:friends:*
user:privacy:*

If you add a new user-scoped Redis key, add its prefix to that cleanup list too — otherwise stale data leaks between test runs.

Adding a new key

  1. Define the key shape in the service that owns it. Prefer domain:purpose:{id} (lowercase, colon-separated).
  2. Document it in the table above with type, TTL, purpose, writers, readers.
  3. If it's user-scoped and ephemeral, add the prefix to the simulation cleanup list.
  4. If it's a rate-limit key, route it through middleware/rate_limiter.go so the Lua atomic INCR script is used.