取代Excel记录和WhatsApp催租,一站式管理物业、租户、账单、收据与维修请求
* Preview is for reference only. Actual results may vary depending on the AI model, variable values, and tools used.
You are a full-stack development expert proficient in Next.js 16, Tailwind CSS 4, and Supabase. Please help me build a complete Tenant and Rent Collection Management System.
## Project Overview
Company name: {company_name}
Number of managed properties: {num_properties}
Total units: approximately {num_units} units
Currency: {currency}
Primary color: {primary_color}
This is a rent collection management system designed for Malaysian property owners/management companies, replacing Excel spreadsheet tracking and manual WhatsApp rent reminders.
## Tech Stack
- Next.js 16 (App Router + React 19)
- Tailwind CSS 4 (CSS-first configuration)
- Supabase (Postgres + Auth + RLS + Storage)
- TypeScript strict mode
- shadcn/ui component library
- Deploy to Vercel
## Data Model (Supabase Postgres)
Please create the following table structures with complete RLS policies and indexes:
### 1. properties
```
id: uuid PK default gen_random_uuid()
owner_id: uuid FK -> auth.users(id)
name: text NOT NULL -- e.g. Menara Sentral Residences
address: text NOT NULL
city: text NOT NULL -- e.g. Kuala Lumpur
state: text NOT NULL -- e.g. Selangor, Johor
postcode: text
property_type: text CHECK (property_type IN ('apartment', 'condo', 'shophouse', 'terrace', 'semi-d', 'bungalow', 'commercial'))
total_units: integer NOT NULL
notes: text
created_at: timestamptz default now()
updated_at: timestamptz default now()
```
### 2. units
```
id: uuid PK default gen_random_uuid()
property_id: uuid FK -> properties(id) ON DELETE CASCADE
unit_number: text NOT NULL -- e.g. A-12-03
floor: integer
bedrooms: integer
bathrooms: integer
size_sqft: numeric
monthly_rent: numeric NOT NULL -- e.g. 1800.00
status: text CHECK (status IN ('vacant', 'occupied', 'maintenance', 'reserved')) default 'vacant'
notes: text
created_at: timestamptz default now()
updated_at: timestamptz default now()
UNIQUE(property_id, unit_number)
```
### 3. tenants
```
id: uuid PK default gen_random_uuid()
owner_id: uuid FK -> auth.users(id)
full_name: text NOT NULL
ic_number: text -- MyKad IC number
passport_number: text -- for foreign tenants
phone: text NOT NULL
email: text
emergency_contact_name: text
emergency_contact_phone: text
bank_name: text
bank_account: text
notes: text
created_at: timestamptz default now()
updated_at: timestamptz default now()
```
### 4. leases
```
id: uuid PK default gen_random_uuid()
unit_id: uuid FK -> units(id)
tenant_id: uuid FK -> tenants(id)
start_date: date NOT NULL
end_date: date NOT NULL
monthly_rent: numeric NOT NULL
security_deposit: numeric NOT NULL -- typically 2 months rent
utility_deposit: numeric -- typically half month rent
advance_rent: numeric -- typically 1 month advance
stamp_duty: numeric
stamp_duty_paid_by: text CHECK (stamp_duty_paid_by IN ('landlord', 'tenant', 'shared')) default 'tenant'
status: text CHECK (status IN ('active', 'expired', 'terminated', 'pending_renewal')) default 'active'
renewal_reminder_days: integer default 60 -- remind 60 days before expiry
agreement_file_url: text -- uploaded tenancy agreement PDF
notes: text
created_at: timestamptz default now()
updated_at: timestamptz default now()
```
### 5. billings
```
id: uuid PK default gen_random_uuid()
lease_id: uuid FK -> leases(id)
tenant_id: uuid FK -> tenants(id)
unit_id: uuid FK -> units(id)
billing_month: date NOT NULL -- 1st of each month
amount: numeric NOT NULL
late_fee: numeric default 0
total_amount: numeric GENERATED ALWAYS AS (amount + late_fee) STORED
status: text CHECK (status IN ('pending', 'paid', 'partial', 'overdue', 'waived')) default 'pending'
due_date: date NOT NULL -- typically the 7th of each month
notes: text
created_at: timestamptz default now()
updated_at: timestamptz default now()
```
### 6. payments
```
id: uuid PK default gen_random_uuid()
billing_id: uuid FK -> billings(id)
amount: numeric NOT NULL
payment_date: date NOT NULL
payment_method: text CHECK (payment_method IN ('cash', 'bank_transfer', 'fpx', 'cheque', 'ewallet')) NOT NULL
reference_number: text -- bank transfer reference
bank_name: text
proof_url: text -- payment proof screenshot
receipt_number: text UNIQUE -- auto-generated RCP-20260401-001
notes: text
created_at: timestamptz default now()
```
### 7. maintenance_requests
```
id: uuid PK default gen_random_uuid()
unit_id: uuid FK -> units(id)
tenant_id: uuid FK -> tenants(id)
title: text NOT NULL -- e.g. Aircon leaking
description: text NOT NULL
category: text CHECK (category IN ('plumbing', 'electrical', 'aircon', 'structural', 'appliance', 'pest', 'other'))
priority: text CHECK (priority IN ('low', 'medium', 'high', 'urgent')) default 'medium'
status: text CHECK (status IN ('submitted', 'in_progress', 'completed', 'cancelled')) default 'submitted'
photo_urls: text[] -- photos of the issue
resolution_notes: text
resolved_at: timestamptz
assigned_to: text -- maintenance person name
estimated_cost: numeric
actual_cost: numeric
created_at: timestamptz default now()
updated_at: timestamptz default now()
```
### 8. deposits
```
id: uuid PK default gen_random_uuid()
lease_id: uuid FK -> leases(id)
deposit_type: text CHECK (deposit_type IN ('security', 'utility', 'advance_rent', 'other')) NOT NULL
amount: numeric NOT NULL
status: text CHECK (status IN ('held', 'partially_refunded', 'fully_refunded', 'forfeited')) default 'held'
refund_amount: numeric
refund_date: date
refund_notes: text -- reason for deductions
created_at: timestamptz default now()
```
### Indexes (must create)
```sql
CREATE INDEX idx_units_property_id ON units(property_id);
CREATE INDEX idx_units_status ON units(status);
CREATE INDEX idx_leases_unit_id ON leases(unit_id);
CREATE INDEX idx_leases_tenant_id ON leases(tenant_id);
CREATE INDEX idx_leases_status ON leases(status);
CREATE INDEX idx_leases_end_date ON leases(end_date);
CREATE INDEX idx_billings_lease_id ON billings(lease_id);
CREATE INDEX idx_billings_tenant_id ON billings(tenant_id);
CREATE INDEX idx_billings_status ON billings(status);
CREATE INDEX idx_billings_billing_month ON billings(billing_month);
CREATE INDEX idx_billings_due_date ON billings(due_date);
CREATE INDEX idx_payments_billing_id ON payments(billing_id);
CREATE INDEX idx_maintenance_unit_id ON maintenance_requests(unit_id);
CREATE INDEX idx_maintenance_tenant_id ON maintenance_requests(tenant_id);
CREATE INDEX idx_maintenance_status ON maintenance_requests(status);
CREATE INDEX idx_deposits_lease_id ON deposits(lease_id);
```
### RLS Policies
- Enable RLS on all tables
- Use (select auth.uid()) for row-level security filtering on owner_id
- Tenant portal: tenants can only see leases, billings, payments, and maintenance_requests associated with them
- Property owners: can only see data under their own properties
## Business Logic
### Auto Billing Generation
- Auto-generate monthly bills for all active leases on the 1st of each month
- Trigger via Supabase Edge Function or pg_cron
- Default due_date is the 7th of each month
- Auto-mark as overdue if unpaid past due_date
- Configurable late_fee (e.g. RM10/day or flat RM50)
### Payment Processing
- Recording payment auto-updates billing status
- Support partial payments
- Auto-generate receipt_number format: RCP-{YYYYMMDD}-{sequence}
- Generate PDF receipt after payment
### Lease Management
- Show reminder on Dashboard {renewal_reminder_days} days before lease expiry
- Auto-change unit status to vacant when lease expires (if not renewed)
- Calculate stamp duty: Malaysian standard = RM1 per RM250 of annual rent (first RM2,400 exempt)
### Deposit Management
- Standard Malaysian configuration: 2 months security deposit + 1 month advance rent + half month utility deposit
- On move-out: check outstanding rent, maintenance costs, calculate refundable deposit
- Record deduction details and refunds
## Page Structure and UI/UX
### Landlord Admin Panel (login required)
#### 1. Dashboard (/dashboard)
- Top stat cards: total properties, total units, occupancy rate, monthly expected rent, collected rent, overdue amount
- Occupancy rate shown as donut chart
- Monthly collection progress bar
- Overdue tenant list (red highlight, showing days and amount)
- Upcoming lease expiry list (within 60 days)
- Recent maintenance requests
- Quick action buttons: record payment, add tenant, submit maintenance
#### 2. Property Management (/properties)
- Property list card view, each card showing: name, address, total units, occupancy rate
- Click to enter property detail, showing all units in grid view
- Units color-coded by status: green=occupied, gray=vacant, orange=maintenance
- Click to quickly edit unit information
#### 3. Tenant Management (/tenants)
- Tenant list table with search and filters
- Tenant detail page showing: personal info, current lease, billing history, payment records, maintenance requests
- One-click WhatsApp rent reminder (generates wa.me link with pre-filled reminder message)
#### 4. Billing Management (/billings)
- View all bills by month
- Filters: all/pending/paid/overdue
- Bulk operations: bulk generate bills, bulk mark as paid
- Invoice preview and print
#### 5. Payment Records (/payments)
- Record new payment form: select tenant -> auto-show unpaid bills -> enter amount and method
- Payment history list
- Export monthly/annual reports (CSV)
#### 6. Maintenance Requests (/maintenance)
- Kanban board view: Submitted -> In Progress -> Completed
- Each card shows: unit number, issue title, priority badge, submission time
- Click to expand details, upload completion photos, enter costs
#### 7. Receipt Generation (/receipts)
- Select payment record to generate official receipt
- Receipt template includes: company name and logo, tenant info, property and unit info, payment amount and method, receipt number and date
- Support PDF download or direct WhatsApp share
#### 8. Reports (/reports)
- Monthly collection report
- Property revenue report
- Overdue analysis report
- Deposit status report
- Support CSV and PDF export
### Tenant Portal (separate entry /tenant-portal)
- After login, see own information
- View current and historical bills
- View payment records and download receipts
- Submit maintenance requests (with photo upload)
- Track maintenance progress
- View lease information
## UI Design Specifications
- Primary color: {primary_color} for buttons, important labels, progress bars
- Background: white #FFFFFF, card background #F8FAFC
- Text: dark #0F172A, secondary #64748B
- Success/Paid: #22C55E
- Overdue/Warning: #EF4444
- Pending: #F59E0B
- Font: Inter + Noto Sans SC
- Responsive design: desktop sidebar navigation, mobile bottom navigation
- All amounts displayed as: {currency} 1,800.00
- Date format: DD/MM/YYYY (Malaysian standard)
## Sample Data (please auto-populate)
Create sample data for an apartment building in Kuala Lumpur:
Property: Menara Sentral Residences, Jalan Sultan Ismail, Kuala Lumpur
20 units (A-01-01 to A-04-05, 5 units per floor, 4 floors)
Monthly rent range: {currency} 1,500 - {currency} 2,800
15 occupied units, 5 vacant
15 tenants (common Malaysian names, including Chinese, Malay, and Indian names)
Each tenant has complete IC number (fictional but correct format YYMMDD-SS-NNNN)
Past 3 months of billing and payment records:
- 12 on-time payments
- 2 overdue (5 days and 15 days overdue respectively)
- 1 partial payment
3 sample maintenance requests:
- 1 completed (aircon repair)
- 1 in progress (pipe leak)
- 1 newly submitted (door lock malfunction)
## Key Implementation Requirements
1. All CRUD operations use Supabase Server Actions
2. Real-time data updates using Supabase Realtime (billing status changes)
3. File uploads (lease PDFs, maintenance photos, payment proofs) use Supabase Storage
4. Receipt PDF generation using @react-pdf/renderer
5. Report export using xlsx library for Excel generation
6. WhatsApp integration using wa.me deep links
7. Mobile-first responsive design
8. Chinese interface (Simplified Chinese), key terms retained in Malay/English (e.g. Tenancy Agreement, Stamp Duty)
Please start with the Supabase database migration files, then build the complete frontend and backend code.