Data Models

Comprehensive guide to all data models and their relationships in Gridova

User Model

user.jsonjson
{
  "id": "user_123abc",
  "email": "owner@example.com",
  "name": "John Doe",
  "role": "owner",  // "owner", "tenant", "admin"
  "phone": "+628123456789",
  "avatar_url": "https://cdn.gridova.com/avatars/user_123.jpg",
  "created_at": "2024-01-15T08:30:00Z",
  "updated_at": "2024-06-20T14:22:00Z",
  "settings": {
    "notifications_enabled": true,
    "email_alerts": true,
    "language": "id",
    "currency": "IDR",
    "timezone": "Asia/Jakarta"
  }
}

Boarding House Model

boarding_house.jsonjson
{
  "id": "bh_456def",
  "owner_id": "user_123abc",
  "name": "Kos Pak Budi",
  "description": "Boarding house near campus with 24/7 electricity monitoring",
  "address": {
    "street": "Jl. Sudirman No. 123",
    "city": "Jakarta",
    "province": "DKI Jakarta",
    "postal_code": "12345",
    "country": "Indonesia",
    "coordinates": {
      "latitude": -6.2088,
      "longitude": 106.8456
    }
  },
  "total_rooms": 10,
  "occupied_rooms": 7,
  "electricity_rate": 1500,  // IDR per kWh
  "admin_fee": 5000,  // IDR per month
  "created_at": "2024-01-15T08:30:00Z",
  "updated_at": "2024-06-20T14:22:00Z"
}

Room Model

room.jsonjson
{
  "id": "room_789ghi",
  "boarding_house_id": "bh_456def",
  "room_number": "A-101",
  "floor": 1,
  "type": "single",  // "single", "double", "suite"
  "status": "occupied",  // "vacant", "occupied", "maintenance"
  "monthly_rent": 1500000,  // IDR
  "size_sqm": 12.0,
  "facilities": [
    "AC",
    "Private Bathroom",
    "WiFi",
    "Wardrobe"
  ],
  "device_id": "ESP32_001",  // Associated IoT device
  "current_tenant_id": "user_tenant_001",
  "created_at": "2024-01-15T08:30:00Z",
  "updated_at": "2024-06-20T14:22:00Z"
}

Tenant Model

tenant.jsonjson
{
  "id": "user_tenant_001",
  "user_id": "user_999xyz",
  "room_id": "room_789ghi",
  "boarding_house_id": "bh_456def",
  "check_in_date": "2024-06-01",
  "check_out_date": null,  // null if still active
  "contract_duration": 12,  // months
  "deposit_amount": 1500000,  // IDR
  "emergency_contact": {
    "name": "Jane Doe",
    "relationship": "Mother",
    "phone": "+628987654321"
  },
  "id_card_number": "3201234567890123",
  "id_card_photo_url": "https://cdn.gridova.com/documents/ktp_001.jpg",
  "status": "active",  // "active", "expired", "terminated"
  "created_at": "2024-06-01T10:00:00Z",
  "updated_at": "2024-06-20T14:22:00Z"
}

Device Model

device.jsonjson
{
  "id": "ESP32_001",
  "room_id": "room_789ghi",
  "boarding_house_id": "bh_456def",
  "name": "Room A-101 Monitor",
  "type": "esp32",
  "hardware": {
    "board": "ESP32-WROOM-32",
    "sensors": ["PZEM-004T"],
    "relays": 2
  },
  "firmware_version": "1.2.3",
  "status": "online",  // "online", "offline", "error"
  "ip_address": "192.168.1.100",
  "mac_address": "AA:BB:CC:DD:EE:FF",
  "signal_strength": -45,  // dBm
  "uptime": 345600,  // seconds
  "last_seen": "2024-06-25T10:30:45Z",
  "relay_states": {
    "relay1": true,
    "relay2": false
  },
  "settings": {
    "data_interval": 5000,  // ms
    "alert_threshold_power": 2000,  // watts
    "auto_shutoff_enabled": false
  },
  "created_at": "2024-01-20T09:15:00Z",
  "updated_at": "2024-06-25T10:30:45Z"
}

Sensor Data Model

