Two phases on a live system: pipeline, documents and finance at JV Elétrica
Case· JV Elétrica

Two phases on a live system: pipeline, documents and finance at JV Elétrica

A solar energy project management system already in production, with 137 active projects. No new stack, no rewrite — incremental work with a database backup before every change.

JV Elétrica works with distributed micro-generation projects — solar energy — and already had its own system live, with 137 registered projects and clients using the portal daily. The request was not to build something new. It was to fix what was broken and extend what was missing, without stopping operations.

The entry decision

No new stack was introduced. We did not rebuild authentication, did not rebuild the schema, did not propose a platform migration. All work was incremental on the system already running in production.

That is a risk decision, not a lazy one. A system with 137 active projects and end clients uploading documents is not an environment for a rewrite. And before any schema change, a full database backup — a commitment made to the client in the first conversation and honored in every round.

Phase 1: the bugs nobody had found

The original scope listed four mapped bugs. One of them was a technical document that would lock up: once the end client uploaded the signed PDF, the record entered a validation state and could no longer be deleted or corrected by anyone. If the file was wrong, the flow simply stopped.

Another was subtler: the server ran on Berlin time, and every timestamp displayed in the system was shifted — not just on the audit screen, but everywhere. It was fixed at the source, not patched screen by screen.

Two problems that were not on the list appeared during execution. The file download link expired after one hour and failed silently — anyone opening it later got no error, it just did not work. And number formatting did not follow the Brazilian standard, which only became visible through a screenshot the client sent after delivery.

The project data form

The central delivery of the first phase was a complete modal form with five blocks: project type, client data, generating unit, generator information and beneficiary units. Uploads for identity document, energy bill, and photos of the metering panel, breaker and building facade.

Two details defined its quality. Total generator and inverter power is calculated in real time as the user types quantity and power — no calculate button, no reload. And the beneficiary unit percentages must add up to exactly 100%, with submission blocked until they do. That is a domain rule, not a generic form validation.

What support surfaced

During the seven days of support, the client reported that an end user had uploaded the wrong document and could not remove it. The root cause was the same rule as the original bug: once signed, the record disappeared from correction options for both the admin and the client. A workaround existed through the admin panel, but it was neither self-service nor obvious.

The fix was a cancel-and-resend button, available to the end client while the document awaits validation. On confirmation, the wrong file is discarded, the record returns to its previous state and the client resends immediately, without depending on the admin — who receives an in-app notification of the cancellation. An additive migration in the database, with a backup taken first.

Fixing the symptom would have meant giving the delete button back to the admin. Fixing the problem meant giving autonomy back to whoever made the mistake.

Phase 2: panel, pipeline and finance

The second phase came through a direct contract, with five items. A user panel in the admin area, with photo change, phone, password reset and deletion. A new failed-inspection stage in the project pipeline. A simplified project creation form — name and notes only — leaving the complete form untouched.

And the financial side: a dashboard with a color system for quick reading of balance and status, a filter for projects with an outstanding balance, a total balance view for the user, and a billing button that sends an email with the consolidated summary of the client account.

What the client's testing found

The client tested on the delivery day itself and raised six items. Worth recording, because that is where the real work shows.

User photo upload failed for two reasons in sequence: first a missing protection header on the request; after fixing that, a storage folder on the server with the wrong owner, which prevented the service from writing. The email for the new failed-inspection stage did not fire because the newly created status had never been mapped in the notification system — no event, no email.

And the user photo did not appear in the portal header because of a much older bug: the session never loaded the image field, which affected all users from the start and had nothing to do with Phase 2. It was fixed along the way.

Process

All work was done through direct server access, without a local clone. Database backup before each round of changes. QA with disposable admin and test client users, deleted afterwards. Clean build and type checks on every round, with deployment confirmed by server response before notifying the client.

Stack

Next.js · TypeScript · NextAuth · PostgreSQL · Contabo VPS