Really useful post, thanks. Lesson 3 hit home for me: the slow endpoint is usually a missing index, and adding the index is cheaper than adding a cache.
A small tip for lesson 5: staticcheck warns about a plain string as a context key, because another package can use the same string. An unexported key type avoids that:
type requestIDKey struct{}
ctx := context.WithValue(r.Context(), requestIDKey{}, id)
And one I'd add to the list: set timeouts on http.Server itself, at least ReadHeaderTimeout. A slow client can hold a connection open while it sends headers, and that happens before the handler runs, so the context timeout from lesson 2 never starts.