sensor_data.jsonjson
{
  "id": "sd_001abc",
  "device_id": "ESP32_001",
  "room_id": "room_789ghi",
  "timestamp": "2024-06-25T10:30:45Z",
  "data": {
    "voltage": 220.5,  // Volts
    "current": 2.83,  // Amperes
    "power": 623.81,  // Watts
    "energy": 12.456,  // kWh (cumulative)
    "frequency": 50.0,  // Hz
    "power_factor": 0.99,
    "apparent_power": 630.22,  // VA
    "reactive_power": 89.15  // VAR
  },
  "calculated": {
    "cost_hour": 935.72,  // IDR per hour at current power
    "cost_day": 22457.28,  // IDR per day
    "energy_today": 8.234,  // kWh today
    "cost_today": 12351.00  // IDR today
  }
}

Data Retention

Raw sensor data is kept for 30 days. Hourly aggregates are kept for 1 year. Daily/monthly summaries are kept indefinitely for billing purposes.

Relay Control Model

relay_control.jsonjson
{
  "id": "rc_002xyz",
  "device_id": "ESP32_001",
  "room_id": "room_789ghi",
  "relay_number": 1,
  "action": "on",  // "on", "off", "toggle"
  "triggered_by": "user_123abc",
  "trigger_type": "manual",  // "manual", "scheduled", "automation", "emergency"
  "timestamp": "2024-06-25T10:31:00Z",
  "success": true,
  "response_time_ms": 234,
  "metadata": {
    "source": "mobile_app",
    "app_version": "1.5.2",
    "platform": "android"
  }
}

Transaction Model

transaction.jsonjson
{
  "id": "txn_003abc",
  "tenant_id": "user_tenant_001",
  "room_id": "room_789ghi",
  "boarding_house_id": "bh_456def",
  "type": "electricity",  // "rent", "electricity", "deposit", "refund"
  "period": {
    "month": 6,
    "year": 2024,
    "start_date": "2024-06-01",
    "end_date": "2024-06-30"
  },
  "amount": 185000,  // IDR
  "breakdown": {
    "energy_kwh": 123.45,
    "rate_per_kwh": 1500,
    "subtotal": 185175,
    "admin_fee": 0,
    "adjustment": -175,
    "total": 185000
  },
  "status": "paid",  // "pending", "paid", "overdue", "cancelled"
  "payment_method": "transfer",  // "cash", "transfer", "ewallet", "card"
  "payment_date": "2024-07-01T08:15:00Z",
  "payment_proof_url": "https://cdn.gridova.com/payments/proof_003.jpg",
  "due_date": "2024-07-05",
  "notes": "June 2024 electricity bill",
  "created_at": "2024-07-01T00:00:00Z",
  "updated_at": "2024-07-01T08:15:00Z"
}

Alert Model

alert.jsonjson
{
  "id": "alert_004xyz",
  "device_id": "ESP32_001",
  "room_id": "room_789ghi",
  "type": "high_power",  // "high_power", "offline", "sensor_error", "overload"
  "severity": "warning",  // "info", "warning", "error", "critical"
  "title": "High Power Consumption",
  "message": "Power usage exceeded 2000W threshold",
  "data": {
    "current_power": 2350.5,
    "threshold": 2000.0,
    "duration_seconds": 120
  },
  "resolved": false,
  "resolved_at": null,
  "resolved_by": null,
  "timestamp": "2024-06-25T10:32:00Z",
  "notifications_sent": {
    "push": true,
    "email": true,
    "sms": false
  }
}

Automation Rule Model

automation_rule.jsonjson
{
  "id": "rule_005abc",
  "user_id": "user_123abc",
  "room_id": "room_789ghi",
  "device_id": "ESP32_001",
  "name": "Auto shutoff at night",
  "enabled": true,
  "trigger": {
    "type": "schedule",  // "schedule", "sensor", "manual"
    "schedule": {
      "time": "23:00",
      "days": ["mon", "tue", "wed", "thu", "fri", "sat", "sun"],
      "timezone": "Asia/Jakarta"
    }
  },
  "conditions": [
    {
      "type": "power",
      "operator": "<",
      "value": 50,
      "unit": "watts"
    }
  ],
  "actions": [
    {
      "type": "relay_control",
      "relay": 1,
      "state": false
    },
    {
      "type": "notification",
      "message": "Room A-101 power automatically turned off"
    }
  ],
  "last_triggered": "2024-06-24T23:00:00Z",
  "trigger_count": 45,
  "created_at": "2024-02-10T14:30:00Z",
  "updated_at": "2024-06-20T09:15:00Z"
}

