-
Notifications
You must be signed in to change notification settings - Fork 1
features property management
Active contributors: Saksham, Ravi
The Property Management (PM) module is the landlord and relationship-manager surface of 360 Ghar. It manages the full lifecycle of managed properties: leases, rent collection, maintenance requests, documents, inspections, expenses, reports, tenants, rental applications, and RM assignments. Every PM operation flows through a central authorisation layer that enforces owner, agent (RM), tenant, and admin scopes.
app/api/api_v1/endpoints/
├── pm_properties.py # managed property list, get, dashboard summary
├── pm_leases.py # lease CRUD, terminate, list
├── pm_rent.py # generate charges, record payment, due list, history
├── pm_maintenance.py # maintenance request CRUD, status updates
├── pm_documents.py # document upload, list, delete
├── pm_inspections.py # move_in/move_out/routine inspections
├── pm_expenses.py # expense tracking by category
├── pm_tenants.py # tenant list, status transitions
├── pm_applications.py # rental applications + forms
├── pm_assignments.py # RM (agent) → owner assignments
├── pm_dashboard.py # portfolio dashboard metrics
└── pm_reports.py # financial and occupancy reports
app/services/
├── pm_authz.py # central authorisation layer (assert_can_*)
├── pm_properties.py # managed property service
├── pm_leases.py # lease service
├── pm_rent.py # rent charge generation + payment recording
├── pm_maintenance.py # maintenance requests + work orders
├── pm_documents.py # document storage
├── pm_inspections.py # inspection checklists
├── pm_expenses.py # expense CRUD
├── pm_tenants.py # tenant lifecycle
├── pm_applications.py # rental applications
├── pm_assignments.py # RM assignments
├── pm_dashboard.py # dashboard aggregation
└── pm_reports.py # report generation
app/models/
├── pm_leases.py # Lease, RentalApplication, RentalApplicationForm
├── pm_finance.py # RentCharge, RentPayment, Expense
├── pm_maintenance.py # MaintenanceRequest, WorkOrder
└── pm_documents.py # Document, InspectionChecklist
| Abstraction | File | Role |
|---|---|---|
assert_can_manage_owner_portfolio |
app/services/pm_authz.py |
Owner-scope check: admin passes, agent must own the assignment, user must be self |
assert_can_access_property |
app/services/pm_authz.py |
Property-scope check with optional tenant lease lookup |
assert_can_access_lease |
app/services/pm_authz.py |
Lease-scope check resolving tenant, owner, and RM |
can_access_booking |
app/services/pm_authz.py |
Booking-scope check for stays overlap |
_get_actor_role |
app/services/pm_authz.py |
Normalises UserRole from model or schema |
create_lease |
app/services/pm_leases.py |
Validates dates, prevents duplicate active leases, persists |
generate_rent_charges |
app/services/pm_rent.py |
Idempotent monthly charge generation for active leases |
record_rent_payment |
app/services/pm_rent.py |
Records RentPayment, updates RentCharge.status
|
create_maintenance_request |
app/services/pm_maintenance.py |
Tenant or owner creates request, optional lease link |
Every PM call starts in pm_authz.py. The actor is resolved through _get_actor_role (handling both UserRole enum columns and string schemas) and routed to one of four scope assertions. Admins pass everywhere. Agents must have agent_id linked to the owner's users.agent_id column (the RM assignment). Owners act on their own portfolio. Tenants are allowed only when allow_tenant=True and they hold an active lease on the property.
graph TD
Client -->|/api/v1/pm/*| EP[app/api/.../pm_*.py]
EP --> AUTH[pm_authz.assert_can_*]
AUTH -->|admin| OK{Pass}
AUTH -->|agent| RM[users.agent_id matches owner.agent_id]
AUTH -->|user/owner| OWN[owner_id == actor.id]
AUTH -->|tenant| LEASE[active Lease on property]
OK --> SVC[pm_* service]
SVC --> Models[(Lease, RentCharge, RentPayment, MaintenanceRequest, Document, Expense)]
EP --> DASH[pm_dashboard.compute_dashboard_metrics]
DASH --> Agg[occupancy, active leases, open maintenance, expected rent]
Sched[AsyncIOScheduler] -->|monthly| RENT[generate_rent_charges]
Lease creation enforces a single active lease per property: create_lease queries for Lease.property_id == property_id AND Lease.status == active and raises BadRequestException if one exists. Lease status transitions go through draft → pending_signature → active → expiring_soon → expired (or terminated / renewed), with termination_date and termination_reason captured on termination.
Rent collection is idempotent. generate_rent_charges accepts a start_month and months count (1-24), resolves the active-lease scope for the actor, and upserts RentCharge rows keyed by (lease_id, billing_month). record_rent_payment inserts a RentPayment, then recomputes the linked RentCharge.status (pending, partial, paid, overdue, waived) from the sum of payments. Late fees use late_fee_amount or late_fee_percentage after grace_period_days (default 5).
Maintenance requests support the full workflow open → in_review → work_order_created → resolved → closed, with linked WorkOrder rows carrying WorkOrderStatus. Tenants can create requests against properties they lease; owners and RMs manage them. Documents, inspections (move_in/move_out/routine), and expenses are scoped to the same property/lease authorisation.
-
Auth dependencies: PM endpoints use
get_current_active_user,get_current_agent, andget_current_adminfromapp/api/api_v1/dependencies/auth.py. -
Notifications: rent due, maintenance status, lease termination, and document approval events flow through notifications via
dispatch_notification_to_user. -
MCP servers: the MCP servers admin server exposes
agent_*PM tools; the user server exposesowner_*andtenant_*PM tools. Shared logic lives inapp/mcp/tool_ops/(leases, rent, maintenance, dashboard) andapp/mcp/chatgpt/pm_*modules. -
AI agent: the AI agent registers PM tools for owners, tenants, agents, and admins via
app/services/ai_agent/tools/owner.pyandtenant.py. -
Storage: document uploads use Cloudinary through the shared storage service with
DOCUMENT_*storage folder enums.
New PM operations must go through pm_authz — never query Lease or MaintenanceRequest directly without an assert_can_access_* call. New rent charge fields belong in generate_rent_charges and the RentCharge model; the payment application logic in record_rent_payment must be updated to recompute RentCharge.status. Status enums live in app/models/enums.py and any new value requires a migration plus an enum update in CLAUDE.md.
| File | Purpose |
|---|---|
app/services/pm_authz.py |
Central authorisation (260 lines) |
app/services/pm_leases.py |
Lease service (280 lines) |
app/services/pm_rent.py |
Rent charges + payments (343 lines) |
app/services/pm_maintenance.py |
Maintenance + work orders (217 lines) |
app/services/pm_dashboard.py |
Dashboard metrics (9.9 KB) |
app/services/pm_reports.py |
Financial and occupancy reports |
app/services/pm_applications.py |
Rental applications (9 KB) |
app/services/pm_properties.py |
Managed property service (8.9 KB) |
app/services/pm_documents.py |
Document storage |
app/services/pm_inspections.py |
Inspection checklists |
app/services/pm_expenses.py |
Expense tracking |
app/services/pm_tenants.py |
Tenant lifecycle |
app/services/pm_assignments.py |
RM assignments |
app/api/api_v1/endpoints/pm_*.py |
12 endpoint modules |
app/mcp/tool_ops/{leases,rent,maintenance,dashboard}.py |
Shared MCP logic |
app/mcp/chatgpt/pm_*.py |
ChatGPT-specific PM tool wrappers |
- Features overview
- Ghar Core (marketplace)
- 360 Stays (bookings)
- 360 Flatmates
- Property Management
- 360 Virtual Tours
- 360 Data Hub
- MCP servers and widgets
- AI agent
- Blog and SEO
- Notifications
- Vastu analyzer