All projects
Haziq Nazeer
BackendSocial Platform Backend (Instagram for Dogs)2025 — Present

Frizbee

The NestJS backend for an Instagram-style social network for dogs — feed, Reels, 24h Stories, a full social graph and push — designed with keyset pagination and 37 database indexes to scale toward 1M+ users.

Backend Engineer
Frizbee preview

01 — Overview

The project

Frizbee is the backend for an Instagram-style social platform built for dogs: a photo / Reels feed, ephemeral 24-hour Stories, a full social graph (followers, mutual friends, blocks), “Wolf Pack” communities, reactions and threaded comments, and push notifications. It's a NestJS 11 + Prisma + PostgreSQL API with Redis, BullMQ, an S3 / CloudFront media layer and an FFmpeg HLS transcode pipeline.

Role

Backend Engineer

Timeline

2025 — Present

Stack

9 technologies

02 — Context

Problem & approach

The problem

A social feed has to stay fast as data grows into the millions of rows: offset pagination collapses, naïve queries trigger N+1 explosions, ephemeral content must expire reliably, media can't be pushed through the API, and blocks / privacy must be enforced on every read — all without slowing the hot path.

My approach

I designed the data model and queries for scale from day one. The feed uses keyset (cursor) pagination backed by composite (createdAt DESC, id DESC) indexes — 37 indexes and uniques across 24 models — so feed reads stay O(limit) regardless of table size. Viewer reactions and context are batch-loaded to kill N+1s; hot signals (Pick-of-the-Litter, viral cutoff) are precomputed off the request path and cached in Redis. Three independent BullMQ queues (media, notifications, push) isolate retry domains, an hourly cron expires Stories in bounded batches, and media uploads go direct to S3 via presigned URLs with an FFmpeg HLS transcode worker that streams from S3 to stay memory-light. Engineered to scale toward 1M+ users.

03 — Showcase

A closer look

Reels — delivered through the FFmpeg HLS video pipeline

Reels — delivered through the FFmpeg HLS video pipeline

Dog profiles and the social graph the API models

Dog profiles and the social graph the API models

Search and discovery across posts and Wolf Packs

Search and discovery across posts and Wolf Packs

04 — Capabilities

Key features

01

Dual feed

Photo / text Posts and video Reels, with FOR_YOU, followers and friends scopes.

02

Keyset pagination

Cursor pagination on every list, backed by composite indexes — O(limit) reads.

03

Ephemeral Stories

24-hour Stories with hourly, batched, memory-bounded TTL cleanup.

04

Social graph

Followers (“pawollers”), mutual friends and symmetric blocks.

05

“Wolf Pack” communities

Group spaces with bidirectional invite / request join negotiation.

06

HLS video pipeline

FFmpeg adaptive-bitrate transcode with instant-playback fallback.

07

Aggregated push

“X and N others” deduped notifications delivered via Firebase FCM.

05 — Contribution

My role

As Backend Engineer, here is exactly what I owned and delivered on this project.

  • Built the entire NestJS backend — 16 modules, 24 Prisma models, 31 migrations.
  • Designed the indexed schema (37 indexes / uniques) and the keyset-paginated, privacy- and block-aware feed engine.
  • Eliminated N+1s by batch-loading viewer reactions and context per page.
  • Built the event-driven notification + FCM push pipeline across 3 BullMQ queues with independent retries.
  • Built the S3 + CloudFront media layer and the FFmpeg HLS transcode worker that streams from S3.
  • Built ephemeral Stories with cron-driven, batched TTL cleanup and Redis-cached feed signals.

06 — Engineering

Challenges I solved

Challenge

Feed pagination has to stay fast at millions of rows.

Solution

Keyset (cursor) pagination with take limit+1 over composite (createdAt DESC, id DESC) indexes — O(limit) reads instead of offset scans that degrade with depth.

Challenge

Rendering a feed page risked an N+1 storm of per-post reaction lookups.

Solution

Batch-loaded the viewer's reactions for the whole page in one query (postId IN …) and loaded block / friend context once via Promise.all.

Challenge

Ephemeral Stories must reliably disappear without exhausting memory.

Solution

An hourly cron deletes expired stories in bounded pages (100×100), removing S3 objects before DB rows, backed by an expiresAt index.

Challenge

A Firebase outage shouldn't corrupt notification state or double-send pushes.

Solution

Split push into its own BullMQ queue with per-device jobs, idempotency via a pushSentAt marker, and dead-token pruning.

07 — Toolbox

Built with

NestJSPrismaPostgreSQLRedisBullMQAWS S3CloudFrontFFmpeg / HLSFirebase FCM

08 — Impact

Outcomes

1M+

Designed to scale to users

37

Targeted DB indexes

O(limit)

Keyset-paginated feed

Next project

Vybstack

AI Social Platform Backend

Want something like this built?

I'm available for freelance work. Let's build yours.

Hire me