Energy Summary Model

energy_summary.jsonjson
{
  "id": "summary_006xyz",
  "room_id": "room_789ghi",
  "period_type": "monthly",  // "daily", "weekly", "monthly", "yearly"
  "period": {
    "month": 6,
    "year": 2024
  },
  "statistics": {
    "total_energy_kwh": 123.45,
    "total_cost": 185175,
    "average_power": 175.8,
    "peak_power": 2350.5,
    "peak_timestamp": "2024-06-15T14:30:00Z",
    "minimum_power": 12.3,
    "hours_active": 720,
    "hours_off": 0
  },
  "comparison": {
    "previous_period_kwh": 118.32,
    "change_percentage": 4.33,
    "trend": "increasing"
  },
  "daily_breakdown": [
    {
      "date": "2024-06-01",
      "energy_kwh": 4.12,
      "cost": 6180,
      "avg_power": 171.67
    },
    // ... other days
  ],
  "cost_breakdown": {
    "energy_cost": 185175,
    "admin_fee": 5000,
    "tax": 0,
    "total": 190175
  },
  "generated_at": "2024-07-01T00:05:00Z"
}

Model Relationships

Entity Relationship Diagram

User (Owner)
  ↓ owns (1:N)
BoardingHouse
  ↓ contains (1:N)
Room
  ├─ occupiedBy (1:1) → Tenant (User)
  ├─ monitors (1:1) → Device
  └─ generates (1:N) → Transaction

Device
  ├─ produces (1:N) → SensorData
  ├─ receives (1:N) → RelayControl
  ├─ triggers (1:N) → Alert
  └─ executes (1:N) → AutomationRule

Room + Period
  └─ summarizes (1:1) → EnergySummary
                

API Response Format

All API responses follow this standard format:

Success Response

success_response.jsonjson
{
  "success": true,
  "data": {
    // Requested data here
  },
  "meta": {
    "timestamp": "2024-06-25T10:30:45Z",
    "request_id": "req_abc123"
  }
}

Success with Pagination

paginated_response.jsonjson
{
  "success": true,
  "data": [
    // Array of items
  ],
  "pagination": {
    "page": 1,
    "per_page": 20,
    "total_items": 157,
    "total_pages": 8,
    "has_next": true,
    "has_prev": false
  },
  "meta": {
    "timestamp": "2024-06-25T10:30:45Z",
    "request_id": "req_abc123"
  }
}

Error Response

error_response.jsonjson
{
  "success": false,
  "error": {
    "code": "DEVICE_NOT_FOUND",
    "message": "Device with ID 'ESP32_999' not found",
    "details": {
      "device_id": "ESP32_999"
    }
  },
  "meta": {
    "timestamp": "2024-06-25T10:30:45Z",
    "request_id": "req_abc123"
  }
}

Common Error Codes

CodeHTTP StatusDescription
UNAUTHORIZED401Invalid or missing authentication token
FORBIDDEN403User lacks permission for this resource
NOT_FOUND404Requested resource does not exist
VALIDATION_ERROR422Invalid request data or parameters
RATE_LIMIT_EXCEEDED429Too many requests in given timeframe
DEVICE_OFFLINE503Device is not connected or responding
SERVER_ERROR500Internal server error occurred

TypeScript Type Definitions

types.tstypescript
// User types
export interface User {
  id: string;
  email: string;
  name: string;
  role: 'owner' | 'tenant' | 'admin';
  phone?: string;
  avatar_url?: string;
  created_at: string;
  updated_at: string;
  settings: UserSettings;
}

export interface UserSettings {
  notifications_enabled: boolean;
  email_alerts: boolean;
  language: string;
  currency: string;
  timezone: string;
}

