UUIDs, serials, and dedup sets in your projects — the details
The concrete ID and dedup mechanics across zoth and traverse, with the pagination reality.
Know your own system
The applied version of yesterday. Walk each mechanism with its file paths.
Zoth — UUIDs everywhere, one dedicated dedup table
- Every entity:
google/uuid.UUID(v4). SQLC overrides mapuuid↔ Go type, nullable → pointer (emit_pointers_for_null_types). - Event correlation:
AccessGrantedEvent{RequestID, TenantID, UserID, ResourceID, ...}— the request UUID threads through the whole lifecycle: API → outbox (aggregate_id) → RabbitMQ payload → emitter's resolve → audit metadata. When something breaks, one UUID greps the entire story across services in Better Stack. That's the operational argument for stable cross-service IDs — say it. - Dedup key:
<routingKey>:<request_id>inprocessed_events— note what it is: a namespaced natural key, not a generated ID. Dedup keys should be derived from the event's identity, never randomly minted (a random key dedups nothing). aggregateOf(event): the outbox storesaggregate_id = RequestIDfor known event types,uuid.Nilotherwise — event sourcing's aggregate concept, minimally: events are attributed to the business object they concern, which is what makes "show me everything about request X" one indexed query.- List endpoints:
LIMIT CASE WHEN $n > 0 THEN $n ELSE 2147483647 END— the optional-pagination SQL idiom (one query serves both).
Traverse — serials, one natural composite key per concern
Submission.idserial → keyset pagination on the inbox (WHERE id < cursor ORDER BY id DESC) — the pattern needs monotonic ids, and traverse has them.- Dedup by natural composite keys, one per race class:
(userId, idempotencyKey)submissions;(platform, slug)problems;(userId, problemId)solves;(solveId, revisionNumber, type)revisions;(notificationId, channel)deliveries;(blockerId, blockedId)blocks; canonical(userId1 < userId2)friend streaks. Notice: no dedup table at all — every duplicate concern is a unique constraint on the table that owns the entity. The DB constraint is both the truth and the fast path. - JobId-keyed enqueues (BullMQ dedupes by job id):
broadcast-fanout-<id>,notification-push-drain— generated IDs are dedup keys when the unit is "this job should exist once." - Calendar token:
HMAC-SHA256(JWT_SECRET, userId)truncated to 16 hex — a derived, stateless ID for the public .ics feed: revocable only by rotating the secret (know this weakness: no per-user revocation — a per-user random token column would fix it).
The cross-cutting lessons to recite
- Dedup key = the natural identity of the event/entity, namespaced by type when one ID legitimately appears in multiple event types (zoth's routingKey prefix).
- Constraints double as indexes — the duplicate-check lookup is the constraint's index; no separate "seen" table unless the entity table would bloat (zoth's events are ephemeral → dedicated
processed_eventswas the right call; traverse's dedup targets are the entities). processed_eventsneeds a TTL — it grows unboundedly; a cron deleting rows older than the broker's max redelivery window (days, not forever) is the missing piece. Say it as the known gap + fix.
Bulletproof your resume
Say these answers aloud before moving on
These are the follow-ups an interviewer will actually ask about your projects.
Why does zoth need a dedup table when traverse doesn't?
Because the dedup subject differs: zoth dedups transient events (broker redeliveries) — nothing else in the schema represents 'this delivery happened', so a dedicated processed_events table with insert-on-conflict is the minimal truth. Traverse dedups entities (submissions, problems, revisions) — the entity table itself can carry the unique constraint, which is both the rule and the lookup index. The design rule: dedup lives with whichever table owns the fact; only mint a dedicated table when the fact is otherwise stateless.
How does one request's story get traced across your three services?
The request UUID is the correlation key: it's the outbox aggregate_id, the event payload's RequestID, the audit row's target_id, and the dedup key's suffix. So one UUID queries outbox_events, greps emitter logs (OTel spans carry it in attributes), and pulls the audit history. Stable cross-service identifiers are the cheapest observability investment I made — no distributed tracing magic needed to answer 'what happened to request X'.
What's wrong with your calendar feed token?
It's HMAC(secret, userId) — stateless and revocable only by rotating the global secret, which invalidates every user's feed at once. The fix is a per-user random token column (rotate per user, revoke per user) at the cost of a DB write on rotation. It's a deliberate tradeoff at 100 users, and it's the exact trade I'd revisit first if the feed carried anything sensitive — it currently exposes only revision schedule times.