← Back to archive

ParkFlow: From Requirements Gathering to an AI-Assisted MVP

How we turned a real parking problem into an MVP with TypeScript, Supabase, license-plate-driven UX, and AI-assisted development.

ParkFlow started as the final project of the first semester of the Systems Analysis and Development program, in the Prompt Engineering and AI Applications course.

The proposal was to build a parking system with the support of artificial intelligence and a vibe coding tool. However, the project stopped being just a quickly generated screen once we started discussing business rules, operator experience, data integrity, and technical limitations.

This article documents the MVP creation process, the main decisions made, and what I learned during development.

ParkFlow is an educational and prototyping project. Features related to cameras, license-plate recognition, barrier gates, and other devices should be treated as simulations or future possibilities until a real, validated integration exists.

The problem we wanted to solve

Running a parking lot involves more than registering a car entering the premises.

A system like this needs to answer questions such as:

  • how many spots are still available?
  • is a given vehicle already in the parking lot?
  • how much should be charged for the parking time?
  • does the customer have an active monthly subscription?
  • how do we preserve the history of entries, exits, and payments?
  • how do we prevent data from different accounts from getting mixed?

We also realized that customer service could slow down if the operator had to fill in name, CPF, and complete vehicle details at every entry.

The central idea of ParkFlow became:

Centralize and streamline parking lot operations, reducing manual tasks and inconsistencies.

Requirements gathering

Before treating the project as a product, we organized the requirements into categories.

Functional requirements

Among the features identified were:

  • registering vehicle entries;
  • issuing receipts with a QR Code or barcode;
  • calculating the fee based on parking time;
  • registering monthly subscribers and tracking payments;
  • generating daily and monthly revenue reports.

Non-functional requirements

We also recorded expectations related to system quality:

  • responsive interface;
  • fast entry registration;
  • data protection;
  • availability during operation;
  • backup strategy.

These items were defined as project requirements, but they should not be mistaken for proven guarantees. Metrics such as 99,9% availability, full encryption, and automatic backup require specific implementation, infrastructure, and testing.

Less obvious requirements

Some needs only surface when we think about real-world operation:

  • preventing two active entries for the same license plate;
  • freeing the spot after exit;
  • keeping change logs;
  • preserving history for several years;
  • migrating data from old spreadsheets;
  • configuring thermal printers and barrier gates in the future.

This survey showed that a good-looking interface would not be enough. The system needed to represent operational rules.

The project’s technical foundation

The structure analyzed in the project uses:

AreaTechnology or organization
LanguageTypeScript
Web applicationVite
Runtime and dependenciesBun
Backend and databaseSupabase
Versioned databaseMigrations
QualityESLint and Prettier
InterfaceComponents and styles organized within the project

The main organization was separated by responsibility:

src/
├── components/
├── hooks/
├── integrations/
├── lib/
├── routes/
├── router.tsx
├── server.ts
└── styles.css

supabase/
├── migrations/
└── config.toml

docs/
└── prompts/

The intent of this structure is to keep interface, reusable rules, integrations, and data access from getting mixed together.

A simplified view of the architecture is:

flowchart LR
    U[Operador ou administrador] --> UI[Aplicação web]
    UI --> AUTH[Autenticação]
    UI --> MOD[Operações e gestão]
    MOD --> DB[(Supabase)]
    DB --> UI
    MOD --> INT[Integrações simuladas ou futuras]

How we used AI during development

One of the main lessons was not trying to generate the entire system with a single prompt.

We split requests by responsibility:

  • interface and UX;
  • authentication;
  • backend;
  • database;
  • spot management;
  • billing;
  • testing;
  • future integrations;
  • specific refinements.

The format that helped the most was:

Contexto
Problema atual
Objetivo
Regras de negócio
Requisitos técnicos
O que não deve ser alterado
Resultado esperado

We also used a specific prompt to analyze and improve other prompts before execution. The idea was to identify missing context, ambiguities, architecture risks, and forgotten requirements.

The workflow ended up looking close to this:

