Rent Desk
Demo data

Setup

Two connections make this real: the Google Sheet that holds the numbers, and an AI key so the assistant can hold a conversation. Everything works without them, on sample data.

Where things stand
Spreadsheet
.data/portfolio.json
Not set
Assistant model
Keyword matching only, until an AI Gateway key is added
Not set
Who can do what
Open, and add-only. Anyone with the link can add entries but cannot change existing rows. Set APP_PASSCODE before putting this on the internet.
Not set
What is in there now
2 properties · 30 units · 26 current tenants · 77 payments · 12 expense entries
Connect your Google Sheet
A service account is a robot Google account. You share the sheet with its email address, and this app signs in as that robot. No passwords to keep up with.
  1. 1. Make the spreadsheet. Create a blank Google Sheet and copy the long id out of its address bar, the part between /d/ and /edit.
  2. 2. Make a service account. In the Google Cloud console, enable the Google Sheets API, then create a service account and a JSON key for it.
  3. 3. Share the sheet with it. Share your spreadsheet with the service account's email address as an Editor.
  4. 4. Add the environment variables.
    GOOGLE_SHEET_ID=your-spreadsheet-id
    GOOGLE_SERVICE_ACCOUNT_JSON={"client_email":"...","private_key":"..."}
    AI_GATEWAY_API_KEY=your-ai-gateway-key
    APP_PASSCODE=her-passcode-adds-entries-only
    OWNER_PASSCODE=your-passcode-can-also-edit

    Locally that is a .env.local file. On Vercel they go in the project's environment variables.

  5. 5. Build the tabs. Once the variables are set, this button creates every tab with the right column headers.
Add the Google variables first, then restart the app.
What each tab holds
You can always type in the sheet by hand. The assistant reads and writes these same columns, so keep the headers as they are.
TabWhat it is forColumns
PropertiesOne row per apartment complex.property_id, name, address, city, state, zip, notes
UnitsOne row per door, with market rent and whether it is occupied, vacant, or being renovated.unit_id, property_id, unit_label, beds, baths, sqft, market_rent, status, notes
TenantsOne row per tenant, past and present, with lease dates and monthly rent.tenant_id, unit_id, name, phone, email, status, move_in_date, move_out_date, lease_start, lease_end, monthly_rent, deposit, rent_due_day, notes
PaymentsEvery dollar collected: rent, late fees, deposits.payment_id, date, unit_id, tenant_id, period, category, amount, method, reference, notes
ChargesExtra amounts owed on top of rent, mostly late fees.charge_id, date, unit_id, tenant_id, period, type, amount, status, notes
RenovationsRenovation projects per unit, with a budget and a status.renovation_id, property_id, unit_id, scope, status, start_date, target_date, completed_date, budget, contractor, notes
MaintenanceWork orders and repair requests.work_order_id, date_reported, property_id, unit_id, issue, priority, status, vendor, scheduled_date, completed_date, notes
ExpensesMoney spent, optionally tied to a renovation project or work order.expense_id, date, property_id, unit_id, category, vendor, amount, description, renovation_id, work_order_id, notes
RequestsChanges that need the owner: move-outs, corrections, anything that means editing a row. Added here instead of changed in place.requested_at, requested_by, about, request, status
SettingsLate fee amount, grace period, and other preferences.key, value, notes
ActivityLogA log of every change the assistant makes, so nothing is a mystery later.logged_at, actor, action, details