Hazem Azzam.
All projects
Full Stack

BookTomb

BookTomb is a personal book library platform — users register, upload book files, and read them. The API that powers it is built in NestJS 11 on PostgreSQL via Prisma 7, and every module follows Clean Architecture with four layers and a strict inward dependency rule: the domain layer knows nothing about NestJS, Prisma, HTTP or JWT, and infrastructure adapters plug into abstract ports that double as dependency-injection tokens. The identity module implements JWT authentication with refresh-token rotation, token families and reuse detection — replaying a used refresh token revokes the entire family. The catalog module handles book uploads through an upload-intent flow with per-uploader content deduplication on (sha256, uploaderId), cursor-paginated listings, per-field metadata correction and signed cover URLs, with an hourly cron reaper clearing intents abandoned for 24 hours. A health module probes Postgres, Cloudflare R2 and Upstash Redis with per-dependency latency, and a shared kernel provides a generic domain-error-to-HTTP filter so modules add new errors without ever editing the filter. As Product Owner I defined the domain model, the module boundaries and the upload/deduplication contract, and wrote the full documentation set: a hand-authored OpenAPI 3.0.3 specification as the single source of truth, per-module READMEs, architecture/testing/documentation convention docs. The product is still in progress: the API is the first shipped piece, with an admin dashboard, an Android client for readers and a public website planned on top of it.

Aug 2026 - Present

Overview

A personal book library platform — a NestJS + Prisma backend built strictly on Clean Architecture, with an admin dashboard, Android app and website in progress.

Key Challenges

  • Prisma 7's breaking changes: the prisma-client generator emits ESM by default, which crashes a CommonJS NestJS app — solved by pinning moduleFormat="cjs" and runtime="nodejs" and moving to a multi-file schema folder with one .prisma file per module.
  • Prisma 7 requires an explicit driver adapter, so the Prisma service had to be rebuilt on @prisma/adapter-pg + pg rather than relying on the implicit engine connection.
  • Making deduplication safe under concurrency without a distributed lock — the (sha256, uploaderId) unique index is the lock, and the insert conflict is itself the deduplication signal.
  • Keeping the domain layer genuinely framework-free: no NestJS decorators, no Prisma types, no argon2 imports — forcing every dependency through ports and mappers at the infrastructure edge.
  • Upstash exposes one Redis database over both REST and TCP; the health check uses REST while BullMQ needs TCP, so the REST token had to be documented as doubling as the TCP password.
  • @nestjs/schedule shipped an ESM-only release that broke the CommonJS build — resolved by downgrading to the last CJS-compatible version.

Key Achievements

  • Designed and shipped a strict Clean Architecture backend — four layers per module (domain / application / infrastructure / presentation) with ports modelled as abstract classes that double as DI tokens, and a composition root per module.
  • Built JWT authentication with refresh-token rotation, token families and reuse detection: replaying a already-used refresh token invalidates the entire token family.
  • Implemented an upload-intent flow with per-uploader content deduplication keyed on (sha256, uploaderId), using the database's unique constraint itself as the lock instead of an application-level mutex.
  • Shipped a global rate-limiting policy (120 req/min) with tighter per-route caps for login, registration and upload-intent, exempting the health endpoint so uptime monitors are never throttled.
  • Authored a complete documentation set — per-module READMEs, architecture/testing/documentation conventions, Docker and database operations guides, plus a learn-by-doing lesson series for the identity module.
  • Wrote a 1,600-line hand-authored OpenAPI 3.0.3 specification as the single source of truth for the API, with inline examples per response and shared error envelopes — importable directly into Apidog.