
AposenteJá: From Retirement Intake to Secure Document Operations
How we turned a sensitive retirement-intake process into a structured workflow with private uploads, operational tracking, and deliberate document controls.
The problem was not merely building a form
A retirement case begins well before a benefit calculation. The team must identify who is requesting assistance, collect personal information, understand the intended benefit, record the case history, and review documents that may contain sensitive data.
When this process is scattered across messages, spreadsheets, and attachments, predictable problems emerge: incomplete submissions, documents without context, repeated intake work, and limited visibility into what has already been reviewed.
AposenteJá was built to turn that fragmented intake into a single workflow. The solution combines a guided public experience, traceable administrative operations, and an architecture where private files do not need to pass through the application server on their way to storage.
The goal is not to replace specialized human analysis. It is to give professionals a better-organized case, with the information they need to begin and controls appropriate for the sensitivity of the submitted data.
A journey that structures intake at the source
The submission experience is divided into four short stages:
- identify the source of the service request;
- collect the client's personal and contact information;
- complete the retirement-intake questionnaire;
- select and upload supporting documents.
This structure reduces the visual weight of a long form and gives context to each group of questions. Masks for Brazilian identifiers, phone numbers, dates, and postal codes assist input, while validation runs both in the browser and on the server.
The intake captures the intended benefit, retirement history, situations that may require attention, and service notes. Documents therefore arrive as part of a structured case instead of as isolated files.
The form also preserves its draft in the browser. Moving between steps or interrupting the process does not force the user to rebuild the entire case. Once a submission succeeds, the state is cleared so previous data cannot leak into a new registration.
Consent belongs in the flow, not in the footer
At the final stage, users review the consent terms before completing the submission. Acceptance is mandatory and is also part of the server-validated contract.
This choice does not turn an interface into a legal compliance guarantee. It establishes a more responsible product foundation: purpose presented at collection time, affirmative user action, and consistent validation before persistence.
We also avoid personal information in file paths. The browser receives only opaque, temporary identifiers for the upload. Private URLs, credentials, and internal storage names are not exposed in pages, exports, or administrative responses.
Direct, private, and verified uploads
Documents are the most sensitive part of the journey, so the upload flow was designed in three movements.
First, the application creates an idempotent submission in PostgreSQL and reserves the expected slots. Each PDF, JPG, or PNG is then sent directly from the browser to private Vercel Blob storage. Finally, the application verifies the received objects before marking the submission as complete.
Finalization checks file count, path, type, and size. The current limit is ten documents, up to 10 MB each. A repeated attempt must not create a second lead or mix objects from different sessions.
Direct upload avoids transporting large files through a Vercel Function request body and reduces the number of places where content exists. The client is still not treated as the source of truth: authorization and finalization remain server responsibilities.
The dashboard turns submissions into operations
After intake, work continues in an authenticated administrative dashboard. The team can search submissions, filter and sort results, open lead details, export data, and follow each case's progress.
Every registration starts with the New status. Once it moves to another stage, it cannot return to that initial state. The interface reflects this rule, while the server also enforces it and persists both the transition and its history atomically.
This prevents status from becoming a merely visual label. It represents an operational event: who changed it, when it changed, and which state came before. The history preserves enough context for another team member to understand progress without relying on informal memory.
Documents need their own lifecycle
Adding a delete button would have been easy, but inappropriate for sensitive files. In AposenteJá, permanent removal is preceded by a manual quarantine.
An administrator records a reason and confirms the registration's identity. During quarantine, the document is unavailable for regular use but can still be restored. Permanent deletion only becomes available after a minimum waiting period and requires a second, reinforced confirmation.
Downloads, quarantines, restorations, and deletions produce audit evidence. If a storage operation ends in an uncertain state, the system keeps an administrative reconciliation alert instead of pretending the operation succeeded.
This decision separates two concerns that are often conflated: removing database metadata and removing the physical object from storage. The product tracks both sides of the process.
The architecture behind the product
AposenteJá uses Next.js 16, React 19, TypeScript, and Tailwind CSS 4. Input contracts are defined with Zod, while Vitest and Testing Library verify components, validation, and workflows.
Neon/PostgreSQL stores leads, upload sessions, document metadata, status history, and audit events. Private Vercel Blob stores the files, which the dashboard accesses through authenticated and audited routes.
Responsibilities remain separate:
- the browser presents the journey and sends files directly;
- application routes validate identity, contracts, and authorization;
- PostgreSQL maintains operational state;
- Blob maintains private content;
- an optional webhook can connect completed submissions to another service.
The application does not apply migrations automatically. They are part of the deployment gate, because publishing code before the required database structure would create a version that looks healthy while remaining operationally incomplete.
What this system solved
More consistent intake. Cases arrive organized by source, client, retirement context, and documentation.
Less repeated work. Progressive validation, masks, and draft preservation catch errors before submission.
Visible operations. Statuses, filters, details, and history help the team follow each lead.
Files outside the public path. Documents stay in private storage and are accessed through authenticated routes.
Safer retries. Idempotent sessions prevent duplication during retries and network interruptions.
Deliberate deletion. Quarantine, restoration, reinforced confirmation, and auditing make removal a process instead of an irreversible click.
The main lesson
In products that receive sensitive data, security cannot exist only in infrastructure. It must be visible in the user journey, enforced by contracts, and preserved in everyday operations.
AposenteJá connects these layers. Users get a clear path to organize their case, the team receives more consistent data, and the system maintains explicit boundaries around uploads, access, transitions, and deletion.
The result is more than a landing page with a form. It is an operational foundation that turns a complex retirement-service intake into a process that is understandable, traceable, and ready to evolve.
A public version of the project is available on GitHub.