rentED is a property management platform that combines a FastAPI backend and a Next.js dashboard with AI-assisted rental contract ingestion. It streamlines property onboarding, captures structured contract data, and keeps owners, documents, and event logs organized for ongoing operations.
- Overview
- Features
- Tech Stack
- Project Structure
- Quick Start (Docker)
- Environment Variables
- Database Migrations
- Seed Data
- Key Workflows
- Architecture Decisions (ADRs)
- Dashboard Docs and Swagger
- Testing
- Security Notes
- Contributing
- License
rentED focuses on clean contracts, strict ownership rules, and fast onboarding:
- Properties with photos (1 to 10)
- Owner-aware access control (admin sees all, owners see only theirs)
- Contract-driven prefill via LLM suggestions
- Documents linked to properties with download access
- Domain event log with admin/user scoping
- Dashboard highlight view with OpenStreetMap + Leaflet
Suggested GitHub Topics (SaaS-standard):
saas, proptech, fastapi, nextjs, postgres, redis, rq, ai, llm, openai
- Healthcheck:
GET /health - Session-based authentication (HTTP-only cookie)
- Admin-only user management
- Property CRUD with photo uploads
- Contract import suggestions (LLM) inside Create/Edit Property
- Documents linked to properties with downloads
- Activity log for core actions (login, create/update property)
- Work orders module (quote + fixed offer)
- Provider portal with expirable token links
- Alembic migrations and Docker-first setup
- Dashboard map (OpenStreetMap + Leaflet)
- FastAPI
- SQLAlchemy
- Alembic
- PostgreSQL
- Redis + RQ
- LangChain (OpenAI)
- pypdf + optional OCR
- passlib (bcrypt)
- Leaflet + OpenStreetMap (dashboard map)
- Docker Compose
- Next.js
backend/
app/
auth.py
db.py
deps.py
main.py
models.py
schemas.py
ai.py
storage.py
static/
docs.html
dashboard.css
alembic/
scripts/
seed.py
tests/
Dockerfile
requirements.txt
frontend/
components/
pages/
work-orders/
p/wo/
styles/
lib/
next.config.js
package.json
docs/
adr/
0001-public-portal-by-token.md
0002-work-order-status-model.md
0003-proof-requires-pix-and-photo.md
0004-token-hash-and-expiration.md
0005-temporary-provider-identity.md
0006-reuse-documents-storage.md
0007-domain-event-log.md
0008-dashboard-maps-openstreetmap.md
docker-compose.yml
.env.example
README.md
CHANGELOG.md
LICENSE
copy .env.example .env
docker compose up -d --build
docker compose run --rm api alembic upgrade head
docker compose up -d worker
docker compose run --rm api python scripts/seed.py
- API Docs:
http://localhost:8000/docs - Swagger:
http://localhost:8000/swagger - Frontend:
http://localhost:3000
Defined in .env.example:
POSTGRES_USER,POSTGRES_PASSWORD,POSTGRES_DBDATABASE_URL,REDIS_URLOPENAI_API_KEY,OPENAI_MODEL,OPENAI_TEMPERATURE,OPENAI_MAX_TOKENSAI_MODE(liveormock)AI_CONFIDENCE_THRESHOLDAI_LLM_INPUT_MAX_CHARSOCR_MODE(noneortesseract)SESSION_TTL_MINUTES,SESSION_COOKIE_NAME,COOKIE_SECURESEED_ADMIN_USERNAME,SEED_ADMIN_PASSWORD,SEED_ADMIN_NAME,SEED_ADMIN_CELL,SEED_ADMIN_EMAIL,SEED_ADMIN_CPFPORTAL_TOKEN_SECRET,PORTAL_TOKEN_TTL_HOURS
Optional:
UPLOAD_DIR(default:/app/data/uploads)NEXT_PUBLIC_API_BASE(frontend)
docker compose run --rm api alembic upgrade head
Create a new migration after model changes:
docker compose run --rm api alembic revision --autogenerate -m "describe_change"
Seed script creates one admin and sample properties.
Defaults (override in .env):
- Username:
admin - Password:
Admin123!
Run:
docker compose run --rm api python scripts/seed.py
POST /auth/loginGET /auth/mePOST /auth/logout
- Fill the base property fields.
- Upload 1 to 10 photos.
- If rented, upload a contract and click Suggest fields.
- Select fields to apply and click Apply fields.
- Save the property.
The contract document is stored and linked to the property automatically.
- Upload:
POST /documents/upload?property_id=... - List:
GET /documents?property_id=... - Download:
GET /documents/{id}/download
GET /event-logs- Admin sees all entries, other users see only their own.
Admin dashboard endpoints:
GET /work-ordersPOST /work-ordersGET /work-orders/{id}POST /work-orders/{id}/approve-quote/{quote_id}POST /work-orders/{id}/select-interest/{interest_id}POST /work-orders/{id}/request-reworkPOST /work-orders/{id}/approve-proofPOST /work-orders/{id}/cancelDELETE /work-orders/{id}
Provider portal (tokenized, no session cookie):
GET /portal/work-orders/{token}POST /portal/work-orders/{token}/quotePOST /portal/work-orders/{token}/interestPOST /portal/work-orders/{token}/submit-proof
Portal links are generated at creation (quote or fixed interest), and an execution link is generated when a provider is selected for fixed offers.
See docs/adr/ for the decision records covering the provider portal, status model,
token hashing, temporary provider identity, proof requirements, event logging, and
dashboard maps.
/docsprovides a custom interactive dashboard./swaggerprovides full OpenAPI schemas./openapi.jsonreturns raw OpenAPI JSON.
Run tests inside the container:
docker compose run --rm api pytest
- All CRUD endpoints require a session cookie.
- Admin accounts cannot be deleted via the API.
- Uploads are stored locally in
./data/uploads(bind-mounted). - Do not commit
.envor API keys. - Exposed ports are for local dev only; lock them down in production.
- Frontend dev dependency audit: Next.js has known DoS advisories. We are deferring a major upgrade to Next 16.x to avoid breaking changes. Track and upgrade once the frontend migration is planned.
See CONTRIBUTING.md for the workflow and standards.
MIT. See LICENSE for details.
