Pastebin
Create expiring text shares with predictable access control, efficient reads and safe deletion.
Create expiring text shares with predictable access control, efficient reads and safe deletion. This worked design targets SDE-1; the scale figures below are exercise assumptions, not claims about a named company's implementation.
Clarify the prompt
| Ask the interviewer | Decision to record |
|---|---|
| Public, unlisted or private? | Unguessable URLs do not replace authorization for private pastes. |
| Maximum paste size and retention? | They determine inline versus object storage. |
| Can content change after creation? | Immutable pastes make caching and versions simpler. |
Requirements and scope
The core deliverable is: Create expiring text shares with predictable access control, efficient reads and safe deletion. The first design implements the APIs below and the state constraints in the data model. Agree the latency, freshness, retention and failure policy before adding infrastructure. Every successful acknowledgment must have an explicit meaning: accepted intent, committed state or completed external work. These are separate milestones.
Capacity and bottleneck reasoning
Assume one million new pastes/day at 10 KB average: 10 GB/day raw and about 300 GB for 30 days. At a 20:1 read/write ratio this is roughly 231 reads/s average; peak and hot links determine cache sizing.
Keep average and peak demand separate. Add replication, indexes, retries and safety headroom to raw arithmetic before selecting capacity. Load-test the busiest ownership key and recovery traffic as well as uniform happy-path throughput.
APIs and data model
- POST /pastes {text,visibility,expiresAt,requestKey} -> 201 id
- GET /pastes/{id} -> content, 404 or 410
- DELETE /pastes/{id} -> tombstoned; GET never extends retention
paste(paste_id PK, owner_id, object_key, visibility, expires_at, deleted_at, checksum)
Index(expires_at, paste_id); object key includes immutable version
creation(request_key UNIQUE, owner_id, payload_hash, paste_id)Authorize resource ownership at the API boundary; do not trust IDs or state supplied by a client. Bind retry identity to the caller and payload for mutating operations. Reject an incompatible replay instead of returning an unrelated stored result.
Component relationships
Read the diagram
Follow the labeled relationship panels; they are separate directed paths, not one global timeline.
Step-by-step design
1. Establish the authority
Validate size and retention before accepting content. Generate a random identifier, verify uniqueness and store a checksum. For large content upload an immutable object first, then publish metadata; sweep unpublished orphan objects.
2. Make retries and concurrent work safe
Resolve metadata and authorize before serving private content. Cache public immutable content with a TTL no longer than its remaining retention. Rate limit creation and hot reads independently.
3. Scale and recover the critical path
Deletion immediately changes authoritative metadata and invalidates public caches. Physical object cleanup is asynchronous. Expiry is enforced on reads even if the cleanup job is delayed.
Worked request and concurrency example
Paste P expires at 12:00. At 11:59:50 a public cache miss fetches it and receives at most ten seconds of freshness. At 12:00:01 the service refuses the paste even if its blob still exists. A cleanup retry can safely delete the same immutable object again. If P is private, every read checks the caller and the cached response must not be shared across owners.
Failure and recovery walkthrough
An object upload succeeds but the metadata transaction fails. The object remains unreferenced and is collected after a grace interval; it is never discoverable through the read API. Deletion must also address CDN copies and documented backup retention.
Read the diagram
This numbered trace follows one scenario; explain the durable evidence at each transition.
Deep dive: publication and deletion are different protocols
Begin with immutable text, one metadata database and optional blob storage. Choose a maximum byte size, explicit visibility and a retention ceiling. An acknowledged creation means published metadata refers to verified content; an acknowledged deletion means new authorized reads through the service are denied. Physical erasure, cached copies, browser downloads and backup retention have separate timelines. Do not promise that deleting a server row retracts text already downloaded.
Pin the access and expiry contract
| Visibility | Read authority | Cache policy for this exercise |
|---|---|---|
| Public | Published, not deleted and server time before expiry | Shared caching allowed only under the stated revocation bound |
| Unlisted | Same eligibility plus knowledge of the URL | Link possession is not a private ACL; prevent indexing where practical |
| Private | Current owner/share permission plus paste eligibility | No shared plaintext cache; reauthorize every new read |
The simple strict-revocation baseline sends all new reads through metadata authorization and does not serve public edge hits independently. It may cache immutable blob bytes behind that decision. A faster public-CDN variant accepts a bounded stale-serving interval or makes the edge validate current eligibility. Best-effort purge alone cannot establish immediate global denial when an edge is disconnected. At expiry, an edge response's freshness lifetime cannot outlast the remaining retention under the assumed clock/error policy; disable stale-on-error behavior for this contract. Browser cache headers and signed download URLs must fit the same stated bound.
Use Content-Type: text/plain, a safe disposition and escaping in the viewer. Rendering arbitrary submitted text through HTML insertion turns a sharing feature into a script execution surface. Limit bytes before buffering, request duration, creation rate and storage per owner. IDs reduce collision/discovery risk; they do not authorize a private read.
Publish verified bytes, then expose the pointer
For small bounded text, storing metadata and content in one database transaction is a useful first design. Blob storage is justified when payload sizes, streaming and retention costs make it worthwhile. The blob path introduces an explicit publication protocol:
creation(owner, request_key, fingerprint, state, paste_id, upload_generation)
paste(id, owner, object_key, checksum, visibility, expires_at, deleted_at)
cleanup(object_key, generation, not_before, state)
UNIQUE(owner, request_key)First claim the scoped creation identity and fingerprint. Allocate a unique object key for that upload generation; upload immutable bytes and verify length/checksum. Then lock/recheck the creation intent, ensure it is still eligible, and atomically publish metadata and the stored operation result. A request with changed text, visibility or expiry under the same key conflicts. A timeout after publication is resolved by that key, not a second paste.
The blob does not become readable merely because an upload succeeded. Keep objects inaccessible except through the intended authorized delivery path. Failed publication leaves a candidate orphan. A sweeper must arbitrate with publication: lock/transition the same intent to abandoned before collecting its object. A grace timer by itself is insufficient if a paused publisher can later install a pointer to deleted bytes. A stale uploader cannot publish an abandoned generation; retry creates a new generation through the existing creation identity under policy.
Read and delete against authoritative state
At each new read decision, check current policy, deletion and now < expires_at, then resolve the immutable object. If deletion commits after a read was authorized, that in-flight stream may already contain bytes. State that boundary and keep authorization-to-stream time bounded. A long-lived direct object URL bypasses later service checks until its own expiry, so it changes the deletion guarantee.
Read the diagram
Metadata is tombstoned for paste P → Cleanup intent commits with the tombstone → Object deletion succeeds; its reply is lost → Worker retries the same immutable object key → P remains denied throughout cleanup
Delete commits a tombstone and cleanup/outbox intent together. Reads deny immediately under this baseline, even if cleanup is unavailable. Cleanup deletes only the exact immutable object generation and records completion; a lost object-delete response can be reconciled/retried without reviving metadata. Avoid recycling identifiers/object keys while old cleanup jobs or links can still exist. Versioned storage may require deleting retained object versions under a defined policy; removing a current pointer does not prove every byte is erased.
Work the crash boundaries
| Crash or race | Evidence retained | Recovery |
|---|---|---|
| Upload done, publication absent | Creation intent and immutable object | Resume eligible publication or atomically abandon and collect |
| Publication committed, response lost | Stored request result | Return original paste identity |
| Tombstone committed, queue unavailable | Cleanup outbox intent | Republish same cleanup identity |
| Object removed, worker reply lost | Tombstone still denies reads | Retry exact object generation |
| Expiry job delayed | Metadata expiry remains authoritative | Deny reads; collect later |
For one million 10 KB pastes/day, raw additions are about 10 GB/day in decimal units; thirty days is about 300 GB before indexes, replicas and versions. If only 1% of uploads are abandoned, that is still about 100 MB/day needing collection. Track unpublished bytes, oldest cleanup intent, expired-read rejections, authorization latency and the hottest paste independently. A viral paste can dominate egress while average request rate remains small.
Paste assessment: separate denial from erasure
Question: A blob upload succeeded, but the metadata transaction failed. May the service return the object URL as successful creation?
Show answer and explanation
Answer: No under this contract. Creation success requires published metadata and its saved result. Resolve the original creation intent or abandon the upload safely; an object alone is not a published paste.
Question: Delete acknowledged while a disconnected CDN still holds a fresh public response. Does best-effort invalidation prove immediate global denial?
Show answer and explanation
Answer: No. Use the strict metadata-gated baseline or declare the CDN revocation bound and validation policy. Previously delivered bytes cannot be recalled.
Question: Can an orphan sweeper delete an old upload solely because its age exceeds a grace interval?
Show answer and explanation
Answer: Not if a paused publisher can still commit its pointer. Coordinate abandonment/publication through the same generation and authority before deleting bytes.
Score one point for immutable publication identity, visibility/authorization, expiry and cache contract, tombstone/cleanup recovery and safe orphan arbitration. Then add direct signed downloads and identify exactly which revocation promise changes. Review Security and Tenant Isolation and Idempotency for the shared mechanisms.
Decisions and alternatives
| Decision | Trade-off |
|---|---|
| Alternative 1 | Inline database text reduces coordination for small pastes; object storage avoids large database rows and supports streaming. Choose a threshold from measured payload and backup cost. |
| Alternative 2 | Unlisted random IDs reduce accidental discovery but links can leak. Private access needs identity checks and careful cache keys. |
Operational contract
Measure read latency, hot-key concentration, expired-read rejections, orphan bytes and cleanup age. Enforce upload quotas and content-size limits. Use text/plain and safe browser rendering so shared text is not executed as HTML.
Choose alert thresholds from the agreed user-facing objective. Assign an owner for stuck work and a replay/repair procedure that preserves the original business identity. Bound queue depth, concurrency and recovery throughput so an outage does not produce an uncontrolled catch-up burst.
Foundation, senior and staff depth
- Foundation: Explain immutable content, visibility and metadata-gated expiry.
- Senior: Arbitrate publication against orphan collection and recover tombstone cleanup.
- Staff: Defend CDN/signed-link revocation bounds and measured retention/egress budgets.
Practice before revealing the answer
Spend 45 minutes: 5 clarifying scope, 7 on capacity/APIs/state, 12 on the first architecture, 15 on the concurrency and failure examples, and 6 on trade-offs and operations. Draw your own design before comparing it with this chapter.
Question: Is a long random paste ID enough to make a private paste secure?
Show answer and explanation
Answer: No. Anyone who obtains the link could read it unless the service authorizes access. Enforce the owner or sharing ACL before retrieving private content and avoid public caching of that response.
Verification and rollout
Crash after upload, publication, tombstone and physical deletion. Race abandonment with delayed publication, reject changed retry payloads and verify reads at exact expiry. Test disconnected-cache policy separately from authoritative denial.
Primary technical reference
Official documentation for the mechanism used in this exercise. This lesson is an original interview design, not a description of undisclosed company internals.
Related study
Before this design, review these mechanisms and identify which owns the critical state transition:
Use the Interview Playbook to adapt the depth and timing, then return to the question breakdown overview.
Is a long random paste ID enough to make a private paste secure?
Your design draft
Clarify assumptions, explain your approach, and test the difficult cases. Save your draft, then compare it with the study notes.
Self-review checklist
Self-guided practice. Automated AI feedback and code execution are not connected.