flowchart LR
    A[Identificar problema] --> B[Escrever prompt específico]
    B --> C[Revisar contexto e restrições]
    C --> D[Executar alteração]
    D --> E[Testar resultado]
    E --> F{Resolveu?}
    F -- Não --> B
    F -- Sim --> G[Documentar decisão]

In practice, the prompt started working as a small technical specification. The clearer the rules, the lower the chance that a change would break unrelated parts.

First version: fast, but not yet operational

The first generated version let us visualize the MVP quickly. It already featured modules such as dashboard, Smart Check-in, Smart Gate, monitoring, spot map, vehicles, plans, and settings.

However, the interface had many items with the same visual priority, large cards, and spacing that did not help the operator make decisions.

ParkFlow's initial interface

The problem was not merely aesthetic. The screen needed to look like an operations center, not a collection of independent pages.

Refining the interface as an operations center

The refinement reorganized navigation into groups such as:

Operações
Gestão
Sistema

The cards became more compact, and the dashboard started prioritizing information such as:

  • free spots;
  • revenue of the day;
  • vehicles served;
  • average stay duration;
  • entry flow;
  • recent activities;
  • operational alerts.

ParkFlow's refined dashboard

The main change was one of hierarchy. Instead of showing everything with the same weight, the interface started highlighting what the operator needs to track during work.

The most important UX decision: start with the license plate

The initial flow required a lot of data before registering an entry. That increased service time and repeated information from already registered customers.

The solution was to make the license plate the first step of the process.

flowchart TD
    A[Operador informa a placa] --> B{Veículo cadastrado?}
    B -- Sim --> C[Preencher dados existentes]
    B -- Não --> D[Cadastro rápido]
    C --> E{Existe entrada ativa?}
    D --> E
    E -- Sim --> F[Bloquear duplicidade]
    E -- Não --> G{Há vaga disponível?}
    G -- Não --> H[Informar estacionamento lotado]
    G -- Sim --> I[Registrar entrada]
    I --> J[Atualizar ocupação e dashboard]

This flow brought some important rules:

  • optional CPF in quick registration;
  • license-plate search;
  • autofill for known vehicles;
  • duplicate entry blocking;
  • capacity validation;
  • loading, success, and error states;
  • keyboard-friendly use and use on mobile devices.

The improvement was not just visual. It changed the sequence of the operation to reduce friction.

Authentication and data isolation

One of the first problems found was instability in the authentication flows:

  • sessions ending unexpectedly;
  • login failures;
  • sign-up not working correctly;
  • password recovery with issues;
  • protected routes needing review.

The fix had to consider more than the login screen. It was necessary to review:

  • session persistence;
  • tokens and storage;
  • authentication provider configuration;
  • callbacks and redirects;
  • direct access to private routes;
  • queries tied to the authenticated user.

Another central requirement was data isolation.

Conta A → somente dados da Conta A
Conta B → somente dados da Conta B

In a system with Supabase, this requires correctly filtered queries and access policies in the database. Hiding data in the frontend is not enough.

Data integrity: not everything should be deleted

An interesting problem appeared when removing a vehicle that already had registered entries.

The database blocked the deletion because there were historical records linked to the vehicle. Deleting everything in cascade would solve the technical error but would destroy operational and financial information.

The decision was to separate two scenarios:

SituationBehavior
Vehicle with no historyCan be permanently deleted
Vehicle with historyMust be archived
Currently parked vehicleRemoval must be blocked

Archiving, also known as soft delete, removes the vehicle from operational listings without erasing old entries, exits, payments, or reports.

Fields planned for this strategy include:

archived_at timestamp null
archived_by uuid null
archive_reason text null

This decision showed why database rules cannot be treated as secondary interface details.

Safe deletion of zones and spots

Spot management also needed to allow deleting an entire zone without forcing the user to delete each spot individually.

But this action could not be unrestricted.

