Design the server side of a Slack-style chat backend for a 250,000-daily-active workspace, and implement the ordering layer it depends on. Your design doc must justify every component with a number derived from your own capacity model, and your code must produce a strictly increasing per-channel sequence that survives an owner crash and a simulated partition without ever issuing the same number twice. Treat the client as out of scope: it appears only as a cursor and an idempotency key. Push notifications are also out of scope — hand them off at a named boundary and say what contract you hand over.
Start with the capacity model, not the architecture. Until you have written down deliveries/sec, every component you add is unmotivated and you will not be able to defend it in the doc.
For the sequencer, simulate the store rather than running a real database: an in-memory map with an injected fence check is enough to test every interesting case, and it makes the partition test a two-line setup instead of a container orchestration exercise. Make the fence check live in the store, not the allocator — putting it in the allocator means an old owner validates its own authority, which is exactly the bug you are testing for.
The fan-out benchmark is easy to get wrong by accidentally measuring your mock. Encode a realistic payload (400 or so bytes of JSON) and actually write to a discarding sink, so serialisation cost is real. If the naive and optimised versions come out close, check whether your mock registry is returning a pre-built list and skipping the membership scan the naive version is supposed to pay for.
For the two-cursor tests, write them as the two failure stories from challenge 6 before you write the implementation — one test for the blind laptop, one for the badge that never clears. They are much easier to reason about as scenarios than as assertions.
On scope: it is a stronger doc if you explicitly say what you are not designing. Name the push-notification boundary, name the search index as a separate system, and say what contract each gets.
$ python capacity.py --dau 250000 --peak-mult 5 --avg-channel 40 peak connected sockets 150,000 sends/sec avg / peak 58 / 290 fanout multiplier 16.0 x DELIVERIES/sec at peak 4,630 storage/year (x3) 2.2 TB gateway nodes (HA) 6 gateway fleet / month $420 ~ INR 27,930
$ go test ./seq/... -run Handover -count=1 === RUN TestNoDuplicatesAcrossHandovers 100000 assignments, 3 handovers, 2 abandoned blocks max seq 101873 duplicates 0 holes 1127 (expected: block remainders) === RUN TestFencedOwnerIsRefused old owner fence=118 issued 412 writes after losing lease accepted by store: 0 --- PASS: TestNoDuplicatesAcrossHandovers (0.84s) --- PASS: TestFencedOwnerIsRefused (0.11s)
$ go test -bench Fanout -benchtime=200x ./fanout/... BenchmarkFanout/naive/1000 1 2.41 ms/op 1000 encodes BenchmarkFanout/naive/30000 1 72.60 ms/op 30000 encodes BenchmarkFanout/batched/1000 1 0.31 ms/op 1 encode 12 rpcs BenchmarkFanout/batched/30000 1 0.36 ms/op 1 encode 12 rpcs ^ flat: the goal
$ psql -f verify_pagination.sql page | rows_read | duplicates | skipped ------+------------+------------+--------- 1 | 50 | 0 | 0 4000 | 50 | 0 | 0 (insert 200 messages mid-scroll, re-run: duplicates 0, skipped 0)
Implement thread cursors on top of the channel read model and show that a user’s total badge stays a bounded number of queries when they belong to 400 channels containing 9,000 threads, of which they are subscribed to 12.
Add crypto-shredding for regulatory erasure: per-message wrapped keys, a shred operation, and a test proving that after shredding, keyset cursors into the affected range still return the correct number of rows with unchanged sequence numbers.
Implement the client-side reorder buffer with a backfill request, and write a fuzz test that delivers a 500-message window in random order with 5 percent duplicates and 2 percent permanent holes, asserting the m1_render order is always correct and the channel never stalls.
Add a second region and implement channel-ownership rebalancing that moves 100,000 channels between regions without exceeding your stated per-channel failover budget for any single channel, and graph the send-error rate through the migration.
Model data residency: make channel ownership pin to a region at creation time based on the workspace’s declared jurisdiction, then work out what happens to a channel whose members span two jurisdictions and write up which of the three plausible answers you would defend to a regulator.