Skip to content

Back to projects

Freelance project

In production, since July 2026 I'm responsible for the architecture, code review, testing and security; the code is generated with AI under my direction.

Field Report Manager

Web app where installation technicians log each report with its photos from their phone, and the supervisor reviews and approves it. It replaced a three-step process built on WhatsApp and manual data entry.

Client
UxmalTechnologies
Context
Freelance · Individual project
Period
June 2026 – present
Technologies
  • FastAPI
  • Python
  • React
  • TypeScript
  • Next.js
  • Material UI
  • Supabase
  • PostgreSQL
  • Docker
  • Render
  • GitHub Actions
  • Supabase Auth
  • Supabase Storage

Key points

  1. Replaced a three-step workflow — a WhatsApp form, manual data entry by another person, and separate evidence collection — with a single form where the technician logs the report and attaches photos, with known data pre-filled.

  2. Implemented authentication with Supabase Auth and role-based access: each technician sees only their own reports, and each supervisor sees those of their assigned technicians. The supervisor reviews, corrects, and approves; the system generates the PDF and exports the history to Excel.

  3. ONT inventory: the administrator imports devices from Excel with a preview of new, existing, and repeated entries; the supervisor assigns them to each technician, and a report only accepts an ONT assigned to whoever fills it in.

  4. Built for fieldwork with poor signal: photos are compressed on the phone before upload, requests are retried when the network fails, and the form warns before closing if there are unsaved photos.

Problem

Each installation report went through three steps: the technician filled out a form over WhatsApp, another person typed that data in by hand, and the evidence photos were sent separately. The same information was written twice, and the photos were kept apart from the report they belonged to.

Solution

The technician fills in the report from their phone in four sections (general information, customer, installation, and geolocation) and uploads the eight evidence photos each installation requires. The server assigns the technician, supervisor, and team from the session, and the ONT field only lists the devices assigned to that technician. Once submitted, the report goes to review: the supervisor checks it, fixes what is needed, and approves it, and at that point the system generates the PDF with the data and photos. The history can be exported to Excel by date range. An administrator manages users, teams, and the ONT inventory, which is imported from Excel.

Technical decisions

  • I served the API under /api on the same domain as the frontend, through a rewrite rule on Render. With the frontend and API on two onrender.com subdomains, the session cookie was third-party and Safari blocked it: login failed on iPhone and worked on desktop Chrome. The backend now refuses to start if the two origins are not on the same site.
  • The PDF is built with a 250 KB limit: the general photos are reduced first, and the ONT and R20 form photos stay sharp because they are used for technical verification. When a report is approved, its photos are deleted from storage and the PDF remains as the record; a weekly job removes approved reports older than one year, per the business's retention rule.
  • The client never sets the status, technician, team, or settlement date: the server does. Every sensitive endpoint applies the role and resource filter on the read and again on the write, and operations that can collide (installing or reassigning an ONT, approving or deleting a report) run in transactional Postgres functions.
  • Every fixed vulnerability has a regression test in pytest. Continuous integration runs them alongside pip-audit, npm audit, and gitleaks.

Failure handling

  • If the network fails, each request is retried twice before showing an error, and if the session has expired it is renewed once and the request is repeated.
  • The save and submit buttons are disabled while a request is in progress, so a double tap on a slow connection does not create a duplicate report. If the draft was saved but sending it to review failed, the retry updates that same draft.
  • Before a report goes to review or gets approved, the server checks the required fields, the eight photos, the coordinates, and that the ONT belongs to the technician, and replies with the exact list of what is missing.
  • PDF generation and photo uploads have concurrency and rate limits; when the server is busy, it replies with a clear message to try again instead of hanging.

My role

I built it on my own, end to end: the FastAPI API, the React and TypeScript frontend, the data model and migrations in Supabase, authentication with Supabase Auth and role-based access, PDF generation, the Excel export, and the deployment on Render, with continuous integration on GitHub Actions. I maintain it today.

Results

  • Used by five technicians and one supervisor, with ongoing maintenance.
  • The technician records the data and photos in one place; nobody retypes the report by hand anymore.
  • Each approved report is stored as a PDF with its data and its eight photos, ready to download from the supervisor's panel.

Code kept private due to client confidentiality; screenshots, architecture, and a demo available upon request.