ChatNET
A real-time, multi-user chat app I'm building to go deep on SignalR, Redis and real-time systems that scale across server instances.
- Role
- Solo project
- Status
- In active development
- Type
- Direct & group chat
01The problem
Chat looks simple until you run more than one server. A message has to reach users connected to a different instance, clients drop and reconnect mid-conversation, and unread counts and presence have to stay correct throughout.
I wanted a project that forces those problems into the open, and that is built and tested the way I'd want a production service to be.
02My role
I designed and built the whole thing: the ASP.NET Core backend, the React frontend, the data model, the tests and the CI pipeline.
Direct (1:1) and group conversations share a single data model.
03Architecture
Write
- React clientTanStack Query
- REST endpointvertical slice · MediatR · validation
- PostgreSQLEF Core
Live
- API instancemessage saved
- SignalR hubone group per conversation
- Redis backplanefan-out · presence
- React clientZustand store merges sources
04Key decisions
REST for writes, SignalR for pushes
Sending a message is a normal, validated, testable HTTP request. SignalR is only used to push events out to connected clients, which keeps the hub thin and the write path easy to reason about.
Redis backplane and presence
SignalR's Redis backplane fans events out across server instances, and Redis also tracks who is online, so a user on one instance sees messages and presence from users on any other.
Reconnection catch-up
When a client reconnects it fetches what it missed, and the frontend store merges messages arriving from REST history and the live stream without duplicates.
Correctness in the database
A unique index guarantees there is only ever one direct conversation between two users, so the invariant holds even under concurrent requests.
Vertical slices
The backend is organised by feature (Auth, Users, Conversations, Messaging) with MediatR and FluentValidation, and every error comes back as an RFC 7807 problem response.
Production habits from day one
Rate limiting and account lockout on login, security headers, dependency health checks, integration tests against real Postgres and Redis containers, tests that assert database query cost, and a CI pipeline that lints, builds, tests and audits dependencies.
05Outcome
- Shipped: registration and login, conversations and user search, live messaging, paginated history, reconnection catch-up, unread counts, read receipts and online presence.
- Next up: refresh tokens, notifications, file uploads, structured logging, distributed tracing and deployment.
06Stack
- .NET 10
- ASP.NET Core Minimal APIs
- SignalR
- MediatR
- FluentValidation
- EF Core
- PostgreSQL 16
- Redis 7
- React 19
- TypeScript
- Zustand
- TanStack Query
- Tailwind CSS
- Docker Compose