Skip to content
Puneet Moger
← All projects

2026 · Backend and full-stack

Guild-Hub

Real-time messaging with channels, roles and uploads.

Role
Backend and full-stack
Year
2026
Discipline
Full-stack · Backend

01 — The problem

Chat looks simple until permissions, history and delivery all have to be correct at once. A message is only useful if the right people can see it, it arrives without a refresh, and it still makes sense when you scroll back a week later.

02 — Approach

  1. 01

    Model the domain before writing transport code: users, channels, memberships and messages as explicit tables with real foreign keys.

  2. 02

    Enforce role checks at the query layer, so channel membership is the unit of authorisation rather than a client-side flag.

  3. 03

    Keep socket events small and namespaced — the socket carries a signal, the database remains the source of truth.

  4. 04

    Reuse one message pipeline for direct messages and channels so the two views cannot drift apart.

03 — What I built

  • One-to-one and channel-based messaging with persisted history.
  • Socket.io services for low-latency delivery across connected clients.
  • File uploads and emoji reactions inside the message flow.
  • Role-based access control backed by a Prisma schema on PostgreSQL.
  • A modular service structure that keeps transport, data access and authorisation separate.

04 — Outcome

  • A single message model serves both private and channel conversations.
  • Permission logic lives in one place, so a new surface cannot accidentally bypass it.

05 — What I learned

Real-time features fail in ways REST does not: duplicate events, reconnects, and messages arriving out of order. Treating the socket as a notification channel and the database as the truth removed most of that class of bug before it existed.

Stack

  • Next.js
  • TypeScript
  • Node.js
  • PostgreSQL
  • Prisma
  • Socket.io