core PK: id 7 required 2 unique

Description

Stores FCM/APNs push notification tokens registered by user devices. Each record ties a physical device to a user account, enabling targeted push delivery. Tokens are platform-specific, rotate on app reinstall or OS token refresh, and must be deregistered on logout to prevent ghost deliveries.

12
Attributes
5
Indexes
6
Validation Rules
10
CRUD Operations

Data Structure

Name Type Description Constraints
id uuid Primary key — surrogate UUID generated server-side on token registration
PKrequiredunique
user_id uuid Foreign key to users table — owner of the device
required
token string Raw FCM registration token (Android) or APNs device token (iOS) as returned by the platform SDK. Max 4096 chars to accommodate FCM v1 token lengths.
requiredunique
platform enum Mobile OS platform that generated this token
required
app_version string Semantic version of the Meander app at time of registration (e.g. '1.4.2'). Used to detect stale tokens from very old app versions.
-
device_model string Device model string reported by Flutter (e.g. 'iPhone 15 Pro', 'Pixel 8'). Used for diagnostics and analytics only, never for routing logic.
-
os_version string Operating system version string (e.g. 'iOS 17.4', 'Android 14'). Helps identify platform-specific FCM/APNs issues.
-
is_active boolean Whether this token should receive push notifications. Set to false on logout, token rotation, or delivery failure (InvalidRegistration / NotRegistered errors from gateway).
required
last_used_at datetime Timestamp of the most recent successful push delivery to this token. Used by cleanup jobs to identify and deactivate abandoned tokens.
-
failure_count integer Consecutive delivery failure count. Auto-incremented by push-notification-gateway on each failed delivery attempt. Token deactivated when threshold exceeded.
required
registered_at datetime Timestamp when the token was first registered. Set on INSERT, never updated.
required
deregistered_at datetime Timestamp when the token was explicitly deregistered (logout, token refresh). NULL while active.
-

Database Indexes

idx_device_tokens_token_unique
btree unique

Columns: token

idx_device_tokens_user_id
btree

Columns: user_id

idx_device_tokens_user_active
btree

Columns: user_id, is_active

idx_device_tokens_platform_active
btree

Columns: platform, is_active

idx_device_tokens_last_used_at
btree

Columns: last_used_at

Validation Rules

token_not_empty error

Validation failed

platform_enum_valid error

Validation failed

user_id_exists error

Validation failed

token_max_length error

Validation failed

app_version_semver_format warning

Validation failed

failure_count_non_negative error

Validation failed

Business Rules

one_active_token_per_device
on_create

A single physical device token value must be globally unique. If a token arrives that already exists for a different user_id (device transferred or shared), the old record must be deactivated before the new registration is saved. The unique index on `token` enforces this at the DB level; device-token-registration-service handles the upsert logic.

deactivate_on_logout
on_delete

When a user logs out from the mobile app, all device tokens for that user on that device must be immediately set to is_active=false and deregistered_at recorded. This prevents push notifications being delivered to a device after the user has signed out.

auto_deactivate_on_gateway_rejection
always

When push-notification-gateway receives an InvalidRegistration or NotRegistered error from FCM/APNs for a specific token, it must immediately set that token's is_active=false and increment failure_count. This prevents repeated failed deliveries and wasted API calls.

failure_threshold_deactivation
on_update

If failure_count reaches 5 for any token, the token is permanently deactivated (is_active=false) regardless of error type. This guards against transient gateway errors accumulating and marking healthy tokens as dead. Threshold configurable via environment variable.

notification_only_to_active_tokens
always

push-notification-service must query device_tokens WHERE user_id = ? AND is_active = true before dispatching any push. Sending to inactive tokens is prohibited at the service layer, not just the gateway layer.

token_rotation_upsert
on_create

Flutter's Firebase Messaging SDK may refresh the FCM token without user action. The app must send the new token to device-token-registration-service on each app foreground. The service performs an upsert: if the user already has an active token on this platform, update the token value rather than creating a duplicate record.

multi_device_support
always

A single user may have multiple active tokens (one per device they are logged in on). All active tokens for the user must receive push notifications — there is no 'primary device' concept. push-notification-service must fan out to all active tokens for the target user.

Storage Configuration

Storage Type
primary_table
Location
main_db
Partitioning
No Partitioning
Retention
archive_after_1year