A user settings service manages configuration that affects application behavior — email address, two-factor auth state, timezone, connected integrations. Unlike preferences (which are behavioral choices), settings often have strict types, cross-cutting validation rules, and must survive schema evolution as the product grows.
Requirements
Functional
- Store typed settings grouped by feature namespace (account, security, integrations).
- Validate values against a versioned schema on write.
- Migrate existing settings when a schema version changes.
- Support bulk export of all settings for portability (GDPR data download).
- Provide per-namespace read endpoints for feature teams.
Non-Functional
- Schema validation under 5 ms per write.
- Bulk export completed within 2 seconds for typical users.
- Zero downtime schema migrations with backward compatibility.
Data Model
settings_schema(
namespace VARCHAR(100),
key VARCHAR(200),
schema_version INT,
data_type ENUM(bool, int, string, json),
constraints JSONB, -- min/max, regex, enum values
default_value TEXT,
deprecated_at TIMESTAMPTZ,
PRIMARY KEY (namespace, key, schema_version)
)
user_settings(
user_id BIGINT,
namespace VARCHAR(100),
key VARCHAR(200),
value TEXT,
schema_version INT,
updated_at TIMESTAMPTZ,
PRIMARY KEY (user_id, namespace, key)
)
settings_changelog(
id BIGSERIAL PRIMARY KEY,
user_id BIGINT,
namespace VARCHAR(100),
key VARCHAR(200),
old_value TEXT,
new_value TEXT,
changed_by BIGINT,
changed_at TIMESTAMPTZ
)
Core Algorithms
Schema Validation
On every write the service looks up the active schema version for the given namespace/key pair. It deserializes the constraint JSONB into a validator object and runs the value through type coercion and constraint checks (range, pattern, enum membership). Validators are compiled once per schema version and cached in a concurrent hash map, so repeated validation of the same key is O(1) hash lookup plus a lightweight check.
Versioned Settings Migration
When a schema version increments, the service registers a migration function for each affected key. Migration is lazy: when a user setting is read and its stored schema_version is below the current version, the service applies chained migration functions (v1->v2->v3) to produce the current-version value, then writes the migrated value back. This avoids expensive bulk backfills while ensuring all reads return schema-current values. Migration functions are pure transformations registered in code and tested independently.
Bulk Export
The export endpoint streams all rows for a given user_id from the user_settings table, groups them by namespace, and serializes to a structured JSON document. For users with thousands of settings (e.g., many integrations), the query uses a server-side cursor with page size 500 to avoid large result set memory pressure. The export includes human-readable key names and schema descriptions sourced from the in-memory schema map.
API Design
GET /v1/settings/{namespace}— returns all settings in a namespace for the caller.GET /v1/settings/{namespace}/{key}— single setting with current value and schema metadata.PUT /v1/settings/{namespace}/{key}— set a value; validates against current schema version.DELETE /v1/settings/{namespace}/{key}— reset to schema default.GET /v1/settings/export— full settings export as JSON; triggers async job for large accounts.GET /v1/settings/schema/{namespace}— returns current schema for a namespace; used by UI to build dynamic forms.
Scalability and Fault Tolerance
Namespacing lets feature teams own their schema independently and deploy schema changes without coordinating with other teams. A settings registry service holds the canonical schema map and exposes it over an internal gRPC endpoint. Feature services register schemas at deploy time. The main settings service polls the registry every 30 seconds and hot-reloads changed schemas without restart.
For write-heavy operations (e.g., bulk integration sync writing dozens of settings atomically), the service wraps the batch in a single DB transaction and publishes a single settings.bulk_updated event rather than one event per key. Downstream consumers receive the batch as a diff and apply it atomically.
Interview Tips
- Distinguish settings (configuring the system) from preferences (personalizing the experience) — interviewers sometimes conflate them.
- Discuss how deprecated keys are handled: the service accepts writes to deprecated keys with a warning header but stops including them in exports after a sunset date.
- Mention that bulk export is a natural GDPR portability artifact; the same endpoint can power account migration to another provider.
- For migration, emphasize testing each migration function in isolation with property-based tests to avoid data corruption at scale.
See also: Scale AI Interview Guide 2026: Data Infrastructure, RLHF Pipelines, and ML Engineering
See also: Atlassian Interview Guide