# Start production application with Docker secrets
make up
# Check status
make status
# View logs
make logs
# Stop application
make downAccess URLs:
- Main Application: http://localhost (nginx proxy)
- Health Check: http://localhost/health
- API Documentation: https://localhost/docs (with SSL)
- Direct Services (optional):
- Frontend: http://localhost:3000
- Backend API: http://localhost:8000
Default Credentials:
- Admin: [email protected] / admin123
- Tenant: [email protected] / tenant123
Rental
- Author: Niklas Hoglund
- Date: 2024-12-19
- Version: 1.0
- Status: Draft
To create a web portal for apartment tenants to manage rental details and communicate with landlords, while providing administrators tools to manage invoices and public messages. This system aims to streamline the rental management process by providing a centralized platform where tenants can access their rental information and administrators can efficiently manage property operations.
The system will allow tenants to:
- Log in securely to view apartment details and specifications
- Access past, current, and future invoices with payment status
- View a wall of posts from the property admin for announcements and updates
- Download PDF invoices when available
- Receive email notifications for new invoices and important updates
It will allow administrators to:
- Create and manage apartments with flexible rent rates (per year and month)
- Create and assign tenants to specific apartments through the web interface
- View and manage all tenants with their apartment assignments
- Create invoices mapped to apartments and tenants with due dates and amounts
- Mark invoices as paid and track payment history
- Post public messages visible to all tenants with categorization
- Upload and attach PDF files to invoices
- Search and filter through posts and invoices
- Tenant authentication with secure login system
- Apartment detail visibility with comprehensive specifications
- Invoice tracking (past, current, future) with payment status
- Admin apartment and tenant management capabilities through web UI
- Admin invoice creation and status tracking capabilities
- Admin message board with categorized posts and search functionality
| Role | Description | Key Capabilities |
|---|---|---|
| Tenant | Rents an apartment | View apartment, invoices, admin messages |
| Admin | Manages tenants and financials | Assign/view invoices, post messages |
| Developer | Implements and maintains the system | Backend, frontend, database, deployment |
- Secure login with password authentication
- View apartment specifications and details
- View past, current, and future invoices with payment status
- Read admin wall posts with filtering and search capabilities
- Receive invoice notifications by email
- View/download attached PDF invoices (if present)
- Filter and search admin wall posts by category or keywords
- Responsive interface for mobile and desktop access
- Admin login interface with role-based access control
- Create and manage apartments with flexible rent rates (per year and month)
- Create and assign tenants to specific apartments through web UI
- View and manage all tenants with apartment assignments
- Create invoices mapped to apartments and tenants with due dates and amounts
- Mark invoices as paid and track payment history
- Attach PDF files to invoices for documentation
- Create and edit categorized/timestamped posts
- Posts searchable by keyword or category
- Dashboard view of all tenants and their invoice status
- Bulk operations for invoice management
- Linux server (Debian 12.x)
- Nginx 1.24+ as reverse proxy
- PostgreSQL 15+ as primary database
- Python 3.11+ with FastAPI 0.104+ backend
- Docker 24+ for containerization
- Redis 7+ for caching and session management
- HTTPS for all traffic with SSL/TLS encryption
- Passwords stored securely using hashing (bcrypt recommended)
- Role-based access control (admin vs. tenant)
- Input validation to prevent XSS/SQLi attacks
- JWT tokens for session management
- Rate limiting to prevent brute force attacks
- Responsive UI across devices (mobile, tablet, desktop)
- Support for at least 500 concurrent users
- Invoice load time < 1s on average
- Database query optimization with proper indexing
- Caching layer for frequently accessed data
id(Primary Key)name(VARCHAR)email(VARCHAR, unique)password_hash(VARCHAR, bcrypt)apartment_id(Foreign Key to Apartment)created_at(TIMESTAMP)last_login(TIMESTAMP)is_active(BOOLEAN)
id(Primary Key)address(VARCHAR)unit_number(VARCHAR)specs(JSONB for flexible specifications)created_at(TIMESTAMP)
id(Primary Key)apartment_id(Foreign Key to Apartment)year(INTEGER)month(INTEGER, 1-12)amount(DECIMAL)created_at(TIMESTAMP)- Unique constraint on (apartment_id, year, month)
id(Primary Key)apartment_id(Foreign Key to Apartment)tenant_id(Foreign Key to Tenant)amount(DECIMAL)due_date(DATE)status(ENUM: pending, paid, overdue, cancelled)description(TEXT)pdf_attachment_url(VARCHAR, nullable)created_at(TIMESTAMP)paid_at(TIMESTAMP, nullable)
id(Primary Key)title(VARCHAR)content(TEXT)created_at(TIMESTAMP)category(VARCHAR)created_by(Foreign Key to Admin)is_published(BOOLEAN)
id(Primary Key)name(VARCHAR)email(VARCHAR, unique)password_hash(VARCHAR, bcrypt)created_at(TIMESTAMP)last_login(TIMESTAMP)
| Milestone | Description |
|---|---|
| M1 - Setup | Initial server + project scaffolding with Docker, FastAPI, and PostgreSQL setup |
| M2 - Core Models/API | Database models, FastAPI endpoints for Tenants, Invoices, Admin Posts |
| M3 - Admin Dashboard | Admin interface for Invoice + Post management with CRUD operations |
| M4 - Tenant Portal | Tenant interface for apartment view, invoice wall, and post reading |
| M5 - Auth & Security | JWT authentication, password hashing, role-based access control |
| M6 - Deployment | Production deployment with Nginx, SSL, and monitoring setup |
- Should tenants receive email notifications for invoices?
- Should invoices support attachments (PDF)?
- Should admin posts be categorized/timestamped or searchable?
| Question | Decision |
|---|---|
| Tenants should receive invoice notifications via email | ✅ YES |
| Invoices should support PDF attachments | ✅ YES |
| Admin posts should be categorized, timestamped, and searchable | ✅ YES |
- Docker and Docker Compose
- Python 3.11+ (for local development)
- Node.js 18+ (for local development)
-
Clone the repository
git clone <repository-url> cd rental
-
Run the setup script
./scripts/setup.sh
-
Configure SMTP (Optional - for email functionality)
./scripts/setup_smtp.sh
This will help you configure SMTP settings for sending invoice emails with PDF attachments.
-
Start the application
docker-compose up -d
-
Seed initial data
docker-compose exec backend python scripts/seed_data.py -
Access the application
- Frontend: https://localhost
- API Documentation: https://localhost/api/docs
- Admin Panel: https://localhost/admin
- Admin: [email protected] / admin123
- Tenant 1: [email protected] / tenant123
- Tenant 2: [email protected] / tenant123
The system supports sending invoice emails with PDF attachments. To configure SMTP:
-
Run the SMTP setup script
./scripts/setup_smtp.sh
-
Follow the interactive prompts to configure:
- SMTP Server (e.g., smtp.gmail.com)
- SMTP Port (usually 587)
- Username (your email address)
- Password (your email password or app password)
-
For Gmail users: Enable 2-Factor Authentication and generate an App Password
-
For other providers: Use your regular email credentials
-
Test the configuration using the setup script's test option
Note: If SMTP credentials are not configured, the system will run in simulation mode, saving PDFs to the uploads directory instead of sending emails.
-
Backend Setup
cd backend pip install -r requirements.txt cp env.example .env # Edit .env with your configuration uvicorn main:app --reload
-
Frontend Setup
cd frontend npm install npm run dev
The admin web interface provides:
- Tenant Management: Create, view, edit, and delete tenants with apartment assignments
- Edit tenant information and change apartment assignments
- View tenant details with apartment information
- Remove apartment assignments (set to null)
- Apartment Management: Create, edit, and manage apartments with flexible rent rates
- Add multiple rent rates per apartment (different rates for different years/months)
- Edit apartment details including address, unit number, and specifications
- Smart rent rate addition with auto-next month and previous amount defaults
- Add, modify, or remove rent rates for existing apartments
- Prevent duplicate apartments with same address/unit number
- View all rent rates for each apartment in a table format
- Delete apartments (only if no tenants or invoices assigned)
- Invoice Management: Enhanced invoice management system with rent rate integration and templates
- Create and manage invoice templates with Jinja2 support
- Create invoices by selecting apartment, rent rate, and template
- Automatic due date calculation (last day of the month before rent rate month)
- Automatic tenant selection when apartment is chosen
- Send email with PDF attachment option
- Resend invoice email functionality
- View all invoices with tenant, apartment, amount, due date, and status
- Mark invoices as paid with status tracking
- Delete invoices from the system
- Color-coded status indicators (paid, pending, overdue, cancelled)
- Post Management: Create and manage announcements and posts
- Dashboard: Overview of system statistics and quick access to all features
POST /auth/login-json- Login with JSONPOST /auth/login- Login with form data
GET /apartments/- List all apartments with rent ratesPOST /apartments/- Create new apartment with rent ratesPUT /apartments/{id}- Update apartment (including rent rates)DELETE /apartments/{id}- Delete apartment (if no tenants or invoices assigned)POST /apartments/{id}/rent-rates- Add rent rate to apartmentGET /apartments/{id}/rent-rates- Get rent rates for apartmentPUT /apartments/{id}/rent-rates/{rate_id}- Update rent rateDELETE /apartments/{id}/rent-rates/{rate_id}- Delete rent rateGET /tenants/- List all tenantsPOST /tenants/- Create new tenantPUT /tenants/{id}- Update tenant (including apartment assignment)DELETE /tenants/{id}- Delete tenantGET /invoices/- List all invoicesPOST /invoices/- Create new invoice (with rent rate selection, template, and email options)PUT /invoices/{id}- Update invoicePATCH /invoices/{id}/mark-paid- Mark invoice as paidPOST /invoices/{id}/resend-email- Resend invoice email with PDFDELETE /invoices/{id}- Delete invoiceGET /invoice-templates/- List all invoice templatesPOST /invoice-templates/- Create new invoice templateGET /invoice-templates/{id}- Get specific invoice templatePUT /invoice-templates/{id}- Update invoice templateDELETE /invoice-templates/{id}- Delete invoice templatePOST /invoice-templates/{id}/preview- Preview invoice template with sample dataGET /posts/admin- List all posts (including unpublished)POST /posts/- Create new post
GET /tenants/me- Get current tenant infoGET /invoices/my-invoices- Get tenant's invoicesGET /invoices/my-invoices/{id}- Get specific invoice
GET /posts/- List published postsGET /posts/{id}- Get specific published postGET /posts/categories/list- List post categories
rental/
├── backend/ # FastAPI backend
│ ├── routers/ # API route handlers
│ ├── models.py # Database models
│ ├── schemas.py # Pydantic schemas
│ ├── auth.py # Authentication logic
│ ├── database.py # Database configuration
│ ├── config.py # Settings management
│ └── main.py # FastAPI application
├── frontend/ # React TypeScript frontend
│ ├── src/
│ │ ├── components/ # React components
│ │ ├── pages/ # Page components
│ │ ├── hooks/ # Custom React hooks
│ │ └── lib/ # Utility libraries
│ ├── package.json # Node.js dependencies
│ └── vite.config.ts # Vite configuration
├── nginx/ # Nginx configuration
├── scripts/ # Setup and utility scripts
├── docker-compose.yml # Docker services
└── README.md # This file
- JWT-based authentication
- Password hashing with bcrypt
- Role-based access control
- Rate limiting on API endpoints
- HTTPS with SSL/TLS encryption
- Input validation and sanitization
- CORS configuration
- Database connection pooling
- Redis caching layer
- Optimized database queries
- Static file serving
- Gzip compression
- HTTP/2 support
- Invoice Templates Management: Complete CRUD interface for invoice templates
- Template Creation: Create templates with name, description, and Jinja2 content
- Template Editing: Edit existing templates with full form validation
- Template Preview: Preview templates with sample data before saving
- Template Deletion: Delete templates (only if not used by invoices)
- Active/Inactive Status: Enable/disable templates as needed
- Jinja2 Template Engine: Full support for dynamic invoice content
- Variable Support: Use {{ invoice.id }}, {{ tenant.name }}, {{ apartment.address }}, etc.
- Conditional Logic: Support for Jinja2 conditionals and filters
- Sample Templates: Pre-loaded with "Standard Rent Invoice" and "Simple Invoice" templates
- Enhanced Invoice Creation: Template selection and automatic tenant filling
- Template Dropdown: Select from available templates when creating invoices
- Automatic Tenant Selection: Tenant automatically filled when apartment is selected
- Template Integration: Invoices linked to selected templates for PDF generation
- Edit Apartment UI: Complete edit interface for apartments with address, unit number, and specifications
- Smart Rent Rate Management: Add, modify, or remove rent rates for existing apartments
- Auto-Next Month: "+ Add Rate" button automatically adds the next chronological month
- Previous Amount Default: New rent rates default to the previous month's amount for convenience
- Year Rollover: Automatically handles year transitions (December → January)
- Visual Edit Icons: Edit (pencil) icons in apartment table for easy access
- Modal Interface: User-friendly modal form for editing apartment details
- Backend API Enhancement: Updated apartment update endpoint to handle rent rate modifications
- Data Validation: Prevents duplicate rent rates and validates input data
- Invoice Templates: Create and manage reusable Jinja2 invoice templates
- Template Management: Full CRUD operations for invoice templates
- Template Selection: Choose template when creating invoices
- Template Preview: Preview templates with sample data
- Jinja2 Support: Full Jinja2 templating engine for dynamic content
- Rent Rate Integration: Create invoices by selecting apartment and specific rent rate
- Automatic Due Date Calculation: Due date automatically set to last day of the month before the selected rent rate month
- Automatic Tenant Selection: Tenant automatically filled when apartment is selected
- Email Functionality: Send invoice emails with PDF attachments
- Send Email Checkbox: Option to send email when creating invoice (checked by default)
- Resend Email Action: Resend invoice email for existing invoices
- PDF Generation: FIXED - Real PDF generation using WeasyPrint with professional styling
- Template Integration: PDFs use selected invoice template or default template
- Email Simulation: Development mode saves PDFs to uploads directory
- Complete Invoice UI: Full invoice management interface with create, view, and delete operations
- Status Management: Mark invoices as paid with automatic status tracking
- Apartment & Tenant Integration: Create invoices with apartment and tenant selection
- Visual Status Indicators: Color-coded status badges (paid, pending, overdue, cancelled)
- Data Validation: Ensures tenants are assigned to selected apartments
- PDF Generation: FIXED - Real PDF invoice generation using WeasyPrint with Jinja2 templates for email attachments
- Edit Functionality: Edit tenant information and change apartment assignments
- Flexible Assignments: Remove apartment assignments (set to null) or change to different apartments
- Visual Improvements: Enhanced table display with apartment details and edit icons
- Dropdown Selection: User-friendly apartment selection in create/edit forms
- Enhanced Data Model: Replaced single
rent_amountwithRentRatetable supporting multiple rates per apartment - Flexible Pricing: Each apartment can have different rent rates for different years and months
- Duplicate Prevention: Added unique constraints and validation to prevent duplicate apartments
- Web UI: Complete apartment management interface with rent rate management
- Database Migration: Automated migration script to update existing data structure
- Enhanced Deletion Logic: Prevents deletion of apartments with tenants OR invoices assigned
- Real PDF Generation: FIXED - Now generates actual PDF files using WeasyPrint, not just text
- WeasyPrint Integration: Proper HTML-to-PDF conversion with CSS styling
- Professional Styling: Clean, professional invoice layout with proper typography
- Error Handling: Graceful fallback to text if PDF generation fails
- Template Support: PDFs use Jinja2 templates for dynamic content
- Email Attachments: PDFs are properly attached to emails as binary files
- System Dependencies: All required system libraries for WeasyPrint permanently installed in Docker image
- Testing Verified: PDF generation tested and confirmed working with multiple templates
- API Endpoints: Enhanced apartment, tenant, and invoice endpoints with proper validation
- Frontend Routing: Fixed routing issues and improved user experience
- Database Constraints: Added proper foreign key relationships and unique constraints
- Error Handling: Improved error messages and validation feedback
- Cascade Deletes: Proper cleanup of related data when deleting apartments
- Docker Dependencies: All Python packages and system libraries permanently installed in Docker images
# Run the rent rates migration
docker-compose exec backend python scripts/migrate_rent_rates.py
# Add unique constraints
docker-compose exec postgres psql -U rental_user -d rental_db -f /tmp/add_apartment_unique_constraint.sql
# Merge duplicate apartments (if needed)
docker-compose exec postgres psql -U rental_user -d rental_db -f /tmp/merge_duplicate_apartments.sql
# Make tenant apartment_id nullable
docker-compose exec postgres psql -U rental_user -d rental_db -f /tmp/make_tenant_apartment_nullable.sql# Rebuild frontend with no cache
docker-compose stop frontend && docker-compose rm -f frontend
docker-compose build --no-cache frontend
docker-compose up -d frontend
# Rebuild backend with no cache (after dependency changes)
docker-compose build --no-cache backend
docker-compose up -d backend
# Restart backend after model changes
docker-compose restart backend
# Copy files to containers
docker cp backend/models.py rental_backend:/app/models.py
docker cp backend/schemas.py rental_backend:/app/schemas.py
docker cp backend/routers/apartments.py rental_backend:/app/routers/apartments.py
docker cp backend/routers/tenants.py rental_backend:/app/routers/tenants.py
docker cp backend/routers/invoices.py rental_backend:/app/routers/invoices.py
docker cp backend/utils/pdf_email.py rental_backend:/app/utils/pdf_email.py
docker cp frontend/src/pages/AdminDashboard.tsx rental_frontend:/app/src/pages/AdminDashboard.tsx# Tables
docker-compose exec postgres psql -U rental_user -d rental_db -c "\dt"
# Check tenants assigned to apartments
docker-compose exec postgres psql -U rental_user -d rental_db -c "SELECT t.id, t.name, t.email, a.address, a.unit_number FROM tenants t JOIN apartments a ON t.apartment_id = a.id WHERE a.address = '123 Main Street' ORDER BY a.unit_number;"
# Check invoices for apartments
docker-compose exec postgres psql -U rental_user -d rental_db -c "SELECT i.id, i.amount, i.due_date, i.status, a.address, a.unit_number FROM invoices i JOIN apartments a ON i.apartment_id = a.id WHERE a.address = '123 Main Street' ORDER BY a.unit_number;"
# View all invoices with tenant and apartment details
docker-compose exec postgres psql -U rental_user -d rental_db -c "SELECT i.id, i.amount, i.due_date, i.status, t.name as tenant_name, a.address, a.unit_number FROM invoices i JOIN tenants t ON i.tenant_id = t.id JOIN apartments a ON i.apartment_id = a.id ORDER BY i.due_date;"
# Check apartment deletion constraints
docker-compose exec postgres psql -U rental_user -d rental_db -c "SELECT a.id, a.address, a.unit_number, COUNT(t.id) as tenant_count, COUNT(i.id) as invoice_count FROM apartments a LEFT JOIN tenants t ON a.id = t.apartment_id LEFT JOIN invoices i ON a.id = i.apartment_id GROUP BY a.id, a.address, a.unit_number ORDER BY a.id;"