Case study · Private source

Demand Management System

A web platform for an IT team to register development requests, track deadlines and give management a real view of what is in progress — replacing email threads, spreadsheets and verbal requests with a single record.

Role
API, data model, web UI
Stack
Python · FastAPI · PostgreSQL
Front end
TypeScript · Bootstrap
Source
Private — not published
Screen recording of the application. The interface is in Portuguese, the language of its users.

Overview

Requirements, bug reports and improvement requests reached the development team through email, spreadsheets and hallway conversations, so nothing had a reliable owner, priority or history. This platform gives every request a single record that the team works from and that management can read without having to ask around. Its users are the developers, testers and team leads of an IT department that supports several products at once.

My contribution

I built the REST API in Python with FastAPI, designed the relational model in PostgreSQL, and implemented the web interface and the reporting views. That covers the request lifecycle and its state machine, the role and permission rules, the batch grouping, the comment and attachment flow, the scheduled notification job, and the dashboard and ranking queries.

The source is private and belongs to its organisation, so this page describes behaviour and decisions rather than linking to code. The screenshots below come from the running application.

What changes day to day

  • Traceability: every request is recorded with an owner, deadlines and its progress, so the information lives in one findable place.
  • Controlled intake: creating a new demand is restricted to management and administrator roles — an explicit product rule that removes informal queues and keeps the team on what was agreed.
  • Board and indicators: a Kanban view for the people doing the work, summaries and charts for the people deciding, with panels the administrator can adapt, including which blocks appear on the home page.
  • Grouped work: batches gather demands that belong to the same theme or release, so they can be planned and communicated together.
  • Conversation next to the request: comments and attachments stay attached to the demand, and notifications and email alert whoever needs to act.
  • Visible effort: the ranking and the activity log make the team's effort and pace legible over time.

Architecture

A static front end and a REST API served from a single origin behind a reverse proxy, with PostgreSQL as the only source of truth. The API is layered into routers, services and repositories; a scheduled job runs alongside it to send deadline and assignment notifications.

Request flow through the demand management system The browser loads the static front end and calls the REST API through a single reverse proxy origin. The API authenticates the request with a JWT held in an HttpOnly cookie, or a Bearer header for integrations, then passes through routers, services and repositories to PostgreSQL. A scheduled job runs beside the API and sends notifications by email. Browser TypeScript UI Reverse proxy single origin static files + /api Auth JWT cookie · Bearer header Routers FastAPI · OpenAPI schema Services permissions, state machine Repositories SQL, transactions Scheduled job deadline & assignment alerts SMTP email notifications to assignees PostgreSQL demands, batches, users, comments, history The scheduled job reads the same database and sends notifications by email
Request flow as implemented. Simplified: middleware, logging and static asset caching are omitted.

Stack

  • Backend: REST API in Python with FastAPI; services and repositories kept separate; scheduled tasks for notifications.
  • Front end: modular pages written in TypeScript, Bootstrap for layout, interactive charts for the indicators.
  • Data: PostgreSQL — a relational model with referential integrity across demands, batches, users, comments and history.

How work flows

  • Kanban board by state — moving a card reflects the real progress of the request.
  • Batches group demands that belong to the same delivery or theme.
  • Formal intake restricted to management and administrator roles, so priority and deadline are explicit from the start.
  • Dashboard and ranking turn effort and pace into figures leadership can follow.

Delivery

  • Authentication: JWT in an HttpOnly cookie for the web client; the API also accepts a Bearer header for integrations. Repeated failed sign-ins are throttled.
  • API contract: documented REST endpoints, with the interactive OpenAPI/Swagger explorer enabled in the appropriate environments.
  • Deployment: step-by-step setup for a new server — PostgreSQL, build, reverse proxy — covering both Windows and Linux hosts.

Engineering decisions

1. Restricting demand creation to management roles

Decision:
only management and administrator roles can open a demand; developers and testers work on what already exists.
Alternative:
letting anyone open a demand and relying on triage to sort out priority afterwards.
Reason:
the problem being solved was an informal intake queue. Enforcing the rule in the permission layer, rather than in a process document, is what actually removes it.
Limitation:
people who spot a problem but cannot open a demand have to go through someone who can, which adds a step.

2. A JWT in an HttpOnly cookie, with Bearer as a second path

Decision:
the browser receives the token in an HttpOnly cookie; the same API accepts an Authorization: Bearer header for integrations.
Alternative:
keeping the token in localStorage, which is simpler for the front end to handle.
Reason:
an HttpOnly cookie is not readable by page scripts, which removes the most common way a token leaks; serving the front end and the API from one origin avoids cross-origin cookie handling.
Limitation:
cookie-based authentication needs its own cross-site request protection, and the Bearer path has to be kept to service integrations rather than becoming a second login route for the browser.

3. Keeping history in the relational model

Decision:
state changes, comments and assignments are recorded as rows in PostgreSQL with referential integrity to the demand.
Alternative:
application logs, or a document store for activity events.
Reason:
"who changed what and when" has to be queryable next to the demand itself, and the reports filter on the same data by date range, state, system and owner.
Limitation:
the history tables grow with activity and need index maintenance and an archiving policy over time.

Results and limitations

What the system delivers is described above and shown in the screenshots: a single record per request, a board reflecting real state, batch grouping, filtered reports by date range, state, system and owner, and dashboards for leadership. The catalogue of systems is administrable, which matters when one team follows several products on the same board.

Stated limitations

  • No published metrics. I have not run a controlled before-and-after measurement, so no percentage improvement, cycle-time reduction or adoption figure is claimed here.
  • The source is private. The repository belongs to its organisation and is not public, so the code behind this page cannot be reviewed. Only the screenshots and this description are available.
  • No public demo. The system runs inside its organisation's network; there is no hosted instance to try.
  • Interface in Portuguese. The application is built for Portuguese-speaking users; the screenshots reflect that.