Skip to main content
Professional Project

Tipsy To GoEvent Management Platform Backend

A NestJS and PostgreSQL backend for an event management platform, with Stripe payment integration and Firestore-backed real-time chat.

  • NestJS
  • TypeScript
  • PostgreSQL
  • TypeORM
  • Redis
  • Firebase Firestore
  • Stripe
  • REST APIs

Project snapshot

Project type
Event Management Platform Backend
My role
Backend Developer
Contribution
Backend Development
Project context
Professional Project

Project Overview

Tipsy To Go is an event management platform. Its backend holds the events, the user records and the relationships between them, and it coordinates the two external services the product depends on: Stripe for payments and Firebase Firestore for real-time chat.

The business problem is coordination. An event has people attached to it, money attached to it and conversation attached to it, and all three have to stay consistent with each other — a payment Stripe never confirmed must not read as paid, and a conversation about an event has to be reachable by the people actually attached to that event.

I contributed to this project as a Backend Developer, as part of my employment. My work covered the server side — event and user APIs, the PostgreSQL data model, authentication, Stripe payment integration and the Firestore-backed chat functionality — rather than the complete product, which was built by a team.

What stands out

  • Event and user management REST APIs
  • Stripe payment integration with state driven by reported outcomes
  • Firestore-backed real-time chat alongside the REST API

My Role

Backend Developer — Professional Contribution

I worked on the backend: NestJS modules and REST endpoints for events and users, the PostgreSQL data model through TypeORM, authentication and authorisation, Redis-supported caching, Stripe payment integration and the Firestore-backed real-time chat functionality.

The product is owned by my employer and was delivered by a team. This case study documents the backend responsibilities I held within it, not ownership of the platform.

What I was responsible for

  • NestJS modules and REST endpoints for event and user domains
  • PostgreSQL schema and TypeORM entities, relations and migrations
  • Authentication and authorisation on protected endpoints
  • Event workflow logic on the server side
  • Stripe payment integration and the payment state it drives
  • Firebase Firestore integration for real-time chat
  • Redis-supported caching for repeatedly requested data

Services Delivered

The work actually performed on this project, and nothing beyond it.

  • Backend Development

    Server-side application structure, modules and business logic in NestJS and TypeScript.

  • API Development

    REST endpoints for event and user operations, consumed by the platform's client applications.

  • Database Design

    A PostgreSQL model for events, users and their relationships, expressed as TypeORM entities.

  • Authentication & Authorisation

    Sign-in handling and authorisation checks in front of protected endpoints.

  • Payment Integration

    Stripe integration, with the platform's payment records following what Stripe reports rather than what a request assumed.

  • Real-Time Communication

    Firestore-backed chat, so messages reach connected clients without the API being polled for them.

  • Third-Party API Integration

    Stripe and Firebase wired in as separate, configured integrations rather than scattered SDK calls.

  • Business Workflow Development

    Event workflow rules applied on the server, so every client sees the same behaviour.

Functionality

How the system works in practice, workflow by workflow.

  1. Event creation and management

    Events are created and updated through backend endpoints, with the server validating and recording them. The event record is what payments, participation and conversation all hang off.

  2. User accounts and interactions

    User records and their relationships to events are held on the backend, so what a given user may see or do about a given event is answerable from stored data rather than from client state.

  3. Event-related backend operations

    The screens in the client applications are backed by REST endpoints that apply the platform's rules before anything is persisted, which keeps behaviour identical across clients.

  4. Chat communication

    Chat runs on Firebase Firestore, with clients subscribing to conversation data directly and receiving updates as they are written. The NestJS API remains the authority for events, users and payments, while Firestore carries the message stream.

  5. Payment processing

    Payments are handled through Stripe. The platform records the outcome Stripe reports for a payment rather than assuming a request succeeded, so what the database calls paid is what actually cleared.

  6. Authentication and authorisation

    Callers authenticate before reaching protected endpoints, and authorisation runs ahead of business logic, so event and payment operations cannot be reached by simply knowing a URL.

  7. Data management

    Events, users and payment records are modelled relationally in PostgreSQL through TypeORM, with validation at the API boundary keeping malformed data out.

  8. Redis-supported functionality

    Data that is read repeatedly and changes rarely is served from Redis, so recurring reads do not become recurring database queries.

Key Features

What the system does, and what each capability is worth to the business running it.

  • Event management APIs

    Endpoints for creating, updating and retrieving events, with the platform's rules applied server-side.

  • Event workflow management

    The states an event moves through, handled on the backend so every client reads the same progression.

  • User and customer management

    User records and their relationships to events, kept as the reference for what each user may access.

  • Authentication and authorisation

    Protected routes with authorisation applied before any logic that reads or changes data.

  • PostgreSQL data model

    Events, users and payment records modelled relationally with TypeORM entities and migrations.

  • Redis caching

    Repeatedly requested, rarely changing data served from Redis to keep recurring reads off the database.

  • Real-time chat via Firestore

    Firestore carries the message stream, so clients receive conversation updates as they happen instead of polling an endpoint.

  • Stripe payment integration

    Payments processed through Stripe, with the platform's records following the outcome Stripe reports.

  • REST backend APIs

    One NestJS module per domain, so event, user, payment and integration concerns stay separable.

Challenges & Approach

