Timeline-Feed — Fan-Out-on-Write, and an Audit of Its Own Gaps
A fan-out-on-write timeline service with the read path, the write path and the failure modes separated — and an analysis pass that catalogued its own gaps by severity before any of them were fixed.
// DESCRIPTION
A social-media timeline service on Node.js/TypeScript, MongoDB, Redis and Kafka — fan-out-on-write, with a celebrity-account fallback to fan-out-on-read. About 2,900 lines of TypeScript.
The part worth reading is not the architecture. It is the analysis pass run against it before any production claim was made, which sorted its own gaps by severity and found seven that would have blocked deployment.
The finding that justifies doing this at all
Among the criticals: passwords were never stored, and there was no login endpoint. Registration worked, tokens were issued, the happy path demo ran. The authentication system was structurally incomplete in a way that every individual test — and every demo — passed straight over, because nothing exercised the second visit.
Three defects that generalise beyond this codebase
- The pagination cursor was forgeable. It was Base64-encoded JSON, which looks opaque and is not. Anything inside it — timestamps, IDs — is a client-controlled parameter being parsed and spliced into a query. Field-presence validation does not help; an HMAC does.
- Cache refresh on the write path read the database. Each like called
cachePost(postId, await getPost(postId)), andgetPostis the read-through function — so it necessarily missed and hit Mongo. The cache produced database traffic proportional to write rate, under exactly the load it existed to absorb. AHINCRBYon one field replaces it. - Two queries that are an N+1 in disguise. Fetching follower IDs and then the
user objects reads as two round trips, but it grows with
limit; a$lookupaggregation collapses it.
Why the report is the deliverable
Issues are grouped CRITICAL / HIGH / MEDIUM / LOW with the file and line for each, and a phased plan that fixes authentication and input validation before performance — because a faster service that cannot authenticate is not closer to shipping. Writing the severity split down is what makes "needs hardening" an actionable statement instead of a feeling.
// HIGHLIGHTS
- Fan-out-on-write with a fan-out-on-read path for high-follower accounts
- Self-audit found 7 deployment-blocking gaps, including an auth system with no login
- Base64 pagination cursor was forgeable — opaque-looking is not opaque
- Write-path cache refresh that read the DB, i.e. an amplifier under write load
- Severity-sorted plan that fixes correctness before performance