// Boarding House types
export interface BoardingHouse {
  id: string;
  owner_id: string;
  name: string;
  description?: string;
  address: Address;
  total_rooms: number;
  occupied_rooms: number;
  electricity_rate: number;
  admin_fee: number;
  created_at: string;
  updated_at: string;
}

export interface Address {
  street: string;
  city: string;
  province: string;
  postal_code: string;
  country: string;
  coordinates?: Coordinates;
}

export interface Coordinates {
  latitude: number;
  longitude: number;
}

// Room types
export interface Room {
  id: string;
  boarding_house_id: string;
  room_number: string;
  floor: number;
  type: 'single' | 'double' | 'suite';
  status: 'vacant' | 'occupied' | 'maintenance';
  monthly_rent: number;
  size_sqm: number;
  facilities: string[];
  device_id?: string;
  current_tenant_id?: string;
  created_at: string;
  updated_at: string;
}

// Device types
export interface Device {
  id: string;
  room_id: string;
  boarding_house_id: string;
  name: string;
  type: string;
  hardware: DeviceHardware;
  firmware_version: string;
  status: 'online' | 'offline' | 'error';
  ip_address?: string;
  mac_address: string;
  signal_strength?: number;
  uptime: number;
  last_seen: string;
  relay_states: RelayStates;
  settings: DeviceSettings;
  created_at: string;
  updated_at: string;
}

export interface DeviceHardware {
  board: string;
  sensors: string[];
  relays: number;
}

export interface RelayStates {
  relay1: boolean;
  relay2: boolean;
}

export interface DeviceSettings {
  data_interval: number;
  alert_threshold_power: number;
  auto_shutoff_enabled: boolean;
}

// Sensor Data types
export interface SensorData {
  id: string;
  device_id: string;
  room_id: string;
  timestamp: string;
  data: SensorReadings;
  calculated: CalculatedData;
}

export interface SensorReadings {
  voltage: number;
  current: number;
  power: number;
  energy: number;
  frequency: number;
  power_factor: number;
  apparent_power?: number;
  reactive_power?: number;
}

export interface CalculatedData {
  cost_hour: number;
  cost_day: number;
  energy_today: number;
  cost_today: number;
}

// Transaction types
export interface Transaction {
  id: string;
  tenant_id: string;
  room_id: string;
  boarding_house_id: string;
  type: 'rent' | 'electricity' | 'deposit' | 'refund';
  period: TransactionPeriod;
  amount: number;
  breakdown: TransactionBreakdown;
  status: 'pending' | 'paid' | 'overdue' | 'cancelled';
  payment_method?: string;
  payment_date?: string;
  payment_proof_url?: string;
  due_date: string;
  notes?: string;
  created_at: string;
  updated_at: string;
}

export interface TransactionPeriod {
  month: number;
  year: number;
  start_date: string;
  end_date: string;
}

export interface TransactionBreakdown {
  energy_kwh?: number;
  rate_per_kwh?: number;
  subtotal: number;
  admin_fee: number;
  adjustment: number;
  total: number;
}

// Alert types
export interface Alert {
  id: string;
  device_id: string;
  room_id: string;
  type: string;
  severity: 'info' | 'warning' | 'error' | 'critical';
  title: string;
  message: string;
  data: Record<string, any>;
  resolved: boolean;
  resolved_at?: string;
  resolved_by?: string;
  timestamp: string;
  notifications_sent: NotificationStatus;
}

export interface NotificationStatus {
  push: boolean;
  email: boolean;
  sms: boolean;
}

// API Response types
export interface ApiResponse<T> {
  success: boolean;
  data?: T;
  error?: ApiError;
  pagination?: Pagination;
  meta: ApiMeta;
}

export interface ApiError {
  code: string;
  message: string;
  details?: Record<string, any>;
}

export interface Pagination {
  page: number;
  per_page: number;
  total_items: number;
  total_pages: number;
  has_next: boolean;
  has_prev: boolean;
}

export interface ApiMeta {
  timestamp: string;
  request_id: string;
}

Next Steps

REST API Reference
Explore all REST API endpoints with request/response examples
WebSocket API
Learn real-time communication with WebSocket protocol
Authentication Guide
Understand JWT authentication and authorization flow