The engineering problems this project actually presented, why each was difficult, how it was approached and what changed as a result.

  • Real-time chat alongside a request/response API

    The problem
    Chat needs messages to arrive as they are sent. A REST API answers questions when asked, so making it carry a conversation means either polling it constantly or building a second delivery mechanism.
    Why it was difficult
    Introducing a real-time store means the product now has two places data can live, which raises the question the architecture has to answer clearly: what belongs where, and how records in one stay identifiable from the other.
    Approach
    Firestore was used for the message stream, with clients subscribing to it directly, while the NestJS API stayed the authority for events, users and payments. Identifiers shared between the two keep a conversation tied to the event and users it belongs to.
    Outcome
    Messages reach connected clients without the API being polled, and the relational data that has to be authoritative stays in PostgreSQL rather than being split across stores.
  • Keeping payment state and application state consistent

    The problem
    Stripe is the authority on whether money moved; the platform database is the authority on what was booked. If the application marks something paid because a request looked successful, those two records can disagree — and the disagreement is about money.
    Why it was difficult
    Payment flows have intermediate and failed states, and calls to an external processor can succeed, fail or be interrupted. Treating a submitted payment as a completed one is the easy mistake to make and the expensive one to find later.
    Approach
    Payment records on the platform side are driven by the outcome Stripe reports for a payment, so the application's notion of paid is derived from the processor rather than assumed at request time. The integration is confined to its own module.
    Outcome
    The platform does not carry records marked as paid that Stripe never confirmed, and payment handling stays in one place rather than spreading through event logic.
  • Modelling events, users and payments relationally

    The problem
    An event has users attached to it, payments attached to those users, and conversation attached to the event. Each of those relationships is a query someone will need, and the wrong model turns all of them into application-side assembly.
    Why it was difficult
    Event data is naturally many-to-many and the same records are read from several directions — by event, by user, by payment — so the schema has to serve more than one access pattern without duplicating data.
    Approach
    The PostgreSQL schema was designed around those relations and expressed as TypeORM entities, with migrations keeping schema and code in step as the model developed.
    Outcome
    The common questions about an event are answerable in a query, and the database enforces the relationships rather than leaving them to application discipline.
  • Depending on several external services at once

    The problem
    Stripe and Firebase each bring their own SDK, credentials and failure modes. Called directly from wherever they are needed, they spread configuration and error handling across the codebase.
    Why it was difficult
    Every external dependency is a part of the system that can fail for reasons the application cannot see, and the more places it is called from, the more places have to handle that.
    Approach
    Each integration was given its own module and configuration, so credentials and client setup live in one place per service and the rest of the application calls a local interface rather than a vendor SDK.
    Outcome
    Integration concerns stay contained, and a change in how a service is reached is a change in one module instead of a search through the codebase.
  • Consistent authentication across API and chat

    The problem
    Users authenticate against the platform, but chat data lives in Firestore. Identity has to mean the same thing in both places, or a user can be someone in one system and someone else in the other.
    Why it was difficult
    Authorisation also has to run before business logic on every protected route, consistently enough that adding an endpoint does not mean re-deciding how it is protected.
    Approach
    Authentication and authorisation were handled in front of the route handlers at the framework level, with user identity from the platform used as the reference for chat participation.
    Outcome
    Protected endpoints are protected by how they are declared, and the identity a user has in chat is the identity the backend issued them.

Technologies Used

The stack this project runs on, grouped by the job each part does.

Backend

  • NestJS
  • TypeScript
  • REST APIs

Data

  • PostgreSQL
  • TypeORM
  • Redis

Integrations

  • Stripe
  • Firebase Firestore

Cross-cutting

  • Authentication & authorisation
  • DTO validation

Technical Highlights

  • NestJS backend architecture with one module per domain
  • Relational PostgreSQL modelling through TypeORM entities and migrations
  • Firestore-backed real-time communication alongside a REST API
  • Stripe integration with payment state derived from reported outcomes
  • Redis-supported caching for repeated reads
  • REST API development with DTO-defined contracts
  • Authentication and authorisation applied ahead of business logic
  • Event management business logic held on the server

Results & Impact

What changed in practice. No figures are quoted here, because none are published for this project.

  • Event operations handled through APIs

    Events, users and their relationships are managed through endpoints that apply the same rules to every client, instead of behaviour differing by app.

  • Payment records that match the processor

    The platform's payment state follows what Stripe reports, which keeps the database from claiming money moved when it did not.

  • Conversation without polling

    Chat is delivered through Firestore subscriptions, so real-time messaging does not turn into constant requests against the API.

  • Reliable backend and API architecture

    Domain modules, boundary validation and framework-level authorisation give the client applications a predictable surface to build on.

  • Contained integrations

    Stripe and Firebase are configured and called in one place each, so external dependencies stay reviewable instead of diffuse.

Where this project fits

Related service pages

Related technology pages

Full stack on this project

  • NestJS
  • TypeScript
  • PostgreSQL
  • TypeORM
  • Redis
  • Firebase Firestore
  • Stripe
  • REST APIs

Follow the stack we would use, the work we have already shipped, or the services that pair with this one.

Need something comparable built?

Describe the system you have in mind and where your current setup falls short. We will tell you how we would approach it and what it would take.

Talk to a DhaTech engineer