Inspiration

Florida law gives renters real leverage when a landlord won't fix something — Fla. Stat. §83.56(1) requires the landlord be given written notice and 7 days to cure a maintenance problem before a tenant has any real remedy. Almost no student renter in Gainesville knows this exists, and the ones who do usually don't know how to write the letter, track the clock, or prove any of it happened later. The gap isn't the law — it's the paperwork. That felt like a problem software could actually close in six hours, for a population (renters, mostly students) sitting in the room with us.

What it does

RepairRecord turns "my landlord is ignoring me" into a defensible paper trail. A tenant photographs the problem and writes one sentence. The app:

  • Timestamps and hashes the photo server-side at the moment it's uploaded, so the record can't be backdated or disputed later.
  • Classifies the issue with Google Gemini — category, severity, and whether it plausibly affects habitability — from the photo and description.
  • Drafts a statutorily-formatted 7-day notice, with the tenant's facts filled in and the §83.56 citation included.
  • Tracks the cure deadline from the moment the tenant marks the notice delivered, with a live countdown.
  • Exports a single PDF evidence packet — photos, timestamps, hashes, the notice, and the full event log — that a tenant can hand to a legal-aid clinic or small claims court.

It's built to say clearly, on every screen, that it is documentation and a template, not legal advice, with links to UF Student Legal Services and Three Rivers Legal Services.

How we built it

One FastAPI app — Jinja2 templates, Tailwind, SQLite, and xhtml2pdf for the packet — deployed on Render. We avoided a separate frontend/API split so there was one thing to deploy and no CORS to fight with a six-hour clock.

The key design decision was how narrowly we scoped what Gemini is allowed to do. It doesn't write the notice — it writes one paragraph of it. Given the photo and the tenant's raw description, Gemini (in JSON-schema mode) returns a category, a habitability judgment, and a short factual description of what's broken, written in the tenant's voice with no legal language. Our own Python code — not the model — owns the letter's actual legal content: the date, the addresses, the §83.56 citation, the 7-day cure language, the delivery-method footer. Gemini's paragraph gets slotted into that fixed template. The model never sees the statute and never decides what a tenant is entitled to do; it only describes what's in front of the camera.

We split three ways to avoid blocking each other: one person owned the UI and the timeline/disclaimer design, one owned the Gemini classification and letter-drafting logic, one owned storage, the PDF packet, and deployment. We agreed on the data shape (a single JSON blob per issue) in the first fifteen minutes and built against a shared fixture file until integration, which meant almost no merge conflicts all day.

[Add anything specific your team actually did differently today.]

Challenges we ran into

  • Deciding what the model is allowed to write. Our first instinct was to have Gemini draft the whole letter. We backed off that once we thought through what happens if it phrases a legal conclusion wrong — so we rebuilt the letter as a fixed template and shrank Gemini's job to one factual paragraph, with an explicit instruction not to cite law or state legal conclusions.
  • PDF rendering. We initially planned to use WeasyPrint, but its system dependencies (Pango, Cairo) are a real install risk on a laptop you didn't set up yesterday. We switched to xhtml2pdf, pure pip, at the cost of a much smaller supported CSS subset — no flexbox, no grid — so the packet template stayed in plain tables and inline styles.
  • Making the record trustworthy. A photo on a phone proves nothing about when it was taken. The server, not the client, is responsible for the timestamp and a SHA-256 hash of every photo at upload, so the packet can't be argued with later.
  • Designing for a bad day. Our actual user is stressed, possibly overheated, and on a phone. We kept the capture flow to one screen with a single required field and let boilerplate (name, address, landlord) persist locally so a second report takes ten seconds.

[Add any specific bug or moment that actually happened today — judges like one concrete story more than a list.]

Accomplishments we're proud of

A tenant can go from "my AC is broken" to holding a formatted legal notice and a defensible evidence packet in under two minutes, with no account, no login, and no legal knowledge required.

What we learned

The more we constrained what the model was allowed to generate, the more we trusted the output. Letting an LLM draft an entire legal letter felt powerful and was actually the wrong instinct — pulling the legal skeleton out into code and giving Gemini one narrow, checkable job made the whole tool more defensible, not less capable.

What's next for RepairRecord

Partnering with UF Student Legal Services for real-world distribution; adding landlord-response tracking; and — with permission and anonymization — aggregating repair reports into a public repair-complaint map by property, so patterns of neglect become visible before a tenant ever has to search for them.

Built With

Share this project:

Updates

Submission history