Build a production-grade authentication REST API in Node + TypeScript using Express (or Fastify) and PostgreSQL. Endpoints: register (validate input with Zod, hash passwords with bcrypt at cost 12, and prevent user enumeration on a duplicate email), login (issue a short-lived JWT access token plus a rotating refresh token stored HASHED in the DB), refresh (rotate the refresh token and treat reuse of an already-rotated token as a breach signal that revokes the whole session family), and logout (revoke the refresh token). Add middleware for access-token verification and role-based access control (admin/user/guest), plus per-route rate limiting. Deliver refresh tokens as HTTP-only, Secure, SameSite cookies and keep access tokens out of localStorage. Structure the code in clear layers — routes, controllers, services, repositories, middleware — with a typed config module and zero secrets in source. Return a consistent JSON error envelope that never leaks stack traces or reveals which field failed authentication. Cover the edge cases: expired or malformed tokens, clock skew, concurrent refreshes from two tabs, and account lockout after repeated failures. Done when the full register → login → refresh → logout cycle works, refresh-token reuse is detected and revokes the session family, and no endpoint reveals whether a given email exists.
#09Backend
File Upload Service
Build a file-upload API in Node + TypeScript (Express/Fastify) that accepts multipart form data and stores objects in S3-compatible storage (use a local MinIO bucket in dev behind a storage abstraction). Support single and batch uploads with hard limits enforced server-side: 10MB per file, max 5 files per request, and an allowlist of types (images jpg/png/webp, documents pdf/docx) validated by sniffing magic bytes — never trust the file extension or the client-supplied MIME type. Stream uploads to storage rather than buffering whole files in memory. For images, generate thumbnails with sharp; persist metadata (sanitized original name, byte size, detected MIME, checksum, owner, created_at) in Postgres; store objects under UUID or content-addressed keys; and return short-lived signed URLs for retrieval. Add an antivirus scan hook (e.g. ClamAV) and a cleanup job that removes orphaned objects whose DB row failed to commit. Report per-file results so a partial batch failure is clear, reject oversized streams early instead of after a full read, and defend against path traversal and SVG/zip-style payloads. Done when oversized, wrong-type, and spoofed-MIME uploads are all rejected before anything is stored, successful uploads return working signed URLs, and a failed DB write never leaves an orphaned object in the bucket.
#10Backend
WebSocket Real-Time Chat
Implement a real-time chat server in Node + TypeScript using Socket.IO (or ws) backed by PostgreSQL for persistence and Redis pub/sub so it scales across multiple instances. Support multiple rooms, join/leave notifications, typing indicators, presence (online users per room), and history (the last 50 messages loaded on join via cursor pagination). Authenticate the socket handshake with the same JWT used by the REST API and authorize room membership before a client joins. Persist every message and broadcast through the Redis adapter so two server instances stay consistent. Add heartbeat/ping monitoring, server-side rate limiting (max 10 messages per 10 seconds per user with a clear throttled response), input sanitization so rendered messages can't carry XSS, and a message-size cap. Handle the messy realities: reconnection with backfill of missed messages, duplicate delivery (idempotent client-supplied message IDs), out-of-order events, and reliable presence cleanup on disconnect or crash. Done when two clients connected to DIFFERENT server instances exchange messages in real time, history and presence are correct after a reconnect, and the flood limiter blocks abuse without dropping legitimate traffic.
#11Backend
Task Queue with Job Processing
Build a background job system in Node + TypeScript using BullMQ on Redis. Define typed producers for sending email, generating reports, and processing image uploads, and a worker that runs them with configurable concurrency. Each job type gets a Zod-validated payload, idempotency (safe to retry without duplicating side effects), exponential backoff with jitter (max 3 attempts), and a dead-letter queue for terminal failures with the error captured. Make jobs observable: structured logs carrying a correlation ID, per-job duration, and a status API returning queue health (waiting, active, completed in the last hour, failed count, and failure rate). Handle graceful shutdown on SIGTERM — finish or safely re-queue in-flight jobs so no work is lost — plus stalled-job recovery and job prioritization. Guard against the foot-guns: non-idempotent jobs that double-charge or double-send, unbounded retries hammering a downstream, and Redis connection loss. Include one scheduled/repeatable job as an example. Done when a transient failure retries with backoff and eventually succeeds, a permanently failing job lands in the DLQ with its error preserved, SIGTERM during processing loses no jobs, and the status endpoint reports accurate counts.
#12Backend
GraphQL API with Resolvers
Set up a GraphQL API in Node + TypeScript (Apollo Server or GraphQL Yoga) for a blog, backed by PostgreSQL. Define User, Post, and Comment types with their relationships (User hasMany Post, Post hasMany Comment). Implement Relay-style cursor pagination for listing posts, a single-post query with nested comments, and search by title. Add mutations to create/update/delete posts with Zod-validated inputs and field-level authorization (only the author or an admin may mutate a post). Solve the N+1 problem with DataLoader batching on every nested association, and enforce query depth and cost limits so a deeply nested query can't DoS the server. Return typed, structured errors that distinguish validation, authorization, and not-found cases instead of leaking internals, and use schema-first codegen so resolver types are generated, not hand-maintained. Handle pagination edge cases (empty page, invalid or stale cursor) and make deletes either cascade or soft-delete consistently across the graph. Done when fetching a list of posts with their comments issues a bounded number of SQL queries (verify it — no N+1), unauthorized mutations are rejected with a typed error, invalid cursors fail gracefully, and the schema and resolver types are generated from one source of truth.
#13Backend
OAuth2 Social Login Integration
Implement OAuth2 social login for Google and GitHub in Node + TypeScript (Express/Fastify) using the authorization-code flow with PKCE. Build the full flow: generate and store a state value and PKCE verifier, redirect to the provider, then on callback verify the state to block CSRF, exchange the code for tokens, and fetch the user profile. Create or link a local account from the profile — and link accounts SAFELY: only auto-link to an existing account when the provider reports the same email AND that email is verified; otherwise require an explicit verification step rather than trusting an unverified address. Store provider access/refresh tokens encrypted at rest, refresh them when expired, and never expose them to the client. After a successful login, issue YOUR OWN session (HTTP-only refresh cookie + access token) instead of relying on provider tokens for app auth. Handle the failure paths: the user denies consent, the state is missing/expired/mismatched, the provider is down, and the email already belongs to a password account. Done when both providers complete login end to end, a forged/mismatched-state callback is rejected, same-email account linking happens only on verified emails, and provider tokens are never sent to the browser.
#14Backend
API Rate Limiter Middleware
Build configurable rate-limiting middleware in Node + TypeScript (Express/Fastify) backed by Redis so limits are shared across instances. Implement three pluggable strategies — fixed window, sliding-window log, and token bucket (burst-friendly) — selectable per route. Key limits by authenticated user when available and fall back to the client IP for anonymous requests, parsing the IP safely from trusted proxy headers (do not blindly trust a spoofable X-Forwarded-For). Support tiered limits (free 60/min, pro 600/min), per-route overrides, and a bypass list for health checks. On every response set the standard headers (X-RateLimit-Limit, -Remaining, -Reset) and, when exceeded, return 429 with Retry-After. Make the Redis operations atomic (a Lua script or pipeline) so concurrent requests can't over-count past the limit, and decide explicitly — by configuration — whether to fail open or closed when Redis is unreachable. Handle clock skew, distributed race conditions, and very bursty traffic. Done when concurrent requests right at the limit never exceed it due to a race, tier and per-route overrides apply correctly, the documented headers and the 429/Retry-After behavior match real responses, and the Redis-down behavior is the one you configured.