codecall 1.2.3 → 1.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (23) hide show
  1. package/README.md +104 -207
  2. package/package.json +1 -1
  3. package/plugins/codecall/.claude-plugin/plugin.json +6 -2
  4. package/plugins/codecall/.codex-plugin/plugin.json +13 -4
  5. package/plugins/codecall/agents/codecall-planner.md +6 -1
  6. package/plugins/codecall/skills/codecall/SKILL.md +96 -95
  7. package/plugins/codecall/skills/codecall/references/backend-map/api.md +113 -0
  8. package/plugins/codecall/skills/codecall/references/backend-map/architecture.md +65 -0
  9. package/plugins/codecall/skills/codecall/references/backend-map/async.md +81 -0
  10. package/plugins/codecall/skills/codecall/references/backend-map/auth.md +97 -0
  11. package/plugins/codecall/skills/codecall/references/backend-map/caching.md +65 -0
  12. package/plugins/codecall/skills/codecall/references/backend-map/data.md +144 -0
  13. package/plugins/codecall/skills/codecall/references/backend-map/http.md +97 -0
  14. package/plugins/codecall/skills/codecall/references/backend-map/index.md +165 -0
  15. package/plugins/codecall/skills/codecall/references/backend-map/observability.md +65 -0
  16. package/plugins/codecall/skills/codecall/references/backend-map/ops.md +129 -0
  17. package/plugins/codecall/skills/codecall/references/backend-map/quality.md +81 -0
  18. package/plugins/codecall/skills/codecall/references/backend-map/realtime.md +65 -0
  19. package/plugins/codecall/skills/codecall/references/backend-map/reliability.md +65 -0
  20. package/plugins/codecall/skills/codecall/references/backend-map/scaling.md +81 -0
  21. package/plugins/codecall/skills/codecall/references/backend-map/security.md +97 -0
  22. package/plugins/codecall/skills/codecall/references/backend-map/storage.md +81 -0
  23. package/plugins/codecall/skills/codecall/references/receipt-template.html +71 -0
