Business Objects Reference¶
Complete guide to Poolula Platform's core business objects
Overview¶
Poolula Platform models the operations of Poolula LLC through five core business objects. Each object represents a real-world concept and includes built-in provenance tracking for transparency.
The Five Core Objects:
- Property - Rental properties owned by the LLC
- Transaction - Financial events (revenue, expenses, capital)
- Document - Legal and operational documents
- Obligation - Compliance and operational deadlines
- AuditLog - Immutable change history
Entity Relationship Diagram¶
erDiagram
Property ||--o{ Transaction : "has"
Property ||--o{ Document : "relates_to"
Property ||--o{ Obligation : "subject_of"
Transaction }o--o{ Document : "evidenced_by"
Document }o--o{ Obligation : "creates"
AuditLog }o--|| Property : "tracks"
AuditLog }o--|| Transaction : "tracks"
AuditLog }o--|| Document : "tracks"
AuditLog }o--|| Obligation : "tracks"
Property {
uuid id PK
string address
date acquisition_date
decimal purchase_price_total
decimal land_basis
decimal building_basis
decimal ffe_basis
date placed_in_service
enum status
json provenance
json extra_metadata
timestamp created_at
timestamp updated_at
}
Transaction {
uuid id PK
uuid property_id FK
date transaction_date
decimal amount
enum category
string description
string source_account
enum transaction_type
json provenance
json extra_metadata
timestamp created_at
timestamp updated_at
}
Document {
uuid id PK
uuid property_id FK
string filename
enum doc_type
date effective_date
string[] entities
string version
enum confidentiality
string content_hash
json provenance
json extra_metadata
timestamp created_at
timestamp updated_at
}
Obligation {
uuid id PK
uuid property_id FK
enum obligation_type
date due_date
enum status
string recurrence
text description
json provenance
json extra_metadata
timestamp created_at
timestamp updated_at
}
AuditLog {
uuid id PK
timestamp timestamp
string user
string action
string entity_type
uuid entity_id
json old_value
json new_value
text reason
json context
}
1. Property¶
Purpose: Represents a rental property owned by Poolula LLC
Key Fields¶
| Field | Type | Required | Description |
|---|---|---|---|
id |
UUID | Yes | Unique identifier (auto-generated) |
address |
String | Yes | Physical address of the property |
acquisition_date |
Date | Yes | Date property was acquired |
purchase_price_total |
Decimal | Yes | Total purchase price |
land_basis |
Decimal | Yes | Basis allocated to land (non-depreciable) |
building_basis |
Decimal | Yes | Basis allocated to building (depreciable) |
ffe_basis |
Decimal | No | Basis allocated to furniture/fixtures/equipment |
placed_in_service |
Date | No | Date property was placed in service for depreciation |
status |
Enum | Yes | Current status (ACTIVE, UNDER_CONTRACT, SOLD, INACTIVE) |
provenance |
JSON | Yes | Data lineage and source information |
extra_metadata |
JSON | No | Additional property-specific data |
Computed Properties¶
@property
def total_basis(self) -> Decimal:
"""Sum of all basis components"""
return self.land_basis + self.building_basis + self.ffe_basis
@property
def depreciable_basis(self) -> Decimal:
"""Only building and FFE (land is not depreciable)"""
return self.building_basis + self.ffe_basis
Lifecycle States¶
stateDiagram-v2
[*] --> UNDER_CONTRACT: Property identified
UNDER_CONTRACT --> ACTIVE: Closing complete
ACTIVE --> SOLD: Property sold
ACTIVE --> INACTIVE: Property removed from service
SOLD --> [*]
INACTIVE --> [*]
Relationships¶
- HAS MANY Transactions (revenue, expenses tied to property)
- HAS MANY Documents (deeds, leases, inspection reports)
- HAS MANY Obligations (property taxes, insurance renewals)
Example¶
{
"id": "12345678-1234-1234-1234-123456789012",
"address": "900 S 9th St, Montrose, CO 81401",
"acquisition_date": "2024-04-15",
"purchase_price_total": "442300.00",
"land_basis": "78200.00",
"building_basis": "364100.00",
"ffe_basis": "10000.00",
"placed_in_service": "2025-02-01",
"status": "ACTIVE",
"provenance": {
"source_type": "manual_entry",
"source_id": "poolula_facts.yml",
"confidence": 1.0,
"verification_status": "verified"
},
"created_at": "2025-11-13T10:00:00",
"updated_at": "2025-11-13T10:00:00"
}
2. Transaction¶
Purpose: Financial events (revenue, expenses, capital contributions/distributions)
Key Fields¶
| Field | Type | Required | Description |
|---|---|---|---|
id |
UUID | Yes | Unique identifier |
property_id |
UUID | No | Associated property (null for LLC-level) |
transaction_date |
Date | Yes | Date transaction occurred |
amount |
Decimal | Yes | Transaction amount (always positive) |
category |
Enum | Yes | Chart of accounts category |
description |
String | Yes | Human-readable description |
source_account |
String | No | Bank account or source |
transaction_type |
Enum | Yes | REVENUE, EXPENSE, CAPITAL_CONTRIBUTION, CAPITAL_DISTRIBUTION |
provenance |
JSON | Yes | Source of transaction data |
Transaction Categories (Chart of Accounts)¶
Revenue:
- RENTAL_INCOME - Rental revenue from tenants
Operating Expenses:
- UTILITIES_GAS, UTILITIES_WATER, UTILITIES_ELECTRIC, UTILITIES_INTERNET
- REPAIRS_MAINTENANCE - Ongoing maintenance and repairs
- INSURANCE - Property insurance premiums
- PROPERTY_TAXES - Annual property tax
- PROPERTY_MANAGEMENT - Management fees
- BANK_FEES - Banking and transaction fees
- PROFESSIONAL_FEES - CPA, attorney, consultant fees
Capital:
- CAPITAL_IMPROVEMENT - Improvements that increase basis
- FURNITURE_FIXTURES - FFE purchases
- BASIS_ADJUSTMENT - Corrections to depreciable basis
Member Transactions:
- MEMBER_CONTRIBUTION - Capital contributed to LLC
- MEMBER_DISTRIBUTION - Distributions to member
Other:
- UNCATEGORIZED - Transactions not yet categorized
Validation Rules¶
def validate_amount(self) -> None:
"""Amount must be positive (use transaction_type for direction)"""
if self.amount <= 0:
raise ValueError("Transaction amount must be positive")
def validate_category_type_match(self) -> None:
"""Category must match transaction_type"""
# Example: RENTAL_INCOME must be REVENUE type
# UTILITIES_GAS must be EXPENSE type
Lifecycle¶
stateDiagram-v2
[*] --> IMPORTED: CSV/Manual entry
IMPORTED --> CATEGORIZED: Category assigned
CATEGORIZED --> RECONCILED: Matched to bank statement
RECONCILED --> REPORTED: Included in tax reports
IMPORTED --> FLAGGED: Validation error
FLAGGED --> CATEGORIZED: Issue resolved
Relationships¶
- BELONGS TO Property (nullable - some transactions are LLC-level)
- EVIDENCED BY Documents (receipts, invoices, bank statements)
- TRACKED BY AuditLog entries
Example¶
{
"id": "22222222-2222-2222-2222-222222222222",
"property_id": "12345678-1234-1234-1234-123456789012",
"transaction_date": "2024-11-01",
"amount": "1500.00",
"category": "RENTAL_INCOME",
"description": "November 2024 rental income",
"source_account": "Chase Business Checking",
"transaction_type": "REVENUE",
"provenance": {
"source_type": "csv_import",
"source_id": "airbnb_nov_2024.csv",
"source_field": "row_15",
"confidence": 1.0
}
}
3. Document¶
Purpose: Legal and operational documents with metadata and provenance
Key Fields¶
| Field | Type | Required | Description |
|---|---|---|---|
id |
UUID | Yes | Unique identifier |
property_id |
UUID | No | Associated property (nullable for LLC docs) |
filename |
String | Yes | Original filename |
doc_type |
Enum | Yes | Document category |
effective_date |
Date | No | Date document becomes effective |
entities |
String[] | No | Legal entities involved (validated format) |
version |
String | No | Version identifier (e.g., "v2", "2024-11-13") |
confidentiality |
Enum | Yes | PUBLIC, INTERNAL, CONFIDENTIAL, RESTRICTED |
content_hash |
String | Yes | SHA-256 hash for integrity verification |
Document Types¶
class DocumentType(str, Enum):
DEED = "deed"
LEASE = "lease"
OPERATING_AGREEMENT = "operating_agreement"
AMENDMENT = "amendment"
INVOICE = "invoice"
RECEIPT = "receipt"
BANK_STATEMENT = "bank_statement"
TAX_RETURN = "tax_return"
INSPECTION_REPORT = "inspection_report"
APPRAISAL = "appraisal"
INSURANCE_POLICY = "insurance_policy"
CONTRACT = "contract"
OTHER = "other"
Entity Name Validation¶
Entities must be standardized legal names: - "Poolula LLC" (not "poolula" or "Poolula") - "Hidalgo-Sotelo Living Trust" (exact format) - Property addresses must match Property.address exactly
Lifecycle¶
stateDiagram-v2
[*] --> UPLOADED: File uploaded
UPLOADED --> OCR_PROCESSING: PDF scanned
OCR_PROCESSING --> INDEXED: Text extracted
INDEXED --> VERSIONED: New version uploaded
VERSIONED --> ARCHIVED: Document superseded
Relationships¶
- BELONGS TO Property (nullable)
- EVIDENCES Transactions (invoice → expense)
- CREATES Obligations (lease → rent due dates)
Example¶
{
"id": "33333333-3333-3333-3333-333333333333",
"property_id": "12345678-1234-1234-1234-123456789012",
"filename": "900_s_9th_lease_2024.pdf",
"doc_type": "LEASE",
"effective_date": "2024-02-01",
"entities": ["Poolula LLC", "Tenant Name"],
"version": "v1",
"confidentiality": "CONFIDENTIAL",
"content_hash": "a1b2c3d4e5f6...",
"provenance": {
"source_type": "manual_upload",
"uploaded_by": "trustee",
"confidence": 1.0
}
}
4. Obligation¶
Purpose: Compliance deadlines and recurring operational tasks
Key Fields¶
| Field | Type | Required | Description |
|---|---|---|---|
id |
UUID | Yes | Unique identifier |
property_id |
UUID | No | Associated property (nullable for LLC obligations) |
obligation_type |
Enum | Yes | Type of obligation |
due_date |
Date | Yes | Next due date |
status |
Enum | Yes | PENDING, COMPLETED, OVERDUE, CANCELLED |
recurrence |
String | No | RRULE format for recurring obligations |
description |
Text | Yes | Details about the obligation |
Obligation Types¶
class ObligationType(str, Enum):
PROPERTY_TAX = "property_tax"
INSURANCE_RENEWAL = "insurance_renewal"
LLC_ANNUAL_REPORT = "llc_annual_report"
TAX_FILING = "tax_filing"
LEASE_RENEWAL = "lease_renewal"
INSPECTION = "inspection"
MAINTENANCE_SCHEDULED = "maintenance_scheduled"
COMPLIANCE_FILING = "compliance_filing"
OTHER = "other"
Recurrence (RRULE Format)¶
Uses iCalendar RRULE standard:
# Annual property tax (every April 30)
recurrence = "FREQ=YEARLY;BYMONTH=4;BYMONTHDAY=30"
# Quarterly estimated taxes (April 15, June 15, Sept 15, Jan 15)
recurrence = "FREQ=YEARLY;BYMONTH=4,6,9,1;BYMONTHDAY=15"
# Monthly rent due (1st of each month)
recurrence = "FREQ=MONTHLY;BYMONTHDAY=1"
Lifecycle¶
stateDiagram-v2
[*] --> PENDING: Obligation created
PENDING --> COMPLETED: Completed on time
PENDING --> OVERDUE: Due date passed
OVERDUE --> COMPLETED: Completed late
PENDING --> CANCELLED: No longer applicable
COMPLETED --> [*]: Archived
CANCELLED --> [*]: Archived
COMPLETED --> PENDING: Recurrence creates next instance
Relationships¶
- BELONGS TO Property (nullable)
- CREATED BY Documents (lease → rent obligations)
- TRACKED BY AuditLog entries
Example¶
{
"id": "44444444-4444-4444-4444-444444444444",
"property_id": "12345678-1234-1234-1234-123456789012",
"obligation_type": "PROPERTY_TAX",
"due_date": "2025-04-30",
"status": "PENDING",
"recurrence": "FREQ=YEARLY;BYMONTH=4;BYMONTHDAY=30",
"description": "Annual property tax payment to Montrose County",
"provenance": {
"source_type": "manual_entry",
"created_by": "trustee",
"confidence": 1.0
}
}
5. AuditLog¶
Purpose: Immutable record of all changes to business objects
Key Fields¶
| Field | Type | Required | Description |
|---|---|---|---|
id |
UUID | Yes | Unique identifier |
timestamp |
DateTime | Yes | When change occurred |
user |
String | Yes | Who made the change (user ID or "system") |
action |
String | Yes | CREATE, UPDATE, DELETE, etc. |
entity_type |
String | Yes | Property, Transaction, Document, Obligation |
entity_id |
UUID | Yes | ID of the changed entity |
old_value |
JSON | No | Previous state (null for CREATE) |
new_value |
JSON | No | New state (null for DELETE) |
reason |
Text | No | Why the change was made |
context |
JSON | No | Additional context (IP address, request ID, etc.) |
Actions Tracked¶
CREATE- New entity createdUPDATE- Entity modifiedDELETE- Entity soft-deletedRESTORE- Entity undeletedIMPORT- Batch import operationEXPORT- Data exportedLOGIN- User authentication (future)QUERY- Sensitive data accessed (future)
Immutability¶
Critical: AuditLog entries are NEVER modified or deleted. They provide a permanent record.
Example¶
{
"id": "55555555-5555-5555-5555-555555555555",
"timestamp": "2025-11-13T14:30:00.000000",
"user": "system:seed_script",
"action": "CREATE",
"entity_type": "Property",
"entity_id": "12345678-1234-1234-1234-123456789012",
"old_value": null,
"new_value": {
"address": "900 S 9th St, Montrose, CO 81401",
"acquisition_date": "2024-04-15",
"purchase_price_total": "442300.00"
},
"reason": "Initial data import from poolula_facts.yml",
"context": {
"script_version": "1.0.0",
"source_file": "poolula_facts.yml"
}
}
Common Patterns¶
Provenance Structure¶
All business objects (except AuditLog) include provenance:
{
"source_type": "csv_import | manual_entry | api_call | system_generated",
"source_id": "filename.csv | user_id | request_id",
"source_field": "row_15 | cell_B3 | null",
"created_at": "2025-11-13T10:00:00Z",
"created_by": "system:importer | user_id",
"confidence": 1.0,
"verification_status": "unverified | verified | needs_review",
"notes": "Additional context about data origin"
}
Metadata Flexibility¶
The extra_metadata field allows storing domain-specific data:
// Property metadata
{
"square_footage": 1200,
"bedrooms": 2,
"bathrooms": 1.5,
"parcel_number": "12345-67-890"
}
// Transaction metadata
{
"check_number": "1234",
"cleared_date": "2024-11-05",
"reconciliation_status": "matched"
}
Data Integrity Rules¶
UUID Primary Keys¶
All entities use UUID primary keys (not auto-incrementing integers): - Globally unique - Portable across databases - No collision risk in distributed systems
Soft Deletes¶
Entities are never hard-deleted:
- Set status = INACTIVE instead of DELETE
- Maintain referential integrity
- Enable audit trail
Decimal for Money¶
All monetary amounts use Decimal type (not float):
- Exact precision (no rounding errors)
- Stored as NUMERIC in database
- String representation in JSON ("442300.00")
Timestamps¶
All mutable entities include:
- created_at - When record was created (never changes)
- updated_at - Last modification time (auto-updated)
Next Steps¶
- Platform Interfaces: See platform-interfaces.md for how to interact with these objects
- Quick Reference: See quick-reference.md for common operations cheat sheet
- API Documentation: See http://localhost:8082/docs for interactive API docs
- Data Model Code: See
core/database/models.pyfor SQLModel implementations