Traverse rapid-fire + the RabbitMQ claim, handled
25 questions on your own product, plus the exact script for the resume discrepancy.
Know your own system
The drill set, then the script.
- What is Traverse? → passive DSA capture (extension) + spaced-repetition scheduling + streaks/analytics, iOS app + backend.
- How does capture work? → MAIN-world network interception in the extension; platform adapters normalize judge responses; POST with idempotency key + device id.
- Why a queue? → 15 s LLM ladder off the request path; 10 s → 0.2 s p95 (Day 4).
- Which queue, precisely? → BullMQ on Redis. (And the resume script — see below.)
- How do you dedup submissions? →
@@unique([userId, idempotencyKey]); duplicate POST returns 200 with the existing row. - What happens on the AI provider failing? → ladder falls through (BYOK Gemini → server Gemini → Groq → G4F), JSON cleaned/validated, heuristic fallback, scheduling never blocks on AI.
- How does scheduling work? → FSRS-style memory state per problem/user-topic; due dates from retrievability targets (0.85); predictions persisted with model version; calibration measured.
- What's the calibration harness? → predicted vs observed, bucketed by modelVersion (Day 72).
- Free vs premium? → AI signals nulled at one choke point for free users; the deterministic scheduler path is always exercised.
- How do notifications work? → intent (Notification) + per-channel ledger (NotificationDelivery) with lease claim, backoff, terminal statuses; push best-effort via APNs/FCM; in-app truth.
- Why no WebSockets? → push for closed apps, polling for freshness, no stateful socket fleet (Day 73).
- Cache strategy? → cache-aside, per-data TTLs (120–600 s), worker-driven invalidation, 2 s timeouts, degrade-to-no-op.
- Redis policies? → noeviction (queue safety over cache elasticity), AOF, removeOnComplete bounds (Day 46).
- What breaks at 2 replicas? → in-memory rate limiters and node-cron jobs (Day 50).
- Biggest query perf win? → streak walk 300→2 queries; achievements 120→4 (Day 28).
- Durability? → WAL archiving to S3, 5-min RPO, Aiven offsite, executable restore endpoints (Day 34).
- Deploy? → GitLab CI → SSH → compose, git-reset + rebuild + health gate, migrate-on-boot refusing stale schemas.
- Security posture? → bcrypt-12, strict auth limits, webhook HMAC over raw body, log redaction, BYOK isolation; debts: hardcoded provider key, two timing-unsafe compares (Day 90).
- How do you know it works? → integration tests replaying real migrations, per-feature regression tests (the wiring bugs I found and guarded), calibration for the scheduler.
- Social graph? → double-row friendship, canonical pair streaks with CHECK constraint, blocks filtered by a single visibility predicate.
- What's the recon feature? → streaming unbounded capture dumps to disk,
.partial+ atomic rename, per-platform quota, digest email (Day 82). - Biggest scaling limit? → single VPS, single Redis, in-memory limiters; the ladder is Redis-backed limits → read replicas → partition submissions.
- What would you rebuild? → submission outbox (close the enqueue gap), Redis split, token expiry on JWTs, encrypted BYOK keys.
- Why Node/TypeScript? → one language across extension, backend, tooling; the workload is I/O-bound, not CPU-bound.
- What are you proudest of? → the fact/derivation split that made a 50× latency win safe, and the calibration harness that measures the scheduler instead of asserting it works.
The RabbitMQ script (memorize verbatim)
If asked "your resume says RabbitMQ for Traverse":
"My resume summarizes the pattern as a message queue — the implementation is BullMQ over Redis, and RabbitMQ is the technology in my other project, Zoth. The architectural decision is identical in both: decouple ingestion from downstream processing so user-facing writes don't pay for slow side effects. In Traverse I chose a Redis-backed queue because the jobs are small triggers whose truth lives in Postgres, and a single VPS didn't need a second broker; in Zoth I chose RabbitMQ because provisioning events needed broker-native retry accounting, DLQ semantics, and process isolation — and I can go deep on either."
Then pivot to what you did build (the 50× win), not to the discrepancy. Own it, don't litigate it.
Bulletproof your resume
Say these answers aloud before moving on
These are the follow-ups an interviewer will actually ask about your projects.
You're asked to compare BullMQ and RabbitMQ — answer from experience.
BullMQ: Redis-backed, jobs as Redis structures, delayed/repeatable jobs, per-queue concurrency and rate limits, jobId-based dedup, stalled-job recovery, AOF for restart durability; ops cost is one Redis you already run. RabbitMQ: real broker semantics — exchanges and routing keys, prefetch-based credit flow control, per-message ack/nack, x-death retry accounting, dead-letter exchanges, and language-agnostic clients; ops cost is a broker to run. I've shipped both: BullMQ for the product pipeline where the DB holds truth and jobs are triggers; RabbitMQ where provisioning events needed DLQ/retry semantics and process isolation from request handling.
What's the strongest technical story in Traverse?
The fact/derivation split and its measured consequence: submissions and solves are durable facts written synchronously; revisions, streaks, rings, achievements, and notifications are derivations computed by workers from those facts. That let me move the entire AI ladder (15 s timeouts, multiple providers) off the request path for a 50× p95 improvement without weakening durability — and it also means derived state is rebuildable, which is why Redis losing a job degrades features instead of corrupting truth. The calibration harness is the same philosophy applied to the algorithm: measure rather than assert.
What's the weakest part of your answer set?
Anything about the client side — the extension's interception details and the iOS app are the parts I've spent least time in recently, and an interviewer who probes MAIN-world vs isolated-world interception or SwiftUI state management could go deeper than I can answer fluently today. That's on my study list, and it's an honest boundary rather than a bluff: I'd rather say 'that's the layer I know least' than invent details about code I didn't write.