The defined flow was:

  1. select the zone;
  2. open a modal with the name and number of spots;
  3. report how many are free and occupied;
  4. block the operation if any spot is occupied;
  5. delete the zone only when all spots are free;
  6. preserve entry, exit, and payment history;
  7. automatically update the interface.

This is an important difference between “adding a button” and implementing a safe operation.

Full account backup and export

Another evolution was allowing the export of all of an account’s data, not just one category at a time.

The proposal considers three formats:

CSV

Since CSV does not support multiple tables in a single file, the idea is to generate a .zip containing separate files:

vehicles.csv
subscriptions.csv
plans.csv
access_logs.csv
entries_exits.csv
payments.csv
infractions.csv
parking_spots.csv
parking_zones.csv
settings.csv

XLSX

A spreadsheet with one tab per data type.

JSON

A structured file:

{
  "exportedAt": "2026-06-22T00:00:00.000Z",
  "ownerId": "identificador-da-conta",
  "data": {
    "vehicles": [],
    "subscriptions": [],
    "plans": [],
    "entriesExits": [],
    "payments": [],
    "parkingSpots": []
  }
}

The most important rule is that the export must respect the authenticated user and never include:

  • data from other accounts;
  • tokens;
  • keys;
  • environment variables;
  • internal secrets;
  • unnecessary sensitive information.

Smart Gate and future integrations

The Smart Gate was designed to demonstrate a possible automated flow for monthly subscribers:

flowchart TD
    A[Veículo se aproxima] --> B[Simular leitura da placa]
    B --> C[Buscar veículo e assinatura]
    C --> D{Plano ativo?}
    D -- Sim --> E[Simular acesso autorizado]
    E --> F[Registrar evento]
    D -- Não --> G[Exibir acesso negado]

The project was also planned for future integrations with:

  • IP cameras;
  • RTSP streams;
  • OCR/LPR providers;
  • barrier gate controllers;
  • spot sensors;
  • QR Code readers;
  • thermal printers.

The documentation, however, makes the limitation clear: these features are simulated or planned. They do not represent an already validated physical integration.

This distinction matters so as not to present a prototype as if it were a production hardware system.

Outcome of the process

ParkFlow evolved from a visual MVP into a proposal with rules closer to a real product.

DecisionProblem facedExpected result
License-plate check-inRepetitive typingFaster service
Duplicate blockingTwo entries for the same vehicleOperational consistency
Capacity controlEntry with no available spotReliable occupancy
Per-user isolationData mixing between accountsMulti-user security
Vehicle archivingDeletion breaking historyRecord preservation
Safe zone deletionSlow or risky administrationControlled operation
Full exportFragmented backupData portability
Modular promptsBroad, unpredictable changesIncremental refinement

What I learned

1. Requirement is not the same as a ready feature

Documenting a need is only the beginning. Availability, encryption, backup, and performance need to be implemented and measured.

2. UX depends on the operational context

The best form is not necessarily the one that collects the most data. In a parking lot, starting with the license plate makes more sense than starting with the CPF.

3. History integrity should guide the database

Deleting a primary record can affect entries, payments, and reports. In some cases, archiving is better than deleting.

4. Security must exist in the database

Filtering data only in the interface does not guarantee isolation. Rules must be enforced in queries and access policies.

5. Better prompts work as specifications

Providing context, constraints, business rules, and acceptance criteria produces more predictable results than generic requests.

6. Simulation must be presented as simulation

Prototypes can demonstrate advanced ideas, but they need to clearly communicate what is real, what is simulated, and what is still on the roadmap.

Next steps

The project documentation points to the following priorities:

  1. fully validate login, sign-up, recovery, and session persistence;
  2. test data isolation with different accounts;
  3. confirm check-in and check-out rules;
  4. validate billing calculation and monthly subscribers;
  5. review the actual Supabase migrations;
  6. create tests for the most critical rules;
  7. improve accessibility and responsiveness;
  8. implement real integrations only after technical definition and testing;
  9. review LGPD, backup, and audit requirements before any production use.

Project reference

Diagrama ampliado
100%
↑↓ to navigate · Enter to open 8 items in the index