Collaborative Playlist · Engineering synthesis

Centralized Production Architecture

Keep playlist membership, ordering, and version changes in one transactional boundary. Route every mutation for a playlist through one logical owner, publish committed changes through a transactional outbox, and scale reads and live delivery independently.

Write boundaryOne playlist
AuthorityRelational primary
Live deliveryKafka + WebSocket
Partition keyplaylist_id

Complete system map

Command and read path

Web / mobile client→API gateway→Playlist service→Owner partition
Owner partition↔SQL primary shard→Read replica→Redis snapshot cache

Committed event path

SQL outbox→Outbox publisher→Kafka by playlist_id→Fanout workers
Kafka→WebSocket gateways→Subscribed clients+Cache projector

Media boundary

Playlist service→ media_idCatalog service→Track metadata→Audio CDN

The playlist domain stores media references and ordering. Catalog metadata and audio delivery remain separate services.

Components and responsibilities

ComponentResponsibilityWhy it exists
API gatewayTLS, authentication, quotas, request IDsKeeps edge policy separate from playlist logic.
Playlist serviceReads, command validation, routing, response assemblyStateless instances scale request processing horizontally.
Owner partitionSerialize active mutations for one playlistOne commit order makes move and delete races deterministic.
SQL primary shardCanonical playlists, membership, entries, versions, mutations, outboxOne transaction preserves authorization, order, deduplication, and publication intent.
RedisPopular public snapshots and short-lived presenceRead-heavy traffic avoids repeated SQL work; durable truth remains in SQL.
KafkaOrdered committed events by playlist IDFanout, cache projection, audit export, and analytics scale independently.
WebSocket gatewayPersistent connections and playlist subscriptionsConnection state stays outside command servers.
Catalog serviceTrack availability and display metadataPlaylist membership survives catalog metadata changes.

Relational source of truth

playlist(id PK, owner_id, title, visibility, version, shard_key)playlist_member(playlist_id, user_id, role, membership_epoch)playlist_entry(playlist_id, entry_id, position_key, media_id, added_by)playlist_mutation(playlist_id, version, operation_id UNIQUE, actor_id, payload)outbox(event_id PK, playlist_id, version, payload, published_at)

Shard and cluster rows by playlist_id. Index entries by (playlist_id, position_key) and members by (playlist_id, user_id). The mutation log uses (playlist_id, version) for reconnect replay.

Open playlist interaction

  1. The gateway authenticates the caller and forwards the playlist ID.
  2. The playlist service checks Redis for a versioned snapshot of a popular public playlist.
  3. A miss reads playlist metadata, membership, and one ordered entry page from SQL.
  4. The service resolves bounded track metadata through the catalog service and returns entries plus playlist version.
  5. The client opens a WebSocket subscription with its last applied version.
  6. The gateway replays later mutation events or directs the client to refresh a snapshot when the retained log has a gap.

Mutation interaction

  1. The client applies a local add, remove, or move and sends operation_id, base_version, and stable entry anchors.
  2. The playlist service hashes playlist_id to the owner partition.
  3. The owner authenticates the actor, reads membership, and checks the unique operation ID.
  4. Inside one SQL transaction, lock the playlist row or compare its version, validate anchors, update the entry, and increment the playlist version.
  5. The same transaction appends the canonical mutation and an outbox event.
  6. Commit establishes the authoritative result; the service acknowledges the sender with the accepted position and version.
  7. The outbox publisher sends the event to Kafka. Fanout workers deliver it to WebSocket gateways and the cache projector advances Redis.
  8. Clients apply events in version order, detect gaps, and reconcile pending optimistic operations.

Why a relational database

Transactional invariantMembership authorization, entry mutation, version increment, deduplication record, and outbox event commit together.
Access patternsPoint reads by playlist ID and ordered range scans by position key map directly to indexes.
Bounded aggregateA playlist is a natural transaction and partition boundary with modest row counts.
Operational recoveryBackups, replicas, constraints, and transactional logs provide a clear durable authority.

A document store simplifies retrieval of small playlists but creates large-document rewrites, concurrency control, and pagination limits. A pure event store supports history well but requires a materialized list and additional transaction handling for membership and deduplication.

Sharding and hot playlists

  • Place every canonical row for one playlist on the shard selected by hash(playlist_id); mutations stay single-shard.
  • Partition Kafka by playlist_id so downstream consumers observe the SQL commit order.
  • A popular playlist creates a hot read key, handled through Redis snapshots, read replicas, and CDN-safe public metadata.
  • A highly active collaborative playlist creates a hot write partition. Queue its commands at one owner, batch fanout, and enforce per-playlist limits.
  • Large playlists use cursor pagination over (position_key, entry_id); clients subscribe from the returned playlist version.

Failure and recovery

FailureSystem response
Lost mutation acknowledgementThe retry reuses operation_id and returns the committed result.
Owner process stopsRouting assigns a replacement, which loads the current SQL version and resumes serialization.
Kafka unavailableThe SQL transaction commits with its outbox row; publication resumes later.
WebSocket disconnectsThe client reconnects from its last version and receives replay or a fresh snapshot.
Redis unavailableReads fall through to SQL under circuit breaking and request coalescing.
Read replica lagsCollaborative reads use the primary or require a replica version at least as new as the client cursor.

Requirements that change the design

New requirementArchitecture change
Sustained offline editing and device-held authorityAdopt the P2P/local-first architecture and a move-aware list CRDT.
Millions of passive followersProject versioned public snapshots to object storage and CDN distribution.
Strict synchronous moderationAdd policy checks inside the command path before the SQL commit.
Cross-region writes to one playlistChoose one home-region leader or adopt a multi-leader CRDT protocol with explicit conflict semantics.

Architecture recall

  1. Which rows commit in one transaction?
  2. Why is Kafka downstream of a SQL outbox?
  3. Which component owns client connections?
  4. How does a reconnecting client repair a version gap?
  5. What creates a hot write partition?
  6. Which requirement selects the P2P branch?