Deep Dive into Building a Feedback System with TypeScript and PostgreSQL Without Leaving It an Abandoned Inbox
Learn how to design an efficient feedback collection and developer notification system, preventing lost or ignored messages using the Transactional Outbox architecture.

Stock photo for illustration only, not from the actual event
- Creating a feedback button is easy, but building a production-ready backend management system is much more challenging.
- PostgreSQL should be used as the primary database to store raw data before dispatching notifications through other channels.
- Use the Transactional Outbox pattern to prevent issues with unrecorded data or notification failures midway.
- Clearly separate the steps of data ingestion, triage, and product prioritization from one another.
Installing a feedback button on a website or application is extremely easy nowadays, but the real challenge lies not in the input form, but in the management process after a user clicks submit. This article presents an approach to building a compact yet production-ready feedback system using an architecture composed of TypeScript, Express, and PostgreSQL, which can be adapted for bug reports, feature requests, support questions, or in-product conversations.
The lifecycle of a useful feedback system should consist of capturing data through a browser or application, forwarding it to the Feedback API, storing it in a PostgreSQL database via the Transactional Outbox pattern, and sending it to a Notification Worker before distributing it to communication channels such as chat, email, or issue-tracking systems. The core principle is that PostgreSQL acts as the single Source of Truth, while chat tools or email are merely delivery surfaces, not databases.

In software engineering, using the primary database as the starting point before forwarding to external systems (such as chat or email) helps solve external network instability issues. If the chat service goes down while a user submits data, the system will not lose the message because it has already been successfully saved in the database. Beyond feedback systems, this concept is also commonly applied to user verification email systems or payment notification systems.
When designing the database, developers should enable UUIDs, create necessary tables with care, and avoid recording context data that could infringe upon privacy, such as Access Tokens, full form contents, complete URLs, Local Storage data, or sensitive user traits. Furthermore, technical data should be collected immediately at the time the user submits a report to avoid having to ask users later what screen or version they were using.
A classic issue in notification systems is that if the system saves data to the database and then the application crashes before sending the notification, that message will be ignored without anyone knowing. Alternatively, if the order is reversed to notify first and then save to the database, a successful notification might occur even if the data save fails. A safe solution is to use the Transactional Outbox pattern, which commits the report data and notification request together in a single transaction, allowing multiple workers to safely pull tasks using the FOR UPDATE SKIP LOCKED command, while routing tasks to a Dead-Letter state if failures exceed a specified threshold.
Good feedback management is not just about receiving messages and calling it a day; it requires triage that records both status changes and historical context. New feature requests do not always need to be placed on the roadmap; marking a status as "Reviewed and Closed" is a valid outcome as long as it is clear. Moreover, a feedback channel remains healthy only if message neglect is actually measurable, starting by setting readiness criteria based on service-level commitments the team can genuinely maintain, and avoiding labeling a channel as "Live" if there is no team monitoring it around the clock.
Source: Dev.to
Found something wrong in this article? Report an issue with this article
Comments
Leave a Comment