system-design
System design
A design is a set of components plus an answer to "what happens when this one fails or gets ten times the load?". Worked designs (URL shortener, notifications, real-time chat, web crawler, file vault, checkout, recovery choices, sharding and failover) are in DESIGNS.md. Draw the request path, then walk each box and arrow with three questions: what does it own, what does it do when the next hop is slow or down, and which number tells you it's healthy. Start with the smallest design that meets today's targets, write the targets down (requests per second, p99 latency, data size, freshness), and add a component only when a target or a failure mode needs it.
Apply only the routes and checks for the selected job. Read a linked skill's named file from its installed folder when available, or from the linked source. Report an unavailable required reference instead of inventing it. [skill-authoring, DISTRIBUTION.md#composing-skills]
The trusted boundary
- Clients never talk to the database as an admin. An application service holds the credentials on infrastructure you control and enforces authentication, authorization per operation, input validation, size limits, rate limits and audit. It also gives clients a stable API while the schema changes underneath.
- A managed data API is still a boundary. If the browser talks to a hosted database API (Supabase's REST API), the boundary is the row-level policies on every exposed table plus the anonymous key's limited role; the service-role key stays on servers (the
secure-codingskill). - The service is now a dependency. Bound its database pool (a connection per request exhausts the database), give every outbound call a timeout, and make retries bounded and idempotent so they don't amplify an outage. Run it on a private network with a least-privilege database role and secrets from a manager or workload identity.
- Clients submit intent, not rows. "Publish this text to followers" is a command; the server derives the author from the session, validates visibility and limits, assigns a stable ID, and returns the canonical record. Success means stored, not yet visible to everyone.
- Decide scarce resources in the database, never from a cache. Reserving the last copy, seat or unit is a conditional write (
update copies set reserved_by = $1 where id = $2 and reserved_by is null, then check the row count) or a unique constraint, so two concurrent requests can't both win. The cache may say "available" after someone else took it; the write path reads authoritative state. - Relationships that are queried from both ends get their own table (follows as an edge table indexed both ways), not a JSON array inside a row.