@@ -0,0 +1,129 @@
1
+ # Configuration and delivery
2
+
3
+ ## config-management
4
+
5
+ - **Name:** Configuration from the environment
6
+ - **Requires:** none
7
+ - **Signals:** `process.env`, `os.environ`, `os.Getenv(`, `BaseSettings`, `dotenv`, `@ConfigurationProperties`
8
+ - **Idea:** Values that differ between deploys, like database URLs, ports and feature flags, are read from the environment at startup, so one build runs unchanged in dev, staging and production.
9
+ - **Misconceptions:**
10
+ - Reading `process.env.X` wherever it is needed is fine; parse and validate once at startup so a missing value fails the boot, not a request later.
11
+ - Config and code constants are the same; values that never change between deploys belong in code, not an ever-growing list of variables.
12
+ - **Checks:**
13
+ - If a required variable is missing in production, does your code fail at startup or on the first request that needs it?
14
+ - Which value hardcoded in your code would have to change between staging and production, and how would you move it to config?
15
+ - **Go deeper:**
16
+ - [Sriniously · Backend from first principles #17 · 26:41](https://www.youtube.com/watch?v=GR9NtirPXyc&t=1601s)
17
+ - [The Twelve-Factor App: Config](https://12factor.net/config)
18
+
19
+ ## secrets-management
20
+
21
+ - **Name:** Secrets management
22
+ - **Requires:** `config-management`
23
+ - **Signals:** `.env.example`, `aws secretsmanager`, `vault kv get`, `secretKeyRef`, `${{ secrets.`, `SecretStr`
24
+ - **Idea:** Credentials are kept out of code and images, injected at runtime from a secret store with access control, auditing and rotation, so a leaked repo or log does not leak them.
25
+ - **Misconceptions:**
26
+ - Deleting a committed secret in a later commit fixes the leak; it stays in history and forks, so it must be rotated.
27
+ - Environment variables are secure storage; they leak through crash dumps, debug endpoints, child processes and logs that print the config.
28
+ - **Checks:**
29
+ - If the API key in your code leaked today, how would you rotate it, and would your service need a redeploy to pick it up?
30
+ - Where could your code accidentally print a secret, such as an error message, request log or config dump, and how would you redact it?
31
+ - **Go deeper:**
32
+ - [Sriniously · Backend from first principles #17 · 31:03](https://www.youtube.com/watch?v=GR9NtirPXyc&t=1863s)
33
+ - [OWASP Cheat Sheet: Secrets Management](https://cheatsheetseries.owasp.org/cheatsheets/Secrets_Management_Cheat_Sheet.html)
34
+
35
+ ## disposable-processes
36
+
37
+ - **Name:** Disposable, stateless processes (12-factor)
38
+ - **Requires:** `stateless-services`, `graceful-shutdown`
39
+ - **Signals:** `SIGTERM`, `terminationGracePeriodSeconds`, `process.on("SIGTERM"`, `signal.NotifyContext`, `replicas:`, `readinessProbe`
40
+ - **Idea:** Each process starts fast, keeps no state it cannot lose and shuts down cleanly on a signal, so the platform can kill, restart or scale it at any moment safely.
41
+ - **Misconceptions:**
42
+ - A process only stops on deploys; autoscalers, node drains and crashes kill it anytime, so in-memory sessions and queues get lost.
43
+ - Shutting down means exiting immediately; in-flight requests and jobs should finish or be handed back before the process exits.
44
+ - **Checks:**
45
+ - If the platform sends your process SIGTERM mid-request, what happens to that request and to any job your code is running?
46
+ - What state does your code keep in memory or on local disk that would vanish if this instance were replaced right now?
47
+ - **Go deeper:**
48
+ - [Sriniously · Backend from first principles #27 · 50:16](https://www.youtube.com/watch?v=2_fcv3-XfN4&t=3016s)
49
+ - [The Twelve-Factor App: Disposability](https://12factor.net/disposability)
50
+
51
+ ## ci-pipeline
52
+
53
+ - **Name:** Continuous integration pipelines
54
+ - **Requires:** none
55
+ - **Signals:** `.github/workflows/`, `.gitlab-ci.yml`, `on: pull_request`, `actions/cache`, `Jenkinsfile`, `npm ci`
56
+ - **Idea:** Every push is built and tested automatically in a clean environment, so integration problems surface within minutes on the change that caused them instead of at release time.
57
+ - **Misconceptions:**
58
+ - Passing locally means CI will pass; CI starts clean, so missing lockfile entries, env vars and machine-specific state show up there.
59
+ - A red build can wait; once main stays broken, every later failure hides behind it and people stop trusting the pipeline.
60
+ - **Checks:**
61
+ - Which checks run on your change before merge, and which bug class in your code would still reach main untested?
62
+ - If your pipeline takes 25 minutes, which steps would you cache, parallelize or move later, and what feedback would that delay?
63
+ - **Go deeper:**
64
+ - [Sriniously · Backend from first principles #30 · 15:50](https://www.youtube.com/watch?v=_E8X5RIJfQ4&t=950s)
65
+ - [martinfowler.com: Continuous Integration](https://martinfowler.com/articles/continuousIntegration.html)
66
+
67
+ ## container-images
68
+
69
+ - **Name:** Containers and image layers
70
+ - **Requires:** none
71
+ - **Signals:** `Dockerfile`, `FROM node:22-alpine AS build`, `COPY package*.json ./`, `.dockerignore`, `USER node`, `docker build`
72
+ - **Idea:** An image is a stack of cached, read-only layers built from Dockerfile steps, so ordering steps from least to most often changed keeps rebuilds fast and images small.
73
+ - **Misconceptions:**
74
+ - Deleting a file in a later layer removes it from the image; it still ships in the earlier layer, including any secret copied in.
75
+ - Copying the whole project before installing dependencies is harmless; any source change invalidates the cache and reinstalls everything.
76
+ - **Checks:**
77
+ - In your Dockerfile, which line invalidates the cache on every code change, and how would reordering steps speed up rebuilds?
78
+ - What ends up in your final image that production does not need, such as compilers, tests or `.git`, and how would a multi-stage build drop it?
79
+ - **Go deeper:**
80
+ - [Sriniously · Backend from first principles #30 · 38:18](https://www.youtube.com/watch?v=_E8X5RIJfQ4&t=2298s)
81
+ - [Docker docs: Understanding the image layers](https://docs.docker.com/get-started/docker-concepts/building-images/understanding-image-layers/)
82
+
83
+ ## deployment-strategies
84
+
85
+ - **Name:** Rolling, blue-green and canary deploys
86
+ - **Requires:** `load-balancing`
87
+ - **Signals:** `strategy: RollingUpdate`, `maxUnavailable`, `maxSurge`, `canary`, `blue-green`, `trafficRouting`
88
+ - **Idea:** Rolling, blue-green and canary deploys shift traffic to a new version gradually or switchably, so a bad release reaches few users and can be rolled back without downtime.
89
+ - **Misconceptions:**
90
+ - Blue-green makes rollback free; if the new version already migrated the schema or wrote new data, switching back can break the old version.
91
+ - During a rolling deploy only one version runs; old and new serve traffic together, so APIs and schema must work with both.
92
+ - **Checks:**
93
+ - While your deploy is half rolled out, which requests could hit the old version after the new one wrote data, and would that break?
94
+ - What metric would tell you a canary of your change is bad, and how quickly could your setup roll it back?
95
+ - **Go deeper:**
96
+ - [Sriniously · Backend from first principles #30 · 1:16:26](https://www.youtube.com/watch?v=_E8X5RIJfQ4&t=4586s)
97
+ - [Google SRE Workbook: Canarying Releases](https://sre.google/workbook/canarying-releases/)
98
+
99
+ ## infrastructure-as-code
100
+
101
+ - **Name:** Infrastructure as code
102
+ - **Requires:** none
103
+ - **Signals:** `resource "aws_`, `terraform plan`, `.tfstate`, `pulumi up`, `AWSTemplateFormatVersion`, `cdk deploy`
104
+ - **Idea:** Servers, networks, databases and permissions are declared in versioned files that a tool applies, so environments are reproducible, reviewed like code and not hand-configured in a console.
105
+ - **Misconceptions:**
106
+ - Once infrastructure is in code, console tweaks are harmless; manual changes create drift that the next apply silently reverts or fights.
107
+ - The state file is a disposable artifact; losing or corrupting it makes the tool forget what it owns, and it often holds secrets.
108
+ - **Checks:**
109
+ - Before your change applies, what in the plan output would warn you that a resource will be destroyed and recreated instead of updated?
110
+ - Where does your project keep its state file, who can read it, and what stops two people applying at once?
111
+ - **Go deeper:**
112
+ - [Sriniously · Backend from first principles #30 · 1:25:18](https://www.youtube.com/watch?v=_E8X5RIJfQ4&t=5118s)
113
+ - [martinfowler.com: Infrastructure As Code](https://martinfowler.com/bliki/InfrastructureAsCode.html)
114
+
115
+ ## slos-incidents
116
+
117
+ - **Name:** SLOs, error budgets and incidents
118
+ - **Requires:** `metrics-monitoring`
119
+ - **Signals:** `slo:`, `error_budget`, `histogram_quantile(`, `burn rate`, `availability: 99.9`, `postmortem`
120
+ - **Idea:** An SLO sets a target for a user-visible indicator like success rate or latency, and the error budget left over decides when to ship faster or stop and fix reliability.
121
+ - **Misconceptions:**
122
+ - The goal is 100% reliability; it is unattainable and costly, and users cannot tell 99.99% from 100% behind their own networks.
123
+ - Alert on every CPU spike or error; page on symptoms that burn the error budget, not causes users never notice.
124
+ - **Checks:**
125
+ - Which user-facing indicator would you measure for the endpoint in your code, and what latency or success threshold would count as good?
126
+ - If your change caused errors for 5% of requests for ten minutes, how much of a 99.9% monthly budget would that burn?
127
+ - **Go deeper:**
128
+ - [Sriniously · Backend from first principles #30 · 1:33:01](https://www.youtube.com/watch?v=_E8X5RIJfQ4&t=5581s)
129
+ - [Google SRE Book: Service Level Objectives](https://sre.google/sre-book/service-level-objectives/)
@@ -0,0 +1,81 @@
1
+ # Testing
2
+
3
+ ## test-pyramid
4
+
5
+ - **Name:** Unit, integration and end-to-end tests
6
+ - **Requires:** none
7
+ - **Signals:** `describe(`, `pytest`, `func TestX(t *testing.T)`, `@SpringBootTest`, `playwright.config`, `supertest`
8
+ - **Idea:** Tests at different scopes trade speed for realism, so most checks live in fast unit tests, fewer in integration tests and a handful in slow end-to-end tests.
9
+ - **Misconceptions:**
10
+ - More end-to-end tests always mean more confidence; they are slow, flaky and point vaguely at failures, so suites built mostly from them get ignored.
11
+ - Unit tests alone prove the system works; they miss bugs in SQL, serialization, config and the wiring between components.
12
+ - **Checks:**
13
+ - For the change in your code, which bug would a unit test catch that an end-to-end test would not pinpoint, and vice versa?
14
+ - If your test suite took twenty minutes, which tests would you move down a level, and what realism would you give up?
15
+ - **Go deeper:**
16
+ - [Sriniously · Backend from first principles #26 · 14:46](https://www.youtube.com/watch?v=HgVrfHX92y4&t=886s)
17
+ - [martinfowler.com: The Practical Test Pyramid](https://martinfowler.com/articles/practical-test-pyramid.html)
18
+
19
+ ## test-doubles
20
+
21
+ - **Name:** Test doubles: stubs, mocks and fakes
22
+ - **Requires:** `dependency-injection`
23
+ - **Signals:** `jest.mock(`, `vi.fn()`, `unittest.mock.patch`, `@MockBean`, `gomock`, `sinon.stub`
24
+ - **Idea:** A test double stands in for a real dependency, with stubs returning canned answers, mocks verifying calls and fakes giving a working lightweight version, so tests stay fast and deterministic.
25
+ - **Misconceptions:**
26
+ - Mocking everything makes tests thorough; tests that assert exact internal calls break on every refactor while still passing when the real dependency behaves differently.
27
+ - A mock that returns success proves the integration works; it only proves your code handles the answer you invented.
28
+ - **Checks:**
29
+ - In your test, does the double check the outcome your code produces, or just that a specific method was called, and which survives a refactor?
30
+ - What real behaviour of the dependency your code calls, such as timeouts or constraint errors, does your double never simulate?
31
+ - **Go deeper:**
32
+ - [Sriniously · Backend from first principles #26 · 27:27](https://www.youtube.com/watch?v=HgVrfHX92y4&t=1647s)
33
+ - [martinfowler.com: Test Double](https://martinfowler.com/bliki/TestDouble.html)
34
+
35
+ ## integration-tests-real-deps
36
+
37
+ - **Name:** Integration tests against real dependencies
38
+ - **Requires:** `test-pyramid`
39
+ - **Signals:** `testcontainers`, `PostgreSqlContainer`, `docker-compose.test.yml`, `services: postgres`, `@DataJpaTest`, `pytest-postgresql`
40
+ - **Idea:** Integration tests run your code against real instances of the database, cache or broker, usually in throwaway containers, to catch bugs that only appear with the actual engine.
41
+ - **Misconceptions:**
42
+ - SQLite or an in-memory fake is close enough to Postgres; types, locking, constraints and SQL dialect differ, so bugs slip through.
43
+ - Integration tests can share one database freely; leftover rows from one test change another's result unless each test isolates or resets data.
44
+ - **Checks:**
45
+ - Which behaviour in your code, such as a unique constraint, transaction or JSON column, would pass against a fake but fail against the real database?
46
+ - How does your test suite reset data between tests, and what happens if two tests run in parallel against the same schema?
47
+ - **Go deeper:**
48
+ - [Sriniously · Backend from first principles #26 · 41:04](https://www.youtube.com/watch?v=HgVrfHX92y4&t=2464s)
49
+ - [martinfowler.com: Integration Test](https://martinfowler.com/bliki/IntegrationTest.html)
50
+
51
+ ## flaky-tests
52
+
53
+ - **Name:** Flaky tests: time, network and order
54
+ - **Requires:** `test-pyramid`
55
+ - **Signals:** `jest.useFakeTimers`, `freezegun`, `setTimeout(` in a test, `Date.now()`, `--randomize`, `retry: 3`
56
+ - **Idea:** A flaky test passes or fails without code changes because it depends on wall-clock time, real network, shared state or run order, so its failures stop meaning anything.
57
+ - **Misconceptions:**
58
+ - Adding retries or a longer sleep fixes flakiness; it hides a race or hidden dependency and makes the suite slower.
59
+ - A test that passes alone is correct; it may rely on state left by an earlier test and fail when order changes.
60
+ - **Checks:**
61
+ - What in your test depends on the current time, a real network call or a fixed sleep, and how would you make it deterministic?
62
+ - If your test fails only in CI under parallel runs, which shared resource in your code would you suspect first?
63
+ - **Go deeper:**
64
+ - [Sriniously · Backend from first principles #26 · 1:02:36](https://www.youtube.com/watch?v=HgVrfHX92y4&t=3756s)
65
+ - [martinfowler.com: Eradicating Non-Determinism in Tests](https://martinfowler.com/articles/nonDeterminism.html)
66
+
67
+ ## code-coverage
68
+
69
+ - **Name:** What code coverage can and cannot tell you
70
+ - **Requires:** `test-pyramid`
71
+ - **Signals:** `--coverage`, `coverageThreshold`, `pytest-cov`, `go test -cover`, `jacoco`, `istanbul ignore`
72
+ - **Idea:** Coverage reports which lines or branches ran during tests, which reveals untested code but says nothing about whether the assertions would catch a wrong result.
73
+ - **Misconceptions:**
74
+ - 100% coverage means the code is correct; a test with no meaningful assertions can execute every line.
75
+ - Raising the coverage threshold improves quality; teams then write tests that touch code without checking behaviour, just to hit the number.
76
+ - **Checks:**
77
+ - Which branch in your change, such as an error path, is uncovered, and what real failure would it hide?
78
+ - If you broke the main calculation in your code, would any covered test fail, or do the tests only execute it?
79
+ - **Go deeper:**
80
+ - [Sriniously · Backend from first principles #26 · 1:07:39](https://www.youtube.com/watch?v=HgVrfHX92y4&t=4059s)
81
+ - [martinfowler.com: Test Coverage](https://martinfowler.com/bliki/TestCoverage.html)
@@ -0,0 +1,65 @@
1
+ # Real-time
2
+
3
+ ## polling-long-polling
4
+
5
+ - **Name:** Polling and long polling
6
+ - **Requires:** `http-messages`
7
+ - **Signals:** `setInterval(`, `refetchInterval`, `?since=`, `WaitTimeSeconds`, `204 No Content`
8
+ - **Idea:** Polling asks the server for updates on a timer, while long polling holds each request open until data arrives or a timeout passes, giving near-real-time updates over plain HTTP.
9
+ - **Misconceptions:**
10
+ - Short polling every second is harmless; with many clients most requests return nothing yet still cost auth checks, database queries and connections.
11
+ - A long-poll request can stay open indefinitely; proxies and load balancers cut idle connections, so respond within their timeout and let the client reconnect.
12
+ - **Checks:**
13
+ - If the client misses a response from your polling endpoint, how does your code let it resume without losing or duplicating updates?
14
+ - How many requests per minute will your polling interval produce at your expected number of open clients, and what does each one cost?
15
+ - **Go deeper:**
16
+ - [Sriniously · Backend from first principles #25 · 2:26](https://www.youtube.com/watch?v=wUQryt697cs&t=146s)
17
+ - [IETF: RFC 6202, Long polling and streaming in bidirectional HTTP](https://datatracker.ietf.org/doc/html/rfc6202)
18
+
19
+ ## server-sent-events
20
+
21
+ - **Name:** Server-sent events
22
+ - **Requires:** `polling-long-polling`
23
+ - **Signals:** `text/event-stream`, `EventSource`, `Last-Event-ID`, `StreamingResponse`, `SseEmitter`, `retry:`
24
+ - **Idea:** Server-sent events stream one-way updates from server to browser over a long-lived HTTP response, with built-in reconnection and resume via event ids, which suits feeds, notifications and LLM token streaming.
25
+ - **Misconceptions:**
26
+ - SSE needs WebSockets underneath; it is a plain HTTP response with `text/event-stream`, so it works through most proxies and over HTTP/2 without a protocol upgrade.
27
+ - Events reach the client as soon as you write them; compression or proxy buffering can hold them back unless you flush and disable buffering, for example `X-Accel-Buffering: no`.
28
+ - **Checks:**
29
+ - When a client reconnects with `Last-Event-ID`, how does your code replay the events it missed?
30
+ - How does your code notice that a client disconnected and stop the work and timers feeding that stream?
31
+ - **Go deeper:**
32
+ - [Sriniously · Backend from first principles #25 · 11:57](https://www.youtube.com/watch?v=wUQryt697cs&t=717s)
33
+ - [MDN: Using server-sent events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events)
34
+
35
+ ## websockets
36
+
37
+ - **Name:** WebSockets
38
+ - **Requires:** `polling-long-polling`
39
+ - **Signals:** `new WebSocket(`, `Upgrade: websocket`, `socket.io`, `ws.on('message'`, `websocket.accept()`, `gorilla/websocket`
40
+ - **Idea:** A WebSocket upgrades one HTTP request into a persistent, full-duplex connection where client and server send messages anytime, suiting chat, collaboration and games but requiring you to manage connection state.
41
+ - **Misconceptions:**
42
+ - CORS protects WebSocket endpoints like it protects fetch; browsers do not apply it to the handshake, so your server must check `Origin` and authenticate the connection itself.
43
+ - A connection stays open until someone closes it; NATs and proxies silently drop idle sockets, so use ping/pong heartbeats and client reconnection with backoff.
44
+ - **Checks:**
45
+ - When a client reconnects after a network drop, how does your code recover the messages sent while it was offline?
46
+ - What does your code do when a client stops reading and outgoing messages pile up in that socket's buffer?
47
+ - **Go deeper:**
48
+ - [Sriniously · Backend from first principles #25 · 19:21](https://www.youtube.com/watch?v=wUQryt697cs&t=1161s)
49
+ - [MDN: The WebSocket API](https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API)
50
+
51
+ ## pub-sub-fanout
52
+
53
+ - **Name:** Pub/sub fan-out across instances
54
+ - **Requires:** `websockets`, `stateless-services`
55
+ - **Signals:** `redis.publish(`, `@socket.io/redis-adapter`, `CHANNEL_LAYERS`, `pg_notify(`, `XADD`
56
+ - **Idea:** When clients are spread across many server instances, each instance subscribes to a shared broker channel so an event published once reaches every instance and its locally connected sockets.
57
+ - **Misconceptions:**
58
+ - Broadcasting to your in-memory connection list reaches all users; once you run more than one replica, it only reaches sockets on that instance.
59
+ - Redis Pub/Sub keeps messages for subscribers that are briefly offline; it is at-most-once, so use Streams or a durable log when missed messages matter.
60
+ - **Checks:**
61
+ - If the instance holding a user's socket restarts while an event is published, how does your code make sure that user still sees it?
62
+ - How does your code avoid sending every event to every instance when only a few hold interested subscribers?
63
+ - **Go deeper:**
64
+ - [Sriniously · Backend from first principles #25 · 40:51](https://www.youtube.com/watch?v=wUQryt697cs&t=2451s)
65
+ - [Redis: Redis Pub/sub](https://redis.io/docs/latest/develop/pubsub/)
@@ -0,0 +1,65 @@
1
+ # Errors and reliability
2
+
3
+ ## error-handling-global
4
+
5
+ - **Name:** Centralized error handling
6
+ - **Requires:** `middleware-pipeline`
7
+ - **Signals:** `app.use((err, req, res, next)`, `setErrorHandler`, `@ControllerAdvice`, `@app.exception_handler`, `rescue_from`, `application/problem+json`
8
+ - **Idea:** One error-handling layer at the edge of the app turns any thrown error into a consistent, safe HTTP response and a log entry, so handlers do not each reinvent status codes and leak internals.
9
+ - **Misconceptions:**
10
+ - Sending `err.message` or the stack trace to the client helps debugging; it leaks internals, so return a generic message with a request id and log details server-side.
11
+ - Every error should become a 500; validation, not-found and conflict errors are expected outcomes and deserve their own 4xx codes.
12
+ - **Checks:**
13
+ - If an async function in your handler rejects without a try/catch, does the error reach your central handler, or does the request hang or the process crash?
14
+ - How does your error handler decide between a 4xx and a 500, and what does it log for each?
15
+ - **Go deeper:**
16
+ - [Sriniously · Backend from first principles #16 · 41:48](https://www.youtube.com/watch?v=8NaM_9aKS24&t=2508s)
17
+ - [OWASP Cheat Sheet Series: Error handling](https://cheatsheetseries.owasp.org/cheatsheets/Error_Handling_Cheat_Sheet.html)
18
+
19
+ ## timeouts-external-calls
20
+
21
+ - **Name:** Timeouts on external calls
22
+ - **Requires:** none
23
+ - **Signals:** `AbortSignal.timeout(`, `requests.get(url, timeout=`, `context.WithTimeout`, `http.Client{Timeout:`, `statement_timeout`, `connectTimeout`
24
+ - **Idea:** Every network call to a database, API or cache needs an explicit time limit, because without one a slow dependency holds threads, connections and memory until your own service stops responding.
25
+ - **Misconceptions:**
26
+ - HTTP clients ship with sensible timeouts; Python `requests` and Go's default `http.Client` wait forever, and Node `fetch` waits minutes before giving up.
27
+ - A timeout means the remote operation failed; it may have succeeded after you gave up, so blindly retrying a non-idempotent call can apply it twice.
28
+ - **Checks:**
29
+ - What is the total time budget for this request in your code, and do the timeouts on each downstream call fit inside it?
30
+ - When this external call times out in your code, what does the user see, and is it safe to retry?
31
+ - **Go deeper:**
32
+ - [Sriniously · Backend from first principles #16 · 10:40](https://www.youtube.com/watch?v=8NaM_9aKS24&t=640s)
33
+ - [Google SRE book: Addressing cascading failures](https://sre.google/sre-book/addressing-cascading-failures/)
34
+
35
+ ## retries-backoff-jitter
36
+
37
+ - **Name:** Retries with backoff and jitter
38
+ - **Requires:** `timeouts-external-calls`, `idempotency-keys`
39
+ - **Signals:** `Retry-After`, `p-retry`, `tenacity`, `@Retryable`, `maxAttempts`, `2 ** attempt`
40
+ - **Idea:** Retrying transient failures after exponentially growing, randomized delays lets a call recover from blips without a synchronized storm of retries overwhelming a dependency that is already struggling.
41
+ - **Misconceptions:**
42
+ - Any error is worth retrying; 400s, auth failures and validation errors fail identically every time, so retry only timeouts, connection errors, 429 and selected 5xx.
43
+ - Retrying at every layer adds safety; three layers with three attempts each multiply into 27 calls against a dependency that is already failing.
44
+ - **Checks:**
45
+ - Is the operation your code retries idempotent, and if not, what stops a retry after a timeout from doing it twice?
46
+ - What is the worst-case total time your retry loop can spend, including backoff, and does it fit inside the caller's timeout?
47
+ - **Go deeper:**
48
+ - [Sriniously · Backend from first principles #29 · 34:31](https://www.youtube.com/watch?v=eWM0CVReP04&t=2071s)
49
+ - [AWS SDKs and Tools: Retry behavior](https://docs.aws.amazon.com/sdkref/latest/guide/feature-retry-behavior.html)
50
+
51
+ ## graceful-shutdown
52
+
53
+ - **Name:** Graceful shutdown and connection draining
54
+ - **Requires:** none
55
+ - **Signals:** `SIGTERM`, `server.close(`, `srv.Shutdown(ctx)`, `terminationGracePeriodSeconds`, `preStop`, `server.shutdown=graceful`
56
+ - **Idea:** On SIGTERM a service should stop accepting new work, let in-flight requests and jobs finish, close pools cleanly, then exit, so deploys and scale-downs do not drop requests or corrupt half-done work.
57
+ - **Misconceptions:**
58
+ - Shutdown needs no code; without a SIGTERM handler most runtimes exit instantly, and a process running as container PID 1 may ignore the signal until SIGKILL.
59
+ - Closing the server is enough; the load balancer may keep routing new requests for a few seconds, so fail readiness first and keep serving briefly.
60
+ - **Checks:**
61
+ - What happens to a request your code is halfway through when the container receives SIGTERM during a deploy?
62
+ - Does your shutdown path finish within the platform's grace period, and what is left undone if it gets killed early?
63
+ - **Go deeper:**
64
+ - [Sriniously · Backend from first principles #19 · 8:49](https://www.youtube.com/watch?v=6rfBgphiCWM&t=529s)
65
+ - [Kubernetes: Pod lifecycle, termination of Pods](https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/#pod-termination)
@@ -0,0 +1,81 @@
1
+ # Scaling and concurrency
2
+
3
+ ## stateless-services
4
+
5
+ - **Name:** Stateless services and horizontal scaling
6
+ - **Requires:** none
7
+ - **Signals:** `MemoryStore`, `connect-redis`, `SESSION_ENGINE`, `sticky sessions`, `replicas:`, `HorizontalPodAutoscaler`
8
+ - **Idea:** A stateless instance keeps nothing between requests in local memory or disk, putting sessions, uploads and caches in shared stores, so any instance can serve any request and you scale by adding copies.
9
+ - **Misconceptions:**
10
+ - Stateless means no state anywhere; the state still exists, it just moves to a database, cache or object store that all instances share.
11
+ - An in-process cache or rate-limit counter behaves the same with more replicas; each instance keeps its own copy, so limits multiply and caches disagree.
12
+ - **Checks:**
13
+ - If a second instance of your service starts behind the load balancer, which variables or files in your code would give users different answers?
14
+ - Where does your code keep sessions, uploaded files and in-memory counters, and what happens to them when an instance restarts?
15
+ - **Go deeper:**
16
+ - [Sriniously · Backend from first principles #21.2 · 0:43](https://www.youtube.com/watch?v=sOhAopEwjH4&t=43s)
17
+ - [The Twelve-Factor App: Processes](https://12factor.net/processes)
18
+
19
+ ## load-balancing
20
+
21
+ - **Name:** Load balancing
22
+ - **Requires:** `stateless-services`
23
+ - **Signals:** `upstream backend {`, `proxy_pass`, `least_conn`, `X-Forwarded-For`, `readinessProbe`, `trust proxy`
24
+ - **Idea:** A load balancer spreads requests across healthy instances, by round robin or least connections, skipping ones that fail health checks so no single machine is overloaded or a single point of failure.
25
+ - **Misconceptions:**
26
+ - Behind a load balancer, `req.ip` is the client's address; it is the proxy's unless you parse `X-Forwarded-For` and trust only your own proxies.
27
+ - An endpoint that always returns 200 is a good health check; readiness should fail whenever the instance cannot serve, such as during startup or shutdown.
28
+ - **Checks:**
29
+ - If one instance behind your load balancer becomes slow but not dead, how would your current health check and balancing policy react?
30
+ - Does your code rely on the same client reaching the same instance twice, such as for socket state or uploads, and what breaks if it does not?
31
+ - **Go deeper:**
32
+ - [Sriniously · Backend from first principles #21.2 · 9:11](https://www.youtube.com/watch?v=sOhAopEwjH4&t=551s)
33
+ - [Google SRE book: Load balancing in the datacenter](https://sre.google/sre-book/load-balancing-datacenter/)
34
+
35
+ ## io-vs-cpu-bound
36
+
37
+ - **Name:** IO-bound vs CPU-bound work
38
+ - **Requires:** none
39
+ - **Signals:** `worker_threads`, `ProcessPoolExecutor`, `asyncio.to_thread(`, `bcrypt.hashSync`, `GOMAXPROCS`
40
+ - **Idea:** IO-bound work spends its time waiting on networks and disks and scales with concurrency, while CPU-bound work like hashing, image resizing or parsing huge JSON needs real cores, so they need different tools.
41
+ - **Misconceptions:**
42
+ - Marking a function `async` makes CPU-heavy work non-blocking; async only helps while waiting, and a tight loop still freezes the event loop.
43
+ - Python threads speed up CPU-bound code; in standard CPython builds the GIL runs one thread's bytecode at a time, so use processes or native code.
44
+ - **Checks:**
45
+ - Which step in your handler is CPU-heavy, and what happens to other users' requests on the same instance while it runs?
46
+ - Would more concurrency or more cores make this part of your code faster, and how could you measure which one it needs?
47
+ - **Go deeper:**
48
+ - [Sriniously · Backend from first principles #22 · 5:55](https://www.youtube.com/watch?v=bs9MEYRTA30&t=355s)
49
+ - [Node.js: Don't block the event loop (or the worker pool)](https://nodejs.org/en/learn/asynchronous-work/dont-block-the-event-loop)
50
+
51
+ ## event-loop-async
52
+
53
+ - **Name:** Event loop and async/await
54
+ - **Requires:** `io-vs-cpu-bound`
55
+ - **Signals:** `async def`, `Promise.all(`, `asyncio.gather(`, `setImmediate`, `readFileSync`, `CompletableFuture`
56
+ - **Idea:** An event loop runs many tasks on one thread by switching whenever a task awaits IO, so it handles thousands of connections cheaply as long as no task blocks the thread.
57
+ - **Misconceptions:**
58
+ - Awaiting calls one by one in a loop runs them in parallel; each `await` waits for the previous one, so use `Promise.all` or `gather` for independent calls.
59
+ - Calling a blocking library inside an async function is fine; synchronous drivers, `time.sleep` or `fs.readFileSync` stall every request on that loop.
60
+ - **Checks:**
61
+ - Which awaited calls in your handler are independent of each other, and how much latency would running them concurrently save?
62
+ - Does any library your async code calls perform blocking IO under the hood, and how would you notice it in production?
63
+ - **Go deeper:**
64
+ - [Sriniously · Backend from first principles #22 · 37:15](https://www.youtube.com/watch?v=bs9MEYRTA30&t=2235s)
65
+ - [Node.js: The Node.js event loop](https://nodejs.org/en/learn/asynchronous-work/event-loop-timers-and-nexttick)
66
+
67
+ ## race-conditions
68
+
69
+ - **Name:** Race conditions and locks
70
+ - **Requires:** none
71
+ - **Signals:** `SELECT ... FOR UPDATE`, `pg_advisory_xact_lock`, `sync.Mutex`, `SET stock = stock - 1`, `WHERE version = $1`, `SET key val NX PX`
72
+ - **Idea:** A race condition happens when concurrent requests read and write the same data and the result depends on timing, so code needs atomic updates, constraints or locks to keep its invariants.
73
+ - **Misconceptions:**
74
+ - A single-threaded runtime like Node cannot have races; any `await` between reading and writing lets another request interleave, and multiple instances race anyway.
75
+ - An in-memory mutex protects shared data; it only covers one process, so across replicas use row locks, conditional updates or a distributed lock.
76
+ - **Checks:**
77
+ - If two requests run the read-then-write sequence in your code at the same moment, what final value ends up in the database?
78
+ - Could a single conditional `UPDATE ... WHERE` replace the lock in your code, and what would you gain or lose?
79
+ - **Go deeper:**
80
+ - [Sriniously · Backend from first principles #22 · 1:15:32](https://www.youtube.com/watch?v=bs9MEYRTA30&t=4532s)
81
+ - [PostgreSQL: Explicit locking](https://www.postgresql.org/docs/current/explicit-locking.html)
@@ -0,0 +1,97 @@
1
+ # Security
2
+
3
+ ## sql-injection
4
+
5
+ - **Name:** SQL injection and parameterized queries
6
+ - **Requires:** none
7
+ - **Signals:** `WHERE id = $1`, `cursor.execute(sql, params)`, `PreparedStatement`, `$queryRawUnsafe`, `f"SELECT`, `ORDER BY ${`
8
+ - **Idea:** When user input is concatenated into SQL text the database parses it as code, so values must travel separately as bound parameters that can never change the query's structure.
9
+ - **Misconceptions:**
10
+ - Using an ORM makes you immune; raw-query escape hatches, string-built `where` clauses and dynamic sort columns still inject.
11
+ - Escaping quotes or validating input is enough; identifiers like column names cannot be bound, so they need an allowlist instead.
12
+ - **Checks:**
13
+ - Which value in your query reaches the SQL string by concatenation or interpolation rather than as a bound parameter, and where does it come from?
14
+ - If your handler lets the client choose a sort column or filter field, how does your code stop that name from becoming arbitrary SQL?
15
+ - **Go deeper:**
16
+ - [Sriniously · Backend from first principles #20 · 29:27](https://www.youtube.com/watch?v=xB1C1xZZW4k&t=1767s)
17
+ - [OWASP Cheat Sheet: SQL Injection Prevention](https://cheatsheetseries.owasp.org/cheatsheets/SQL_Injection_Prevention_Cheat_Sheet.html)
18
+
19
+ ## object-level-authorization
20
+
21
+ - **Name:** Object-level authorization (BOLA)
22
+ - **Requires:** `rbac-authorization`
23
+ - **Signals:** `req.params.id`, `findById(id)` without an owner filter, `WHERE id = $1 AND owner_id = $2`, `get_object_or_404(`, `@PreAuthorize`, `/users/:userId/`
24
+ - **Idea:** Being logged in and holding the right role says nothing about this particular record, so every lookup by client-supplied id must also check that the caller may access that object.
25
+ - **Misconceptions:**
26
+ - Unguessable UUIDs protect records; ids leak through URLs, logs and shared links, so obscurity is not an access check.
27
+ - A role check in middleware covers it; roles say what kind of action is allowed, not whose order or invoice it is.
28
+ - **Checks:**
29
+ - If another logged-in user changes the id in this request to yours, which line in your handler returns 404 or 403 instead of your data?
30
+ - Does your code scope the database query itself to the caller's tenant or owner, or fetch first and compare afterwards, and which is easier to forget?
31
+ - **Go deeper:**
32
+ - [Sriniously · Backend from first principles #20 · 1:37:31](https://www.youtube.com/watch?v=xB1C1xZZW4k&t=5851s)
33
+ - [OWASP Cheat Sheet: Insecure Direct Object Reference Prevention](https://cheatsheetseries.owasp.org/cheatsheets/Insecure_Direct_Object_Reference_Prevention_Cheat_Sheet.html)
34
+
35
+ ## rate-limiting
36
+
37
+ - **Name:** Rate limiting
38
+ - **Requires:** `http-status-codes`
39
+ - **Signals:** `429 Too Many Requests`, `Retry-After`, `express-rate-limit`, `golang.org/x/time/rate`, Redis `INCR` with `EXPIRE`
40
+ - **Idea:** Capping how many requests a client, key or tenant may make per time window protects shared capacity and slows abuse such as credential stuffing, scraping and runaway retry loops.
41
+ - **Misconceptions:**
42
+ - An in-memory counter works in production; with several replicas each instance counts separately, so the real limit becomes the limit times the instance count.
43
+ - Keying limits only by IP is fair; NAT and proxies share IPs, while attackers rotate them, so key by user, API key or account too.
44
+ - **Checks:**
45
+ - Where does your limiter store its counters, and what limit does a client actually get when your service runs on three instances behind a load balancer?
46
+ - When your code rejects a request with 429, what does the client learn about when to retry, and how would a well-behaved SDK back off?
47
+ - **Go deeper:**
48
+ - [Sriniously · Backend from first principles #20 · 1:32:41](https://www.youtube.com/watch?v=xB1C1xZZW4k&t=5561s)
49
+ - [Microsoft Learn: Throttling pattern](https://learn.microsoft.com/en-us/azure/architecture/patterns/throttling)
50
+
51
+ ## xss
52
+
53
+ - **Name:** Cross-site scripting (XSS)
54
+ - **Requires:** none
55
+ - **Signals:** `innerHTML`, `dangerouslySetInnerHTML`, `v-html`, `mark_safe(`, `Content-Security-Policy`, `DOMPurify.sanitize(`
56
+ - **Idea:** When untrusted data is written into a page without encoding for its context, the browser runs it as script with the victim's session, so output must be escaped or sanitized where it lands.
57
+ - **Misconceptions:**
58
+ - Sanitizing input once on the way in is enough; the safe encoding depends on output context, such as HTML body, attribute, URL or inline script.
59
+ - A JSON API cannot cause XSS; a wrong `Content-Type`, or a frontend inserting the response as HTML, turns stored data into script.
60
+ - **Checks:**
61
+ - Which user-controlled field in your change ends up rendered as HTML, and what escapes or sanitizes it right before it reaches the page?
62
+ - If an attacker stored `<img src=x onerror=...>` in this field, where would your code render it, and would your CSP block it?
63
+ - **Go deeper:**
64
+ - [Sriniously · Backend from first principles #20 · 2:17:21](https://www.youtube.com/watch?v=xB1C1xZZW4k&t=8241s)
65
+ - [OWASP Cheat Sheet: Cross Site Scripting Prevention](https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html)
66
+
67
+ ## csrf
68
+
69
+ - **Name:** Cross-site request forgery (CSRF)
70
+ - **Requires:** `cookie-security`
71
+ - **Signals:** `SameSite=Lax`, `X-CSRF-Token`, `@csrf_exempt`, `csrf().disable()`, `Sec-Fetch-Site`, `protect_from_forgery`
72
+ - **Idea:** Browsers attach cookies to requests that other sites trigger, so a cookie-authenticated endpoint that changes state needs proof the request came from your own pages, not merely the user's browser.
73
+ - **Misconceptions:**
74
+ - CORS stops CSRF; CORS only controls reading responses, while a simple cross-site form POST is still sent with cookies.
75
+ - `SameSite` cookies end the problem; `Lax` still permits top-level GET navigations, so state-changing GET routes stay exploitable.
76
+ - **Checks:**
77
+ - Which state-changing routes in your code rely on a session cookie, and what token, header or origin check rejects the same request sent from another site?
78
+ - If your code disables CSRF protection for an API route, what guarantees callers authenticate with a header token rather than the browser's cookie?
79
+ - **Go deeper:**
80
+ - [Sriniously · Backend from first principles #20 · 2:28:32](https://www.youtube.com/watch?v=xB1C1xZZW4k&t=8912s)
81
+ - [OWASP Cheat Sheet: Cross-Site Request Forgery Prevention](https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html)
82
+
83
+ ## ssrf
84
+
85
+ - **Name:** Server-side request forgery (SSRF)
86
+ - **Requires:** none
87
+ - **Signals:** `fetch(req.body.url)`, `requests.get(url)`, `http.Get(userURL)`, `169.254.169.254`, `redirect: "manual"`
88
+ - **Idea:** When your server fetches a URL the user supplied, an attacker can aim it at internal services or cloud metadata your network trusts, so outbound targets must be restricted.
89
+ - **Misconceptions:**
90
+ - Blocking `localhost` in the string is enough; decimal IPs, IPv6, DNS names resolving to private ranges and redirects all bypass string checks.
91
+ - Validating the hostname once is safe; DNS can resolve differently at fetch time, so check the resolved IP on every connection and redirect.
92
+ - **Checks:**
93
+ - Which URL in your handler comes from the client, and what stops your code from fetching `http://169.254.169.254/` or a private 10.x address with it?
94
+ - Does your HTTP client follow redirects here, and does your code re-check the destination after each hop?
95
+ - **Go deeper:**
96
+ - [Sriniously · Backend from first principles #29 · 25:16](https://www.youtube.com/watch?v=eWM0CVReP04&t=1516s)
97
+ - [OWASP Cheat Sheet: Server Side Request Forgery Prevention](https://cheatsheetseries.owasp.org/cheatsheets/Server_Side_Request_Forgery_Prevention_Cheat_Sheet.html)
@@ -0,0 +1,81 @@
1
+ # Files and object storage
2
+
3
+ ## object-storage
4
+
5
+ - **Name:** Object storage instead of local disk
6
+ - **Requires:** `stateless-services`
7
+ - **Signals:** `PutObjectCommand`, `boto3.client("s3")`, `@google-cloud/storage`, `S3_BUCKET`, `ActiveStorage::Blob`, `multer.diskStorage`
8
+ - **Idea:** Files go to a shared bucket addressed by key instead of the server's own disk, so any instance can read them and nothing is lost when a container is replaced.
9
+ - **Misconceptions:**
10
+ - Writing uploads to `./uploads` is fine until you scale; it breaks the moment a second instance or a redeploy wipes the container filesystem.
11
+ - A bucket is a filesystem; keys only look like paths, renames are copies, and there is no atomic move or append.
12
+ - **Checks:**
13
+ - If your service runs on three instances behind a load balancer, which instance can serve a file your handler just saved, and why?
14
+ - What does your code store in the database for each file, and what happens if the object upload succeeds but that row insert fails?
15
+ - **Go deeper:**
16
+ - [Sriniously · Backend from first principles #23 · 9:54](https://www.youtube.com/watch?v=Ie0TjKI9cDI&t=594s)
17
+ - [AWS docs: What is Amazon S3?](https://docs.aws.amazon.com/AmazonS3/latest/userguide/Welcome.html)
18
+
19
+ ## presigned-urls
20
+
21
+ - **Name:** Pre-signed URLs
22
+ - **Requires:** `object-storage`
23
+ - **Signals:** `getSignedUrl`, `generate_presigned_url`, `PresignPutObject`, `X-Amz-Signature`, `createPresignedPost`
24
+ - **Idea:** The server signs a short-lived URL for one object and one method, so clients upload or download directly from storage without file bytes passing through your API or holding bucket credentials.
25
+ - **Misconceptions:**
26
+ - A pre-signed URL is private once issued; it is a bearer token, so anyone holding it can use it until it expires.
27
+ - Signing an upload URL means the upload is validated; size, content type and contents still need limits in the policy or a check afterwards.
28
+ - **Checks:**
29
+ - How long do the URLs your code signs stay valid, and what could someone do with one copied from a log or browser history?
30
+ - After a client uploads through your pre-signed URL, how does your code learn the upload finished and verify it is the expected file?
31
+ - **Go deeper:**
32
+ - [Sriniously · Backend from first principles #23 · 1:16:42](https://www.youtube.com/watch?v=Ie0TjKI9cDI&t=4602s)
33
+ - [AWS docs: Download and upload objects with presigned URLs](https://docs.aws.amazon.com/AmazonS3/latest/userguide/using-presigned-url.html)
34
+
35
+ ## streaming-uploads
36
+
37
+ - **Name:** Streaming instead of buffering uploads
38
+ - **Requires:** none
39
+ - **Signals:** `stream.pipeline`, `req.pipe(`, `busboy`, `multer.memoryStorage`, `io.Copy(`, `UploadFile.read()`
40
+ - **Idea:** Streaming moves request bytes through the server in small chunks to their destination, so memory stays flat regardless of file size instead of holding the whole body in RAM.
41
+ - **Misconceptions:**
42
+ - Memory storage is fine for uploads; a few concurrent large files load entirely into RAM and the process gets killed for running out of memory.
43
+ - Streaming means no limits are needed; you still cap total bytes, because an endless stream ties up a connection and fills the destination.
44
+ - **Checks:**
45
+ - If ten users upload a 2 GB file to your handler at once, roughly how much memory does your process need, and why?
46
+ - When the client disconnects halfway through, what does your code do with the partial data it already wrote to the destination?
47
+ - **Go deeper:**
48
+ - [Sriniously · Backend from first principles #23 · 1:11:43](https://www.youtube.com/watch?v=Ie0TjKI9cDI&t=4303s)
49
+ - [Node.js docs: Stream](https://nodejs.org/api/stream.html)
50
+
51
+ ## multipart-upload
52
+
53
+ - **Name:** Multipart uploads
54
+ - **Requires:** `object-storage`
55
+ - **Signals:** `CreateMultipartUpload`, `UploadPart`, `CompleteMultipartUpload`, `AbortIncompleteMultipartUpload`, `@aws-sdk/lib-storage`
56
+ - **Idea:** A large object is uploaded as independently sent numbered parts and then assembled, so failed parts retry alone, parts go in parallel, and huge files fit within per-request limits.
57
+ - **Misconceptions:**
58
+ - Multipart upload is the same as `multipart/form-data`; one is an HTML form encoding, the other is a storage API for chunked objects.
59
+ - Abandoned uploads clean themselves up; incomplete parts stay stored and billed until aborted, so you need an abort lifecycle rule.
60
+ - **Checks:**
61
+ - If part 37 of 80 fails in your code, what gets retried, and where do you keep the part numbers and ETags needed to complete?
62
+ - What in your setup removes multipart uploads that a client started but never completed or aborted?
63
+ - **Go deeper:**
64
+ - [Sriniously · Backend from first principles #24 · 4:30](https://www.youtube.com/watch?v=iWrVCxexUWY&t=270s)
65
+ - [AWS docs: Uploading and copying objects using multipart upload](https://docs.aws.amazon.com/AmazonS3/latest/userguide/mpuoverview.html)
66
+
67
+ ## range-requests
68
+
69
+ - **Name:** HTTP range requests
70
+ - **Requires:** `http-messages`
71
+ - **Signals:** `Range: bytes=`, `Accept-Ranges: bytes`, `206 Partial Content`, `Content-Range`, `416 Range Not Satisfiable`, `If-Range`
72
+ - **Idea:** A client asks for a byte slice of a resource with a Range header and the server returns 206 with just that slice, enabling resumable downloads and video seeking.
73
+ - **Misconceptions:**
74
+ - Range support is automatic; a handler that streams a file and always returns 200 forces players and download managers to restart from byte zero.
75
+ - Ranges only matter for video; resumable downloads, parallel chunked fetches and reading file footers like ZIP or Parquet all depend on them.
76
+ - **Checks:**
77
+ - When a client sends `Range: bytes=1000-` to your download endpoint, does your code return 206 with the right Content-Range, or the whole file?
78
+ - If the file changes between two range requests to your handler, how could the client end up with a corrupted mix, and what header prevents that?
79
+ - **Go deeper:**
80
+ - [Sriniously · Backend from first principles #24 · 32:51](https://www.youtube.com/watch?v=iWrVCxexUWY&t=1971s)
81
+ - [MDN: HTTP range requests](https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/Range_requests)