# Lapisan data mentah

Lapisan data mentah berisi 3 skema data yang berbeda, masing-masing melayani aspek yang berbeda dari platform telematika dan business intelligence:

* [`raw_business_data`](#raw_business_data-structure) - berisi tabel, atribut, dan nilai yang terkait dengan informasi bisnis, seperti kendaraan, karyawan, geofence yang ditambahkan oleh pengguna, dll.
* [`raw_telematics_data`](#raw_telematics_data-structure) - berisi tabel, atribut, dan nilai yang terkait dengan data telematika yang dikirim dari perangkat yang dipantau, seperti lokasi, input, output, dan peristiwa.
* [`repo`](#repo-data-structure) - berisi tabel untuk manajemen aset dan inventaris, termasuk tipe aset yang dapat dikonfigurasi, bidang kustom, relasi aset, dan data geospasial untuk pelacakan sumber daya organisasi.

Setiap skema dioptimalkan untuk domain data dan pola aksesnya masing-masing, sehingga memberikan cakupan menyeluruh untuk kebutuhan operasional, telematika, dan manajemen aset.

## `raw_business_data` struktur

Skema ini berisi 40+ tabel yang dipilih dengan cermat untuk mencakup berbagai aspek bisnis dan kasus penggunaan. Tabel-tabel ini merepresentasikan entitas bisnis inti Anda, struktur organisasi, dan data operasional.

<figure><img src="https://660637463-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoFNFEIINiGFbhi3Px3dE%2Fuploads%2FLxWgTRWILnl4LOQt1IZL%2Fraw_business_data.svg?alt=media&#x26;token=66789735-63b4-4328-911c-322cf3283b62" alt=""><figcaption></figcaption></figure>

{% hint style="info" %}
Diagram interaktif skema raw\_business\_data tersedia di **dbdiagram.io**: <https://dbdiagram.io/d/V3-bronze-layer-68ecfd1c2e68d21b4131089a>
{% endhint %}

Temukan detail skema data bisnis mentah di bawah ini.

{% code title="Skema raw\_business\_data" expandable="true" %}

```sql
Table "vehicle_service_tasks" {
  "record_added_at" timestamp [not null]
  "start_mileage" numeric
  "comment" "character varying(255)"
  "status" "character varying(10)" [not null]
  "completion_date" timestamp
  "start_engine_hours" numeric
  "service_task_id" integer [not null]
  "is_notification_push_enabled" boolean [not null]
  "date_notification_interval" interval
  "predicted_datetime" timestamp
  "cost" numeric [not null]
  "mileage_limit" numeric
  "notification_emails" text
  "is_unplanned" boolean [not null]
  "is_repeat" boolean [not null]
  "completion_engine_hours" integer
  "engine_hours_limit" numeric
  "mileage_repeat_interval" integer
  "vehicle_id" integer [not null]
  "engine_hours_notification_interval" integer
  "start_date" timestamp
  "mileage_notification_interval" integer
  "date_repeat_interval" interval
  "description" "character varying(255)"
  "notification_sms_phone_numbers" text
  "end_date" timestamp
  "engine_hours_repeat_interval" integer
  "completion_mileage" integer
}

Table "garages" {
  "record_added_at" timestamp [not null]
  "garage_id" integer [not null]
  "longitude" numeric
  "mechanic_name" "character varying(255)"
  "radius" integer [not null]
  "latitude" numeric
  "organization_label" "character varying(255)"
  "user_id" integer [not null]
  "dispatcher_name" "character varying(255)"
  "address" "character varying(255)"
}

Table "driver_history" {
  "server_datetime" timestamp [not null]
  "address" "character varying(255)"
  "updated_by" integer [not null]
  "object_id" integer
  "longitude" numeric
  "latitude" numeric
  "driver_history_id" integer [not null]
  "hardware_key" "character varying(64)"
  "new_employee_id" integer
  "changed_datetime" timestamp
  "record_added_at" timestamp [not null]
  "old_employee_id" integer
}

Table "departments" {
  "record_added_at" timestamp [not null]
  "department_label" "character varying(255)" [not null]
  "latitude" numeric
  "department_id" integer [not null]
  "address" "character varying(255)"
  "radius" integer [not null]
  "longitude" numeric
  "user_id" integer [not null]
}

Table "checkins" {
  "radius" integer [not null]
  "latitude" numeric [not null]
  "employee_id" integer [not null]
  "longitude" numeric [not null]
  "record_added_at" timestamp [not null]
  "actual_datetime" timestamp [not null]
  "user_id" integer [not null]
  "form_id" integer [not null]
  "address" "character varying(255)"
  "planned_datetime" timestamp [not null]
  "object_id" integer [not null]
  "checkin_id" integer [not null]
  "comment" text
}

Table "statuses" {
  "order_sort" integer [not null]
  "listing_id" integer [not null]
  "color" "character varying(6)" [not null]
  "status_id" integer [not null]
  "status_label" "character varying(200)" [not null]
  "record_added_at" timestamp [not null]
  "is_deleted" boolean [not null]
}

Table "places_linked_entity_fields" {
  "value" bigint [not null]
  "record_added_at" timestamp [not null]
  "place_id" integer [not null]
  "field_id" integer [not null]
}

Table "places_text_fields" {
  "place_id" integer [not null]
  "record_added_at" timestamp [not null]
  "value" text [not null]
  "field_id" integer [not null]
}

Table "users2zones" {
  "zone_id" integer [not null]
  "record_added_at" timestamp [not null]
  "user_id" integer [not null]
}

Table "objects" {
  "record_added_at" timestamp [not null]
  "create_datetime" timestamp [not null]
  "client_id" integer [not null]
  "group_id" integer
  "object_label" "character varying(100)"
  "model" "character varying(64)"
  "is_clone" boolean [not null]
  "is_deleted" boolean [not null]
  "device_id" integer [not null]
  "object_id" integer [not null]
}

Table "device_output_name" {
  "device_id" integer [not null]
  "record_added_at" timestamp [not null]
  "label" "character varying(100)" [not null]
  "number" integer [not null]
}

Table "geofence_points" {
  "longitude" numeric [not null]
  "number" integer [not null]
  "zone_id" integer [not null]
  "record_added_at" timestamp [not null]
  "latitude" numeric [not null]
}

Table "custom_fields" {
  "record_added_at" timestamp [not null]
  "entity_id" integer [not null]
  "is_required" boolean [not null]
  "custom_field_label" text [not null]
  "parameters" jsonb
  "custom_field_type" integer [not null]
  "description" text
  "custom_field_id" integer [not null]
}

Table "places_decimal_fields" {
  "field_id" integer [not null]
  "record_added_at" timestamp [not null]
  "place_id" integer [not null]
  "value" numeric [not null]
}

Table "task_history" {
  "task_id" integer [not null]
  "activity" integer [not null]
  "task_history_id" integer [not null]
  "record_added_at" timestamp [not null]
  "user_id" integer [not null]
  "event_datetime" timestamp [not null]
  "payload" text
}

Table "tags" {
  "tag_label" "character varying(64)" [not null]
  "color" "character varying(6)"
  "user_id" integer [not null]
  "record_added_at" timestamp [not null]
  "tag_id" integer [not null]
}

Table "places" {
  "description" text
  "custom_fields" jsonb
  "place_id" integer [not null]
  "external_id" "character varying(32)"
  "record_added_at" timestamp [not null]
  "user_id" integer
  "latitude" numeric
  "radius" integer
  "place_label" "character varying(256)"
  "assigned_datetime" timestamp
  "address" "character varying(256)"
  "longitude" numeric
}

Table "status_listings" {
  "user_id" integer [not null]
  "is_supervisor_controlled" boolean [not null]
  "is_deleted" boolean [not null]
  "status_listing_id" integer [not null]
  "is_employee_controlled" boolean [not null]
  "record_added_at" timestamp [not null]
  "status_listing_label" "character varying(200)" [not null]
}

Table "models" {
  "record_added_at" timestamp [not null]
  "model_id" integer [not null]
  "has_battery_level" boolean [not null]
  "alternative_label" "character varying(50)" [not null]
  "vendor" "character varying(30)" [not null]
  "is_clone" boolean
  "has_altitude" boolean [not null]
  "has_phone" boolean [not null]
  "type_output_control" "character varying(30)" [not null]
  "has_gsm_roaming" boolean [not null]
  "has_gsm_level" boolean [not null]
  "model" "character varying(255)" [not null]
  "type_special_control" "character varying(255)" [not null]
  "digital_amount" integer [not null]
  "has_detach_button" boolean [not null]
  "has_gsm_name" boolean [not null]
  "analog_amount" integer [not null]
  "outputs_amount" integer [not null]
}

Table "vehicle_trackers_history" {
  "vehicle_id" integer [not null]
  "record_added_at" timestamp [not null]
  "object_id" integer [not null]
  "changed_datetime" timestamp [not null]
  "vehicle_tracker_history_id" integer [not null]
}

Table "groups" {
  "group_id" integer [not null]
  "group_color" "character varying(6)" [not null]
  "group_label" "character varying(255)" [not null]
  "client_id" integer [not null]
  "record_added_at" timestamp [not null]
}

Table "sensor_description" {
  "record_added_at" timestamp [not null]
  "parameters" jsonb
  "input_id" integer [not null]
  "accuracy" numeric [not null]
  "sensor_units" "character varying(10)"
  "multiplier" doubleprecision [not null]
  "input_label" "character varying(64)"
  "sensor_label" "character varying(100)"
  "units_type" integer [not null]
  "divider" doubleprecision [not null]
  "group_id" integer [not null]
  "sensor_id" integer [not null]
  "device_id" integer [not null]
  "sensor_type" "character varying(45)" [not null]
  "group_type" integer [not null]
  "calibration_data" jsonb
}

Table "entities" {
  "entity_label" jsonb
  "record_added_at" timestamp [not null]
  "entity_id" integer [not null]
  "builtin_type" integer [not null]
  "user_id" integer [not null]
}

Table "zones" {
  "address" "character varying(255)"
  "radius" integer [not null]
  "zone_id" integer [not null]
  "circle_center_latitude" numeric [not null]
  "client_id" integer [not null]
  "zone_label" "character varying(100)"
  "color" "character varying(6)" [not null]
  "zone_type" "character varying(20)" [not null]
  "circle_center_longitude" numeric [not null]
  "latitude" numeric [not null]
  "record_added_at" timestamp [not null]
  "longitude" numeric [not null]
}

Table "vehicles" {
  "vehicle_id" integer [not null]
  "payload_length" numeric
  "vin" "character varying(20)"
  "free_insurance_policy_number" "character varying(50)"
  "vehicle_label" "character varying(100)"
  "payload_width" numeric
  "color" "character varying(6)"
  "trailer" "character varying(255)"
  "object_id" integer
  "vehicle_status_id" integer
  "liability_insurance_valid_till" timestamp
  "manufacture_year" integer
  "fuel_grade" "character varying(16)"
  "fuel_cost" numeric
  "fuel_tank_volume" numeric
  "model" "character varying(100)"
  "garage_id" integer
  "payload_height" numeric
  "max_speed" numeric
  "registration_number" "character varying(32)"
  "tyre_size" "character varying(50)"
  "passenger_capacity" integer
  "record_added_at" timestamp [not null]
  "trailer_reg_number" "character varying(32)"
  "free_insurance_valid_till_date" timestamp
  "gross_weight" numeric
  "standard_fuel_consumption" numeric
  "fuel_type" integer
  "payload_weight" numeric
  "additional_info" text
  "vehicle_subtype" "character varying(32)"
  "liability_insurance_policy_number" "character varying(50)"
  "frame_number" "character varying(32)"
  "user_id" integer [not null]
  "vehicle_type" integer [not null]
  "chassis_number" "character varying(32)"
  "tyres_number" integer
  "wheel_arrangement" "character varying(16)"
}

Table "tag_links" {
  "entity_id" integer [not null]
  "record_added_at" timestamp [not null]
  "entity_type" integer [not null]
  "ordinal" integer [not null]
  "tag_id" integer [not null]
}

Table "rules" {
  "rule_id" integer [not null]
  "object_id" integer [not null]
  "parameters" jsonb
  "alert_phone" "character varying(210)" [not null]
  "event_type" "character varying(100)" [not null]
  "client_id" integer [not null]
  "is_push_enabled" boolean [not null]
  "event_comment1" "character varying(255)" [not null]
  "event_label" "character varying(255)" [not null]
  "description" "character varying(255)" [not null]
  "record_added_at" timestamp [not null]
  "alert_sms" text [not null]
  "event_group" integer [not null]
  "created_at" timestamp [not null]
  "maximum" integer [not null]
  "is_deleted" boolean [not null]
  "alert_email" text [not null]
  "event_comment2" "character varying(255)" [not null]
}

Table "status_history" {
  "longitude" numeric
  "new_status_id" integer
  "status_history_id" integer [not null]
  "device_id" integer [not null]
  "updated_by" integer [not null]
  "address" "character varying(255)"
  "latitude" numeric
  "record_added_at" timestamp [not null]
  "server_datetime" timestamp [not null]
  "changed_datetime" timestamp
  "old_status_id" integer
}

Table "rules2zones" {
  "zone_id" integer [not null]
  "record_added_at" timestamp [not null]
  "rule_id" integer [not null]
}

Table "forms" {
  "object_id" integer [not null]
  "description" text
  "form_label" "character varying(255)" [not null]
  "fields" text
  "created_at" timestamp [not null]
  "submission_address" "character varying(255)"
  "submission_latitude" numeric
  "form_id" integer [not null]
  "submission_longitude" numeric
  "is_submission_in_zone" boolean [not null]
  "values" text
  "record_added_at" timestamp [not null]
  "task_id" integer
  "submitted_at" timestamp
}


Table "rules2objects" {
  "object_params" jsonb
  "param_group_number" integer [not null]
  "object_id" integer [not null]
  "record_added_at" timestamp [not null]
  "rule_id" integer [not null]
}

Table "tasks" {
  "time_from" timestamp
  "stay_duration_minutes" interval
  "external_id" "character varying(100)"
  "object_id" integer
  "task_type" integer
  "arrival_duration_minutes" interval
  "status" integer
  "arrival_datetime" timestamp
  "record_added_at" timestamp [not null]
  "task_id" integer [not null]
  "user_id" integer
  "status_change_datetime" timestamp
  "order_sort" integer
  "time_to" timestamp
  "max_delay_minuts" integer
  "is_stay_control_enabled" boolean
  "address" "character varying(255)"
  "task_label" "character varying(200)" [not null]
  "longitude" numeric
  "created_by" integer
  "description" text [not null]
  "radius" integer
  "latitude" numeric
  "stay_duration" integer
  "created_at" timestamp [not null]
  "custom_fields" jsonb
  "parent_task_id" integer
}

Table "places_bigint_fields" {
  "field_id" integer [not null]
  "value" bigint [not null]
  "place_id" integer [not null]
  "record_added_at" timestamp [not null]
}

Table "devices" {
  "is_sim_blocked" boolean [not null]
  "device_id" integer [not null]
  "device_imei" "character varying(64)" [not null]
  "network_label" "character varying(50)" [not null]
  "status_listing_id" integer [not null]
  "signal_level" numeric [not null]
  "phone" "character varying(32)" [not null]
  "has_roaming" boolean [not null]
  "created_at" timestamp [not null]
  "owner_id" integer [not null]
  "record_added_at" timestamp [not null]
}

Table "description_parameters" {
  "description" "character varying(150)"
  "record_added_at" timestamp [not null]
  "type" "character varying(100)" [not null]
  "key" integer [not null]
}

Table "users" {
  "company_label" "character varying(255)" [not null]
  "registration_datetime" timestamp
  "first_name" "character varying(100)" [not null]
  "master_id" integer
  "last_name" "character varying(100)" [not null]
  "birth_date" timestamp
  "timezone_label" "character varying(30)"
  "middle_name" "character varying(100)" [not null]
  "user_id" integer [not null]
  "locale" "character varying(10)" [not null]
  "record_added_at" timestamp [not null]
}

Table "counters" {
  "sensor_id" integer
  "multiplier" numeric [not null]
  "counter_id" integer [not null]
  "device_id" integer [not null]
  "counter_type" integer [not null]
  "record_added_at" timestamp [not null]
}

Table "employees" {
  "driver_license_valid_till" timestamp
  "record_added_at" timestamp [not null]
  "last_name" "character varying(100)"
  "department_id" integer
  "citizen_id_number" "character varying(32)"
  "first_name" "character varying(100)"
  "driver_license_categories" "character varying(32)"
  "user_id" integer [not null]
  "phone_number" "character varying(32)"
  "object_id" integer
  "is_deleted" boolean [not null]
  "driver_license_issue_date" boolean
  "hardware_key" "character varying(64)"
  "middle_name" "character varying(100)"
  "address" "character varying(255)"
  "latitude" numeric
  "employee_id" integer [not null]
  "personnel_number" "character varying(15)"
  "fuel_cost" doubleprecision
  "driver_license_number" "character varying(32)"
  "email" "character varying(100)"
  "fuel_consumption" doubleprecision
  "radius" integer [not null]
  "longitude" numeric
}

Table "places_longtext_fields" {
  "field_id" integer [not null]
  "value" text [not null]
  "record_added_at" timestamp [not null]
  "place_id" integer [not null]
}

Table "groups_objects" {
  "groups_client_id" integer
  "objects_client_id" integer

  Indexes {
    (groups_client_id, objects_client_id) [pk]
  }
}

Ref:"employees"."employee_id" < "checkins"."employee_id"

Ref:"objects"."object_id" < "checkins"."object_id"

Ref:"forms"."form_id" < "checkins"."form_id"

Ref:"sensor_description"."sensor_id" < "counters"."sensor_id"

Ref:"devices"."device_id" < "counters"."device_id"

Ref:"entities"."entity_id" < "custom_fields"."entity_id"

Ref:"departments"."department_id" < "employees"."department_id"

Ref:"users"."user_id" < "departments"."user_id"

Ref:"description_parameters"."key" < "counters"."counter_type"

Ref:"description_parameters"."key" < "custom_fields"."custom_field_type"

Ref:"description_parameters"."key" < "driver_history"."updated_by"

Ref:"description_parameters"."key" < "entities"."builtin_type"

Ref:"description_parameters"."key" < "sensor_description"."units_type"

Ref:"description_parameters"."key" < "status_history"."updated_by"

Ref:"description_parameters"."key" < "tasks"."status"

Ref:"description_parameters"."key" < "tasks"."created_at"

Ref:"description_parameters"."key" < "tasks"."task_type"

Ref:"description_parameters"."key" < "vehicles"."fuel_type"

Ref:"description_parameters"."key" < "task_history"."activity"

Ref:"description_parameters"."key" < "sensor_description"."group_type"

Ref:"devices"."device_id" < "device_output_name"."device_id"

Ref:"status_listings"."status_listing_id" < "devices"."status_listing_id"

Ref:"employees"."employee_id" < "driver_history"."new_employee_id"

Ref:"employees"."employee_id" < "driver_history"."old_employee_id"

Ref:"objects"."object_id" < "driver_history"."object_id"

Ref:"objects"."object_id" < "employees"."object_id"

Ref:"users"."user_id" < "employees"."user_id"

Ref:"users"."user_id" < "entities"."user_id"

Ref:"tasks"."task_id" < "forms"."task_id"

Ref:"objects"."object_id" < "forms"."object_id"

Ref:"objects"."object_id" < "tasks"."object_id"

Ref:"users"."user_id" < "garages"."user_id"

Ref:"groups"."client_id" < "groups_objects"."groups_client_id"

Ref:"objects"."client_id" < "groups_objects"."objects_client_id"

Ref:"models"."model" < "objects"."model"

Ref:"devices"."device_id" < "objects"."device_id"

Ref:"users"."user_id" < "places"."user_id"

Ref:"custom_fields"."custom_field_id" < "places_bigint_fields"."field_id"

Ref:"places"."place_id" < "places_bigint_fields"."place_id"

Ref:"custom_fields"."custom_field_id" < "places_decimal_fields"."field_id"

Ref:"places"."place_id" < "places_decimal_fields"."place_id"

Ref:"custom_fields"."custom_field_id" < "places_linked_entity_fields"."field_id"

Ref:"places"."place_id" < "places_linked_entity_fields"."place_id"

Ref:"custom_fields"."custom_field_id" < "places_longtext_fields"."field_id"

Ref:"places"."place_id" < "places_longtext_fields"."place_id"

Ref:"custom_fields"."custom_field_id" < "places_text_fields"."field_id"

Ref:"places"."place_id" < "places_text_fields"."place_id"

Ref:"rules"."rule_id" < "rules2zones"."rule_id"

Ref:"objects"."object_id" < "rules2objects"."object_id"

Ref:"rules"."rule_id" < "rules2objects"."object_id"

Ref:"zones"."zone_id" < "rules2zones"."zone_id"

Ref:"devices"."device_id" < "sensor_description"."device_id"

Ref:"statuses"."status_id" < "status_history"."new_status_id"

Ref:"statuses"."status_id" < "status_history"."old_status_id"

Ref:"devices"."device_id" < "status_history"."device_id"

Ref:"users"."user_id" < "status_listings"."user_id"

Ref:"status_listings"."status_listing_id" < "statuses"."listing_id"

Ref:"tags"."tag_id" < "tag_links"."tag_id"

Ref:"users"."user_id" < "tags"."user_id"

Ref:"tasks"."task_id" < "task_history"."task_id"

Ref:"users"."user_id" < "task_history"."user_id"

Ref:"tasks"."parent_task_id" < "tasks"."task_id"

Ref:"users"."user_id" < "tasks"."user_id"

Ref:"users"."master_id" < "users"."user_id"

Ref:"users"."user_id" < "users2zones"."user_id"

Ref:"zones"."zone_id" < "users2zones"."zone_id"

Ref:"vehicles"."vehicle_id" < "vehicle_service_tasks"."vehicle_id"

Ref:"objects"."object_id" < "vehicle_trackers_history"."object_id"

Ref:"vehicles"."vehicle_id" < "vehicle_trackers_history"."vehicle_id"

Ref:"garages"."garage_id" < "vehicles"."garage_id"

Ref:"objects"."object_id" < "vehicles"."object_id"

Ref:"users"."user_id" < "vehicles"."user_id"

Ref:"zones"."zone_id" < "geofence_points"."zone_id"

Ref:"users"."user_id" < "devices"."owner_id"

Ref:"users"."user_id" < "objects"."client_id"

```

{% endcode %}

### Frekuensi pembaruan

Data dalam skema ini disinkronkan dengan DB inti. Pembaruan dilakukan secara inkremental saat perubahan terjadi di database MySQL sumber, biasanya kurang dari 5 menit sejak perubahan sumber.

### `description_parameters`

Sistem mencakup data referensi untuk menstandardisasi nilai di seluruh basis data:

<table><thead><tr><th width="167.1817626953125">Jenis referensi</th><th width="173.9090576171875">Deskripsi</th><th>Contoh nilai</th></tr></thead><tbody><tr><td>Definisi tipe</td><td>Tipe entitas standar</td><td><code>vehicle_type: car, truck, bus</code></td></tr><tr><td>Kode status</td><td>Nilai status tugas dan sistem</td><td><code>tasks_status: unassigned, assigned, done</code></td></tr><tr><td>Definisi satuan</td><td>Satuan pengukuran untuk sensor</td><td><code>units_type: liter, gallon, celsius</code></td></tr><tr><td>Klasifikasi entitas</td><td>Kategori entitas bisnis</td><td><code>entities_type: place, task, customer</code></td></tr></tbody></table>

### Tabel kunci menurut kategori

Tabel dalam **`raw_business_data`** schema diatur ke dalam kategori fungsional agar navigasi lebih mudah. Tabel di bawah ini merangkum tabel kunci menurut tujuan bisnisnya:

Entitas bisnis inti

<details>

<summary><strong><code>users</code></strong></summary>

**Deskripsi**: Akun pengguna yang berisi informasi profil, afiliasi perusahaan, pengaturan lokalisasi (timezone, locale), dan hubungan hierarkis melalui master\_id untuk struktur akun multi-level

<table><thead><tr><th width="145">Atribut</th><th>Detail</th></tr></thead><tbody><tr><td><strong>Bidang kunci</strong></td><td>- <code>user_id</code> - Pengidentifikasi unik pengguna<br>- <code>company_label</code> - Nama perusahaan yang terkait dengan pengguna<br>- <code>first_name</code> - Nama pengguna<br>- <code>last_name</code> - Nama belakang pengguna<br>- <code>middle_name</code> - Nama tengah pengguna<br>- <code>locale</code> - Pengaturan bahasa pengguna<br>- <code>timezone_label</code> - Zona waktu dalam format IANA<br>- <code>master_id</code> - ID pengguna utama (jika yang saat ini adalah bawahan)<br>- <code>registration_datetime</code> - Tanggal pendaftaran di sistem<br>- <code>birth_date</code> - Tanggal lahir pengguna</td></tr><tr><td><strong>Relasi</strong></td><td>Pengguna induk melalui <code>master_id</code>, terhubung ke <code>employees</code>, <code>departments</code>, <code>places</code>, <code>tasks</code> melalui <code>user_id</code></td></tr><tr><td><strong>Catatan khusus</strong></td><td>Entitas pusat yang menghubungkan data organisasi; <code>master_id</code> memungkinkan hierarki pengguna untuk struktur akun multi-level</td></tr></tbody></table>

</details>

<details>

<summary><strong><code>employees</code></strong></summary>

**Deskripsi**: Data karyawan dan pengemudi yang digunakan untuk merepresentasikan orang yang bekerja untuk organisasi, termasuk informasi pribadi, detail lisensi, penugasan departemen, kunci perangkat keras untuk identifikasi iButton/RFID, dan data lokasi dengan dukungan geofencing

<table><thead><tr><th width="143">Atribut</th><th>Detail</th></tr></thead><tbody><tr><td><strong>Bidang kunci</strong></td><td>- <code>employee_id</code> - Pengidentifikasi entitas karyawan<br>- <code>user_id</code> - Pengidentifikasi entitas pengguna<br>- <code>object_id</code> - Pengidentifikasi objek entitas<br>- <code>department_id</code> - ID departemen tempat karyawan ditugaskan<br>- <code>first_name</code> - Atribut first_name pada tabel employees<br>- <code>last_name</code> - Atribut last_name pada tabel employees<br>- <code>middle_name</code> - Atribut middle_name pada tabel employees<br>- <code>driver_license_number</code> - Nomor SIM<br>- <code>driver_license_categories</code> - Kategori SIM<br>- <code>driver_license_issue_date</code> - Tanggal penerbitan SIM<br>- <code>driver_license_valid_till</code> - Tanggal sampai SIM berlaku<br>- <code>hardware_key</code> - Kunci perangkat keras<br>- <code>email</code> - Email karyawan<br>- <code>phone_number</code> - Telepon karyawan tanpa tanda "+"<br>- <code>address</code> - Alamat lokasi<br>- <code>personnel_number</code> - Nomor personel karyawan/pengemudi<br>- <code>citizen_id_number</code> - Nomor KTP/NIK<br>- <code>latitude</code> - Lokasi yang terkait dengan karyawan ini<br>- <code>longitude</code> - Lokasi yang terkait dengan karyawan ini<br>- <code>radius</code> - Lokasi yang terkait dengan karyawan ini dalam meter<br>- <code>fuel_consumption</code> - Atribut fuel_consumption pada tabel employees<br>- <code>fuel_cost</code> - Atribut fuel_cost pada tabel employees<br>- <code>is_deleted</code> - Atribut is_deleted pada tabel employees</td></tr><tr><td><strong>Relasi</strong></td><td>Terkait dengan <code>users</code>, <code>departments</code>, <code>objects</code> (tracker yang ditugaskan), dilacak di <code>driver_history</code> dan <code>checkins</code></td></tr><tr><td><strong>Catatan khusus</strong></td><td>Kunci perangkat keras memungkinkan identifikasi pengemudi melalui iButton atau RFID; mendukung geofencing dengan <code>latitude</code>, <code>longitude</code>, <code>radius</code> bidang</td></tr></tbody></table>

</details>

<details>

<summary><strong><code>departments</code></strong></summary>

**Deskripsi**: Unit organisasi dengan data lokasi geografis (latitude, longitude, radius) yang memungkinkan analitik berbasis geofence untuk pelaporan tingkat departemen dan asosiasi lokasi karyawan

<table><thead><tr><th width="156">Atribut</th><th>Detail</th></tr></thead><tbody><tr><td><strong>Bidang kunci</strong></td><td>- <code>department_id</code> - Pengidentifikasi entitas departemen<br>- <code>user_id</code> - Pengidentifikasi entitas pengguna<br>- <code>department_label</code> - Atribut department_label pada tabel departments<br>- <code>latitude</code> - Lokasi yang terkait dengan departemen ini<br>- <code>longitude</code> - Lokasi yang terkait dengan departemen ini<br>- <code>radius</code> - Ukuran geolokasi dalam meter<br>- <code>address</code> - Atribut address pada tabel departments</td></tr><tr><td><strong>Relasi</strong></td><td>Menghubungkan karyawan ke struktur organisasi melalui <code>department_id</code></td></tr><tr><td><strong>Catatan khusus</strong></td><td>Bidang lokasi mendukung analitik berbasis geofence untuk pelaporan tingkat departemen</td></tr></tbody></table>

</details>

Pelacakan dan pemantauan

<details>

<summary><strong><code>devices</code></strong></summary>

**Deskripsi**: Registri perangkat pelacak fisik dengan pengidentifikasi perangkat keras (IMEI), informasi kartu SIM, status konektivitas jaringan (kekuatan sinyal, roaming, operator), dan penetapan daftar status untuk manajemen siklus hidup perangkat

<table><thead><tr><th width="138">Atribut</th><th>Detail</th></tr></thead><tbody><tr><td><strong>Bidang kunci</strong></td><td>- <code>device_id</code> - ID perangkat<br>- <code>owner_id</code> - ID pemilik perangkat di akun mana beacon ditambahkan<br>- <code>device_imei</code> - IMEI perangkat<br>- <code>phone</code> - Nomor kartu SIM perangkat<br>- <code>status_listing_id</code> - ID status perangkat<br>- <code>network_label</code> - Nama jaringan tempat kartu SIM terhubung<br>- <code>signal_level</code> - Kekuatan sinyal perangkat<br>- <code>has_roaming</code> - Penanda ketersediaan roaming<br>- <code>is_sim_blocked</code> - Penanda penguncian kartu SIM<br>- <code>created_at</code> - Tanggal dan waktu entri dibuat</td></tr><tr><td><strong>Relasi</strong></td><td>Entitas inti yang terhubung ke <code>objects</code>, <code>models</code>, <code>sensor_description</code>, <code>counters</code>; <code>owner_id</code> referensi <code>users.user_id</code></td></tr><tr><td><strong>Catatan khusus</strong></td><td>Semua data telematik dalam <code>raw_telematics_data</code> schema mereferensikan tabel ini melalui <code>device_id</code></td></tr></tbody></table>

</details>

<details>

<summary><strong><code>objects</code></strong></summary>

**Deskripsi**: Registri pusat entitas yang dipantau (kendaraan, aset, personel) yang menghubungkan perangkat fisik ke struktur organisasi melalui client\_id dan group\_id, mewakili "unit yang dapat dilacak" dengan satu objek aktif per perangkat

<table><thead><tr><th width="148">Atribut</th><th>Detail</th></tr></thead><tbody><tr><td><strong>Bidang kunci</strong></td><td>- <code>object_id</code> - Pengidentifikasi objek entitas<br>- <code>client_id</code> - Pengidentifikasi entitas klien<br>- <code>device_id</code> - Pengidentifikasi entitas perangkat<br>- <code>object_label</code> - Nama objek<br>- <code>model</code> - Model perangkat<br>- <code>group_id</code> - Grup ID entitas<br>- <code>create_datetime</code> - Tanggal dan waktu pembuatan baris baru di server<br>- <code>is_deleted</code> - Atribut is_deleted pada tabel objects<br>- <code>is_clone</code> - Tanda klon</td></tr><tr><td><strong>Relasi</strong></td><td>Hub pusat yang menghubungkan perangkat ke pengguna (<code>client_id</code>), detail kendaraan, riwayat pelacakan, tugas, dan aturan</td></tr><tr><td><strong>Catatan khusus</strong></td><td>Mewakili "unit yang dapat dilacak" dalam sistem; satu objek per perangkat yang sedang aktif digunakan</td></tr></tbody></table>

</details>

<details>

<summary><strong><code>models</code></strong></summary>

**Deskripsi**: Registri pusat entitas yang dipantau (kendaraan, aset, personel) yang menghubungkan perangkat fisik ke struktur organisasi melalui client\_id dan group\_id, mewakili "unit yang dapat dilacak" dengan satu objek aktif per perangkat

<table><thead><tr><th width="135">Atribut</th><th>Detail</th></tr></thead><tbody><tr><td><strong>Bidang kunci</strong></td><td>- <code>model_id</code> - Pengidentifikasi model entitas<br>- <code>model</code> - Atribut model pada tabel models<br>- <code>vendor</code> - Nama perusahaan yang merilis tracker<br>- <code>alternative_label</code> - Atribut alternative_label pada tabel models<br>- <code>analog_amount</code> - Jumlah input analog pada tracker<br>- <code>digital_amount</code> - Jumlah input diskret pada tracker<br>- <code>outputs_amount</code> - Jumlah output diskret tracker<br>- <code>has_battery_level</code> - Menentukan apakah tracker mengirimkan pembacaan daya baterai<br>- <code>has_altitude</code> - Menentukan apakah tracker mengirimkan ketinggian<br>- <code>has_phone</code> - Apakah ada kartu SIM?<br>- <code>has_gsm_level</code> - Dapatkah tracker mengirimkan kekuatan sinyal GSM?<br>- <code>has_gsm_name</code> - Dapatkah tracker mengirimkan nama jaringan GSM atau kode operator (MCC + MNC)?<br>- <code>has_gsm_roaming</code> - Dapatkah tracker mengirimkan status roaming?<br>- <code>has_detach_button</code> - Apakah tracker memiliki sensor pelepasan?<br>- <code>type_output_control</code> - Profil Kontrol Output Tracker<br>- <code>type_special_control</code> - Berisi pengaturan khusus dan modul fungsional untuk model perangkat individual, seperti mode mengemudi berbahaya (hbm_telfm) untuk peralatan Teltonika<br>- <code>is_clone</code> - Apakah model ini merupakan klon dari model lain?</td></tr><tr><td><strong>Konten</strong></td><td>Penanda kemampuan Boolean menunjukkan bidang data mana yang tersedia dari jenis perangkat ini</td></tr><tr><td><strong>Catatan khusus</strong></td><td>Gunakan penanda kemampuan untuk menentukan sensor dan input yang valid saat melakukan kueri data telematik</td></tr></tbody></table>

</details>

<details>

<summary><strong><code>sensor_description</code></strong></summary>

**Deskripsi**: Konfigurasi sensor komprehensif yang menghubungkan input perangkat ke logika bisnis, termasuk pemetaan input, satuan pengukuran, faktor konversi (multiplier/divider), tabel kalibrasi untuk sensor bahan bakar, ambang akurasi, dan logika pengelompokan untuk pembacaan sensor teragregasi

<table><thead><tr><th width="142">Atribut</th><th>Detail</th></tr></thead><tbody><tr><td><strong>Bidang kunci</strong></td><td>- <code>sensor_id</code> - Pengidentifikasi entitas sensor<br>- <code>device_id</code> - Pengidentifikasi entitas perangkat<br>- <code>sensor_label</code> - Nama sensor untuk UI<br>- <code>input_label</code> - Nama bidang pesan (atribut) dari mana data sensor diambil. Jika sama dengan "input_status", maka itu adalah sensor diskret<br>- <code>sensor_type</code> - Jenis sensor<br>- <code>units_type</code> - Satuan pengukuran<br>- <code>multiplier</code> - Pengali - angka yang digunakan untuk mengalikan nilai bidang. Hanya untuk sensor pengukuran<br>- <code>divider</code> - Pembagi - angka yang digunakan untuk membagi nilai bidang. Hanya untuk sensor pengukuran<br>- <code>accuracy</code> - Persentase tertentu untuk menghitung galat absolut volume tangki. Galat ini digunakan untuk menentukan kapan pengisian atau pengurasan terjadi. Ini hanya digunakan untuk sensor bahan bakar<br>- <code>calibration_data</code> - Atribut calibration_data pada tabel sensor_description<br>- <code>input_id</code> - Nomor input untuk sensor diskret<br>- <code>group_id</code> - Sensor dengan jenis yang sama yang memiliki group_id dan source_id yang sama dianggap berada dalam grup yang sama. Datanya dijumlahkan atau dirata-ratakan, tergantung pada nilai group_type. Ini diperlukan untuk sensor teragregasi. Ini digunakan pada sensor pengukuran<br>- <code>group_type</code> - 0 - jumlahkan nilai sensor dalam grup, 1 - rata-rata<br>- <code>sensor_units</code> - Nama satuan yang dimasukkan pengguna jika units_type=0 (kustom)<br>- <code>parameters</code> - Objek opsional dengan parameter tambahan parent_ids - array opsional parent_ids untuk sensor komposit. volume - double. Opsional. Volume untuk sensor komposit. parent_ids - opsional. Array int. Array parent_ids untuk sensor komposit. volume - opsional. Double. Volume untuk sensor komposit. min - opsional. Double. Nilai mentah minimum yang dapat diterima untuk sensor. max - opsional. Double. Nilai mentah maksimum yang dapat diterima untuk sensor. max_lowering_by_time - opsional. Double. Penurunan nilai legal maksimum per jam. max_lowering_by_mileage - opsional. Double. Penurunan nilai legal maksimum per 100 km. ignore_drains_in_move - opsional. Boolean. Default false. Jika true, pengurasan bahan bakar tidak akan terdeteksi selama pergerakan. ignore_refuels_in_move - opsional. Boolean. Default false. Jika true, pengisian bahan bakar tidak akan terdeteksi selama pergerakan. refuel_gap_minutes - opsional. Integer. Default 5. Waktu dalam menit setelah awal pergerakan, pengisian bahan bakar akan terdeteksi selama pergerakan. custom_field_name - opsional. Boolean. Default false. Parameter ini menentukan apakah bidang input_name adalah nilai kustom yang dimasukkan oleh pengguna. Ini hanya masuk akal jika model tracker memiliki fitur has_custom_fields</td></tr><tr><td><strong>Relasi</strong></td><td>Menghubungkan input perangkat (dari <code>raw_telematics_data.inputs</code>) ke logika bisnis melalui <code>device_id</code> dan <code>input_label</code> pencocokan</td></tr><tr><td><strong>Catatan khusus</strong></td><td><code>calibration_data</code> (JSONB) menyimpan tabel kalibrasi khusus sensor untuk sensor level bahan bakar; <code>multiplier</code> dan <code>divider</code> mengonversi nilai mentah ke satuan</td></tr></tbody></table>

</details>

Manajemen aset

<details>

<summary><strong><code>vehicles</code></strong></summary>

**Deskripsi**: Registri kendaraan komprehensif yang berisi spesifikasi (dimensi, berat, kapasitas), dokumen (VIN, registrasi, asuransi), parameter operasional (konsumsi bahan bakar, volume tangki), dan penugasan tracker saat ini melalui object\_id untuk manajemen armada dan pelacakan kepatuhan

<table><thead><tr><th width="144">Atribut</th><th>Detail</th></tr></thead><tbody><tr><td><strong>Bidang kunci</strong></td><td>- <code>vehicle_id</code> - Pengidentifikasi entitas kendaraan<br>- <code>user_id</code> - Pengidentifikasi entitas pengguna<br>- <code>object_id</code> - Pengidentifikasi objek entitas<br>- <code>garage_id</code> - Pengidentifikasi entitas garasi<br>- <code>vehicle_label</code> - Atribut vehicle_label pada tabel vehicles<br>- <code>registration_number</code> - Nomor registrasi/plat kendaraan<br>- <code>vin</code> - Atribut vin pada tabel vehicles<br>- <code>manufacture_year</code> - Atribut manufacture_year pada tabel vehicles<br>- <code>fuel_type</code> - Atribut fuel_type pada tabel vehicles<br>- <code>fuel_cost</code> - Atribut fuel_cost pada tabel vehicles<br>- <code>fuel_tank_volume</code> - Atribut fuel_tank_volume pada tabel vehicles<br>- <code>max_speed</code> - Atribut max_speed pada tabel vehicles<br>- <code>model</code> - Atribut model pada tabel vehicles<br>- <code>color</code> - Atribut color pada tabel vehicles<br>- <code>trailer</code> - Atribut trailer pada tabel vehicles<br>- <code>additional_info</code> - Atribut additional_info pada tabel vehicles<br>- <code>vehicle_type</code> - Atribut vehicle_type pada tabel vehicles<br>- <code>vehicle_subtype</code> - Atribut vehicle_subtype pada tabel vehicles<br>- <code>vehicle_status_id</code> - Pengidentifikasi entitas status kendaraan<br>- <code>chassis_number</code> - Atribut chassis_number pada tabel vehicles<br>- <code>frame_number</code> - Atribut frame_number pada tabel vehicles<br>- <code>trailer_reg_number</code> - Atribut trailer_reg_number pada tabel vehicles<br>- <code>payload_weight</code> - Atribut payload_weight pada tabel vehicles<br>- <code>payload_height</code> - Atribut payload_height pada tabel vehicles<br>- <code>payload_length</code> - Atribut payload_length pada tabel vehicles<br>- <code>payload_width</code> - Atribut payload_width pada tabel vehicles<br>- <code>passenger_capacity</code> - Jumlah maksimum penumpang<br>- <code>gross_weight</code> - Atribut gross_weight pada tabel vehicles<br>- <code>standard_fuel_consumption</code> - Konsumsi bahan bakar rata-rata normal dalam liter per 100 km<br>- <code>fuel_grade</code> - Atribut fuel_grade pada tabel vehicles<br>- <code>wheel_arrangement</code> - Atribut wheel_arrangement pada tabel vehicles<br>- <code>tyre_size</code> - Ukuran kendaraan: dimensi dan ukuran roda<br>- <code>tyres_number</code> - Jumlah roda<br>- <code>liability_insurance_policy_number</code> - Atribut liability_insurance_policy_number pada tabel vehicles<br>- <code>liability_insurance_valid_till</code> - Tanggal sampai asuransi tanggung gugat berlaku<br>- <code>free_insurance_policy_number</code> - Atribut free_insurance_policy_number pada tabel vehicles<br>- <code>free_insurance_valid_till_date</code> - Tanggal sampai asuransi gratis berlaku</td></tr><tr><td><strong>Relasi</strong></td><td>Terkait dengan <code>objects</code> (tracker saat ini), <code>garages</code> (lokasi layanan), <code>vehicle_service_tasks</code>; dilacak di <code>vehicle_trackers_history</code></td></tr><tr><td><strong>Catatan khusus</strong></td><td>Bidang dimensi fisik (<code>payload_length</code>, <code>payload_width</code>, <code>payload_height</code>, <code>gross_weight</code>) mendukung analitik perencanaan muatan; tanggal asuransi memungkinkan pelacakan kepatuhan</td></tr></tbody></table>

</details>

<details>

<summary><strong><code>garages</code></strong></summary>

**Deskripsi**: Lokasi fasilitas servis dan pemeliharaan dengan koordinat geografis (latitude, longitude, radius), informasi kontak untuk mekanik dan dispatcher, memungkinkan deteksi kunjungan servis berbasis geofence dan analisis kedekatan

<table><thead><tr><th width="135">Atribut</th><th>Detail</th></tr></thead><tbody><tr><td><strong>Bidang kunci</strong></td><td>- <code>garage_id</code> - Pengidentifikasi entitas garasi<br>- <code>user_id</code> - Pengidentifikasi entitas pengguna<br>- <code>latitude</code> - Objek lokasi<br>- <code>longitude</code> - Objek lokasi<br>- <code>radius</code> - Ukuran geolokasi dalam meter<br>- <code>address</code> - Objek lokasi<br>- <code>organization_label</code> - ID depo<br>- <code>mechanic_name</code> - Nama mekanik<br>- <code>dispatcher_name</code> - Nama dispatcher</td></tr><tr><td><strong>Relasi</strong></td><td>Direferensikan oleh <code>vehicles.garage_id</code> untuk penugasan lokasi layanan</td></tr><tr><td><strong>Catatan khusus</strong></td><td>Bidang lokasi memungkinkan deteksi kunjungan servis berbasis geofence dan analisis kedekatan</td></tr></tbody></table>

</details>

<details>

<summary><strong><code>vehicle_service_tasks</code></strong></summary>

**Deskripsi**: Pelacakan jadwal pemeliharaan dan riwayat servis dengan berbagai jenis pemicu (berdasarkan tanggal, berdasarkan jarak tempuh, berdasarkan jam mesin), interval tugas berulang, notifikasi multi-saluran (email, SMS, push), dan pembedaan antara kejadian pemeliharaan terencana (is\_repeat) dan tidak terencana

<table><thead><tr><th width="132">Atribut</th><th>Detail</th></tr></thead><tbody><tr><td><strong>Bidang kunci</strong></td><td>- <code>service_task_id</code> - Pengidentifikasi entitas tugas servis<br>- <code>vehicle_id</code> - Pengidentifikasi entitas kendaraan<br>- <code>description</code> - Atribut description pada tabel vehicle_service_tasks<br>- <code>status</code> - Nilai status dari atribut status<br>- <code>cost</code> - Atribut cost pada tabel vehicle_service_tasks<br>- <code>start_date</code> - Tanggal dan waktu yang terkait dengan atribut start_date<br>- <code>end_date</code> - Tanggal dan waktu yang terkait dengan atribut end_date<br>- <code>completion_date</code> - Tanggal dan waktu yang terkait dengan atribut completion_date<br>- <code>predicted_datetime</code> - Tanggal dan waktu yang terkait dengan atribut predicted_datetime<br>- <code>mileage_limit</code> - Atribut mileage_limit pada tabel vehicle_service_tasks<br>- <code>engine_hours_limit</code> - Atribut engine_hours_limit pada tabel vehicle_service_tasks<br>- <code>start_mileage</code> - Atribut start_mileage pada tabel vehicle_service_tasks<br>- <code>start_engine_hours</code> - Atribut start_engine_hours pada tabel vehicle_service_tasks<br>- <code>mileage_notification_interval</code> - Atribut mileage_notification_interval pada tabel vehicle_service_tasks<br>- <code>engine_hours_notification_interval</code> - Atribut engine_hours_notification_interval pada tabel vehicle_service_tasks<br>- <code>date_notification_interval</code> - Mengonversi bilangan bulat N menjadi N hari<br>- <code>mileage_repeat_interval</code> - Atribut mileage_repeat_interval pada tabel vehicle_service_tasks<br>- <code>engine_hours_repeat_interval</code> - Atribut engine_hours_repeat_interval pada tabel vehicle_service_tasks<br>- <code>date_repeat_interval</code> - Mengonversi bilangan bulat N menjadi N hari<br>- <code>notification_emails</code> - Atribut notification_emails pada tabel vehicle_service_tasks<br>- <code>notification_sms_phone_numbers</code> - Atribut notification_sms_phone_numbers pada tabel vehicle_service_tasks<br>- <code>is_notification_push_enabled</code> - Atribut is_notification_push_enabled pada tabel vehicle_service_tasks<br>- <code>completion_mileage</code> - Atribut completion_mileage pada tabel vehicle_service_tasks<br>- <code>completion_engine_hours</code> - Atribut completion_engine_hours pada tabel vehicle_service_tasks<br>- <code>is_repeat</code> - Atribut is_repeat pada tabel vehicle_service_tasks<br>- <code>is_unplanned</code> - Atribut is_unplanned pada tabel vehicle_service_tasks<br>- <code>comment</code> - Atribut comment pada tabel vehicle_service_tasks</td></tr><tr><td><strong>Konten</strong></td><td>Mendukung tiga jenis pemicu: berbasis tanggal, berbasis jarak tempuh, berbasis jam mesin; pengaturan notifikasi untuk email, SMS, push</td></tr><tr><td><strong>Catatan khusus</strong></td><td><code>is_repeat</code> dan bidang interval memungkinkan jadwal pemeliharaan berulang; <code>is_unplanned</code> membedakan pemeliharaan terjadwal vs. reaktif</td></tr></tbody></table>

</details>

Lokasi dan perutean

<details>

<summary><strong><code>zones</code></strong></summary>

**Deskripsi**: Area yang diberi geofence yang mendefinisikan perimeter virtual menggunakan lingkaran atau poligon untuk memantau kejadian masuk dan keluar kendaraan/aset, mendukung otomatisasi berbasis aturan dan analitik lokasi dengan pengkodean warna untuk diferensiasi visual

<table><thead><tr><th width="150">Atribut</th><th>Detail</th></tr></thead><tbody><tr><td><strong>Bidang kunci</strong></td><td>- <code>zone_id</code> - Pengidentifikasi entitas zona<br>- <code>client_id</code> - Pengidentifikasi entitas klien<br>- <code>zone_label</code> - Atribut zone_label pada tabel zones<br>- <code>zone_type</code> - Atribut zone_type pada tabel zones<br>- <code>latitude</code> - Objek opsional, kotak pembatas yang dapat sepenuhnya memuat hasil yang dikembalikan<br>- <code>longitude</code> - Objek opsional, kotak pembatas yang dapat sepenuhnya memuat hasil yang dikembalikan<br>- <code>circle_center_latitude</code> - Atribut circle_center_latitude pada tabel zones<br>- <code>circle_center_longitude</code> - Atribut circle_center_longitude pada tabel zones<br>- <code>radius</code> - Ukuran geolokasi dalam meter<br>- <code>address</code> - Atribut address pada tabel zones<br>- <code>color</code> - Atribut color pada tabel zones</td></tr><tr><td><strong>Konten</strong></td><td>Jenis zona meliputi circle, polygon (ditentukan melalui <code>geofence_points</code>), dan klasifikasi area khusus</td></tr><tr><td><strong>Relasi</strong></td><td>Direferensikan oleh <code>rules2zones</code>, <code>users2zones</code>; titik sudut poligon disimpan dalam <code>geofence_points</code></td></tr><tr><td><strong>Catatan khusus</strong></td><td>Fungsi PostGIS dapat digunakan untuk memeriksa point-in-polygon untuk analisis geofence yang kompleks</td></tr></tbody></table>

</details>

<details>

<summary><strong><code>places</code></strong></summary>

**Deskripsi**: Titik minat dengan koordinat geografis, definisi radius, dan dukungan field kustom yang dapat diperluas untuk menyimpan informasi kontak pelanggan dan data khusus bisnis, memungkinkan integrasi CRM/ERP melalui external\_id dan pelaporan berbasis lokasi

<table><thead><tr><th width="129">Atribut</th><th>Detail</th></tr></thead><tbody><tr><td><strong>Bidang kunci</strong></td><td>- <code>place_id</code> - Tempatkan pengenal entitas<br>- <code>user_id</code> - Pengidentifikasi entitas pengguna<br>- <code>place_label</code> - Atribut place_label dari tabel places<br>- <code>latitude</code> - Objek lokasi<br>- <code>longitude</code> - Objek lokasi<br>- <code>radius</code> - Ukuran geolokasi dalam meter<br>- <code>address</code> - Atribut address dari tabel places<br>- <code>description</code> - Atribut description dari tabel places<br>- <code>external_id</code> - ID untuk integrasi dengan sistem eksternal (CRM)<br>- <code>custom_fields</code> - Bidang tambahan<br>- <code>assigned_datetime</code> - Tanggal dan waktu penugasan titik minat kepada pengguna</td></tr><tr><td><strong>Relasi</strong></td><td>Diperluas dengan nilai field kustom melalui <code>places_text_fields</code>, <code>places_decimal_fields</code>, <code>places_bigint_fields</code>, <code>places_longtext_fields</code>, <code>places_linked_entity_fields</code></td></tr><tr><td><strong>Catatan khusus</strong></td><td><code>custom_fields</code> JSONB menyediakan akses cepat; tabel terkait memungkinkan pemfilteran dan pengurutan berdasarkan atribut kustom</td></tr></tbody></table>

</details>

<details>

<summary><strong><code>geofence_points</code></strong></summary>

**Deskripsi**: Koordinat simpul berurutan (field number menentukan urutan) yang mendefinisikan batas poligon untuk bentuk geofence kompleks, memungkinkan perimeter geografis yang presisi melampaui zona lingkaran sederhana, digunakan dengan PostGIS ST\_MakePolygon untuk operasi geometris

<table><thead><tr><th width="133">Atribut</th><th>Detail</th></tr></thead><tbody><tr><td><strong>Bidang kunci</strong></td><td>- <code>zone_id</code> - ID zona tempat formulir ini dilampirkan<br>- <code>number</code> - Nomor seri<br>- <code>latitude</code> - Lokasi<br>- <code>longitude</code> - Lokasi</td></tr><tr><td><strong>Relasi</strong></td><td>Beberapa catatan per <code>zone_id</code> menentukan batas poligon; <code>number</code> field menentukan urutan simpul</td></tr><tr><td><strong>Catatan khusus</strong></td><td>Kueri dengan <code>ORDER BY number</code> untuk merekonstruksi jalur poligon; gunakan dengan PostGIS ST_MakePolygon untuk operasi geometris</td></tr></tbody></table>

</details>

Manajemen tugas dan alur kerja

<details>

<summary><strong><code>tasks</code></strong></summary>

**Deskripsi**: Penugasan work order dengan validasi lokasi (latitude, longitude, radius), jendela waktu (time\_from, time\_to), persyaratan durasi kunjungan (stay\_duration\_minutes, arrival\_duration\_minutes), struktur hierarkis melalui parent\_task\_id, dan pelacakan status untuk manajemen layanan lapangan dan operasi pengiriman

<table><thead><tr><th width="130">Atribut</th><th>Detail</th></tr></thead><tbody><tr><td><strong>Bidang kunci</strong></td><td>- <code>task_id</code> - Pengenal entitas tugas<br>- <code>user_id</code> - Pengidentifikasi entitas pengguna<br>- <code>object_id</code> - Pengidentifikasi objek entitas<br>- <code>parent_task_id</code> - Pengenal entitas tugas induk<br>- <code>task_label</code> - Atribut task_label dari tabel tasks<br>- <code>status</code> - Nilai status dari atribut status<br>- <code>task_type</code> - Jenis tugas, task, route, atau checkpoint<br>- <code>latitude</code> - Atribut latitude dari tabel tasks<br>- <code>longitude</code> - Atribut longitude dari tabel tasks<br>- <code>radius</code> - Ukuran geolokasi dalam meter<br>- <code>arrival_datetime</code> - Waktu ketika pelacak tiba di area tugas. DIABAIKAN saat membuat/memperbarui<br>- <code>created_at</code> - Atribut created_at dari tabel tasks<br>- <code>status_change_datetime</code> - Tanggal dan waktu pembaruan tugas<br>- <code>time_from</code> - Tanggal dan waktu yang terkait dengan atribut time_from<br>- <code>time_to</code> - Tanggal dan waktu yang terkait dengan atribut time_to<br>- <code>stay_duration</code> - Atribut stay_duration dari tabel tasks<br>- <code>stay_duration_minutes</code> - Durasi kunjungan. Waktu yang harus dihabiskan pekerja lapangan di lokasi penugasan untuk menyelesaikan tugas dengan berhasil. Beberapa kunjungan bersifat kumulatif<br>- <code>arrival_duration_minutes</code> - Abaikan kunjungan acak yang lebih singkat daripada durasi yang ditentukan. Saat menghitung durasi minimum, kunjungan yang lebih singkat daripada durasi yang ditentukan akan diabaikan<br>- <code>max_delay_minuts</code> - Keterlambatan yang dapat diterima. Jumlah maksimum waktu karyawan boleh terlambat. Setiap tugas yang diselesaikan selama waktu ini akan ditandai sebagai "terlambat"<br>- <code>is_stay_control_enabled</code> - Atribut is_stay_control_enabled dari tabel tasks<br>- <code>address</code> - Atribut address dari tabel tasks<br>- <code>description</code> - Atribut description dari tabel tasks<br>- <code>custom_fields</code> - Atribut custom_fields dari tabel tasks<br>- <code>external_id</code> - Pengenal entitas eksternal<br>- <code>order_sort</code> - Atribut order_sort dari tabel tasks<br>- <code>created_by</code> - Sumber tugas yang dibuat</td></tr><tr><td><strong>Konten</strong></td><td>Mendukung tugas hierarkis melalui <code>parent_task_id</code>; jendela waktu ditentukan oleh <code>time_from</code>/<code>time_to</code>; validasi geofence dengan lokasi dan radius</td></tr><tr><td><strong>Relasi</strong></td><td>Terkait dengan <code>forms</code> (pengumpulan data), <code>task_history</code> (perubahan status), <code>objects</code> (pelacak yang ditugaskan)</td></tr><tr><td><strong>Catatan khusus</strong></td><td><code>stay_duration</code> dan <code>arrival_duration_minutes</code> memungkinkan pemantauan kepatuhan untuk tugas pengiriman dan layanan</td></tr></tbody></table>

</details>

<details>

<summary><strong><code>forms</code></strong></summary>

**Deskripsi**: Formulir pengumpulan data yang dapat dikonfigurasi untuk menangkap informasi terstruktur selama penyelesaian tugas atau check-in aplikasi seluler, dengan field dan nilai disimpan sebagai JSON, validasi lokasi opsional (is\_submission\_in\_zone), dan persyaratan pengiriman wajib saat dilampirkan ke tugas

<table><thead><tr><th width="141">Atribut</th><th>Detail</th></tr></thead><tbody><tr><td><strong>Bidang kunci</strong></td><td>- <code>form_id</code> - Pengenal entitas formulir<br>- <code>task_id</code> - ID tugas tempat formulir ini dilampirkan<br>- <code>object_id</code> - Pengidentifikasi objek entitas<br>- <code>form_label</code> - Label formulir yang ditentukan pengguna<br>- <code>bidang</code> - Jika bernilai true, formulir hanya dapat dikirim di zona tugas<br>- <code>values</code> - Peta dengan ID field sebagai kunci dan objek field_value sebagai nilai. Kunci digunakan untuk menautkan field dan nilai yang sesuai<br>- <code>submitted_at</code> - Tanggal saat nilai formulir terakhir dikirim<br>- <code>submission_latitude</code> - Lokasi tempat nilai formulir terakhir dikirim<br>- <code>submission_longitude</code> - Lokasi tempat nilai formulir terakhir dikirim<br>- <code>submission_address</code> - Lokasi tempat nilai formulir terakhir dikirim<br>- <code>is_submission_in_zone</code> - Jika bernilai true, formulir hanya dapat dikirim di zona tugas<br>- <code>description</code> - Tanggal saat formulir ini dibuat (atau dilampirkan ke tugas)<br>- <code>created_at</code> - Tanggal saat formulir ini dibuat (atau dilampirkan ke tugas)</td></tr><tr><td><strong>Konten</strong></td><td><code>bidang</code> menentukan struktur formulir (JSON); <code>values</code> berisi data yang dikirim (JSON)</td></tr><tr><td><strong>Relasi</strong></td><td>Terkait dengan <code>tasks</code> (work order terkait), <code>objects</code> (pengirim), dirujuk dalam <code>checkins</code></td></tr><tr><td><strong>Catatan khusus</strong></td><td>Flag validasi lokasi <code>is_submission_in_zone</code> memungkinkan aturan pengiriman formulir berbasis geofence</td></tr></tbody></table>

</details>

<details>

<summary><strong><code>checkins</code></strong></summary>

**Deskripsi**: Catatan kehadiran dan aktivitas berbasis lokasi yang dikirim melalui aplikasi seluler, melacak waktu kedatangan yang direncanakan versus waktu kedatangan aktual (planned\_datetime vs actual\_datetime) dengan koordinat geografis dan pengukuran akurasi lokasi (radius) untuk pelaporan ketepatan waktu

<table><thead><tr><th width="129">Atribut</th><th>Detail</th></tr></thead><tbody><tr><td><strong>Bidang kunci</strong></td><td>- <code>checkin_id</code> - Pengenal entitas checkin<br>- <code>employee_id</code> - Pengenal entitas karyawan juga merupakan pengenal untuk pengemudi<br>- <code>object_id</code> - Perangkat karyawan<br>- <code>form_id</code> - Pengenal entitas formulir<br>- <code>user_id</code> - Pengguna karyawan<br>- <code>planned_datetime</code> - Waktu perangkat saat check-in dilakukan<br>- <code>actual_datetime</code> - Waktu server saat permintaan/pesan diproses<br>- <code>latitude</code> - Lokasi tempat check-in dikirim<br>- <code>longitude</code> - Lokasi tempat check-in dikirim<br>- <code>radius</code> - Kesalahan penentuan posisi pada suatu titik dalam meter<br>- <code>address</code> - Alamat check-in<br>- <code>comment</code> - Atribut comment dari tabel checkins</td></tr><tr><td><strong>Relasi</strong></td><td>Menghubungkan karyawan ke formulir dan lokasi; melacak penyimpangan dari jadwal yang direncanakan</td></tr><tr><td><strong>Catatan khusus</strong></td><td>Selisih waktu antara <code>planned_datetime</code> dan <code>actual_datetime</code> memungkinkan pelaporan ketepatan waktu; radius menentukan toleransi lokasi yang dapat diterima</td></tr></tbody></table>

</details>

<details>

<summary><strong><code>task_history</code></strong></summary>

**Deskripsi**: Jejak audit lengkap peristiwa siklus hidup tugas yang menangkap semua perubahan status, penugasan, pembaruan, dan modifikasi field dengan stempel waktu (event\_datetime), atribusi pengguna, dan jenis aktivitas (create, update, assign, status\_change) yang disimpan di field payload untuk kepatuhan dan analisis alur kerja

<table><thead><tr><th width="137">Atribut</th><th>Detail</th></tr></thead><tbody><tr><td><strong>Bidang kunci</strong></td><td>- <code>task_history_id</code> - Pengenal entitas riwayat tugas<br>- <code>task_id</code> - Pengenal entitas tugas<br>- <code>user_id</code> - Pengidentifikasi entitas pengguna<br>- <code>activity</code> - Operasi yang terjadi. Dapat berupa "create", "update", "assign" atau "status_change"<br>- <code>event_datetime</code> - Tanggal dan waktu kejadian<br>- <code>payload</code> - Bergantung pada operasi. Biasanya berisi field yang diubah selama operasi</td></tr><tr><td><strong>Konten</strong></td><td>Jenis aktivitas yang ditentukan dalam <code>description_parameters</code>; <code>payload</code> menyimpan detail khusus peristiwa (teks)</td></tr><tr><td><strong>Catatan khusus</strong></td><td>Penting untuk analisis penyelesaian tugas, pelaporan transisi status, dan pelacakan aktivitas pengguna</td></tr></tbody></table>

</details>

Aturan dan otomatisasi

<details>

<summary><strong><code>rules</code></strong></summary>

**Deskripsi**: Aturan deteksi peristiwa dengan kondisi pemicu yang dapat dikonfigurasi (pelanggaran kecepatan, pelanggaran geofence, ambang sensor, waktu idle) yang disimpan dalam parameter (JSONB), dan pengaturan notifikasi multi-saluran (alert\_email, alert\_sms, alert\_phone, is\_push\_enabled) untuk pemantauan dan peringatan otomatis berdasarkan data perangkat dan server

<table><thead><tr><th width="131">Atribut</th><th>Detail</th></tr></thead><tbody><tr><td><strong>Bidang kunci</strong></td><td>- <code>rule_id</code> - Pengenal entitas aturan<br>- <code>object_id</code> - Pengidentifikasi objek entitas<br>- <code>client_id</code> - Pengidentifikasi entitas klien<br>- <code>event_type</code> - Atribut event_type dari tabel rules<br>- <code>event_label</code> - Atribut event_label dari tabel rules<br>- <code>event_group</code> - Atribut event_group dari tabel rules<br>- <code>description</code> - Atribut description dari tabel rules<br>- <code>parameters</code> - Parameter peristiwa. Untuk detail lebih lanjut tentang parameter yang tersedia, lihat <a href="https://www.navixy.com/docs/navixy-api/user-api/backend-api/resources/tracking/tracker/rules/rule_types/">Navixy API docs</a>.<br>- <code>alert_email</code> - Email untuk notifikasi<br>- <code>alert_sms</code> - Nomor telepon untuk notifikasi SMS<br>- <code>alert_phone</code> - Telepon untuk panggilan suara<br>- <code>is_push_enabled</code> - Jika true, notifikasi push tersedia<br>- <code>created_at</code> - Atribut created_at dari tabel rules<br>- <code>is_deleted</code> - Atribut is_deleted dari tabel rules<br>- <code>maximum</code> - Batas yang diterapkan pada berbagai aturan. Misalnya, untuk aturan waktu idle dengan mesin menyala dalam menit<br>- <code>event_comment1</code> - Atribut event_comment1 dari tabel rules<br>- <code>event_comment2</code> - Atribut event_comment2 dari tabel rules</td></tr><tr><td><strong>Konten</strong></td><td>Parameter aturan (JSONB) menentukan kondisi pemicu; mendukung notifikasi email, SMS, telepon, dan push</td></tr><tr><td><strong>Relasi</strong></td><td>Tautan ke objek melalui <code>rules2objects</code>, zona melalui <code>rules2zones</code></td></tr><tr><td><strong>Catatan khusus</strong></td><td><code>event_type</code> menentukan skenario pemantauan spesifik (ngebut, pelanggaran geofence, ambang sensor); <code>maximum</code> field memungkinkan agregasi peristiwa untuk peringatan berbasis ambang</td></tr></tbody></table>

</details>

<details>

<summary><strong><code>rules2objects</code></strong></summary>

**Deskripsi**: Relasi banyak-ke-banyak yang menautkan aturan ke objek yang dipantau dengan penyesuaian parameter per objek melalui object\_params (JSONB), memungkinkan nilai ambang yang berbeda (misalnya, batas kecepatan) untuk setiap kendaraan atau aset dalam aturan yang sama

<table><thead><tr><th width="140">Atribut</th><th>Detail</th></tr></thead><tbody><tr><td><strong>Bidang kunci</strong></td><td>- <code>rule_id</code> - Pengenal entitas aturan<br>- <code>object_id</code> - Pengidentifikasi objek entitas<br>- <code>param_group_number</code> - Atribut param_group_number dari tabel rules2objects<br>- <code>object_params</code> - Atribut object_params dari tabel rules2objects</td></tr><tr><td><strong>Konten</strong></td><td><code>object_params</code> (JSONB) memungkinkan kustomisasi aturan per objek (misalnya, batas kecepatan yang berbeda per kendaraan)</td></tr><tr><td><strong>Catatan khusus</strong></td><td>Relasi banyak-ke-banyak memungkinkan satu aturan memantau beberapa objek dengan parameter yang berbeda</td></tr></tbody></table>

</details>

<details>

<summary><strong><code>rules2zones</code></strong></summary>

**Deskripsi**: Relasi banyak-ke-banyak yang menghubungkan aturan dengan zona geofence, memungkinkan satu aturan memantau peristiwa masuk/keluar di beberapa area geografis untuk skenario pemantauan spasial yang kompleks

<table><thead><tr><th width="144">Atribut</th><th>Detail</th></tr></thead><tbody><tr><td><strong>Bidang kunci</strong></td><td>- <code>rule_id</code> - Pengenal entitas aturan<br>- <code>zone_id</code> - Pengenal entitas zona</td></tr><tr><td><strong>Catatan khusus</strong></td><td>Relasi banyak-ke-banyak memungkinkan pemantauan multi-zona untuk satu aturan (misalnya, peringatan saat memasuki salah satu dari beberapa area terlarang)</td></tr></tbody></table>

</details>

Status dan kategorisasi

<details>

<summary><strong><code>statuses</code></strong></summary>

**Deskripsi**: Definisi status kustom dalam daftar status, termasuk properti tampilan (color untuk tampilan website, order\_sort untuk penempatan) yang digunakan untuk merepresentasikan status kerja perangkat atau karyawan dengan dukungan soft delete melalui flag is\_deleted

<table><thead><tr><th width="128">Atribut</th><th>Detail</th></tr></thead><tbody><tr><td><strong>Bidang kunci</strong></td><td>- <code>status_id</code> - Pengenal entitas status<br>- <code>listing_id</code> - Pengenal entitas listing<br>- <code>status_label</code> - Nilai status dari atribut status_label<br>- <code>color</code> - Warna yang digunakan untuk ditampilkan di situs web<br>- <code>order_sort</code> - Posisi urut dalam status listing<br>- <code>is_deleted</code> - Atribut is_deleted dari tabel statuses</td></tr><tr><td><strong>Relasi</strong></td><td>Kelompok status yang diatur berdasarkan <code>listing_id</code> (mereferensikan <code>status_listings</code>); digunakan dalam <code>status_history</code></td></tr><tr><td><strong>Catatan khusus</strong></td><td><code>order_sort</code> menentukan urutan tampilan; warna memungkinkan perbedaan visual dalam pelaporan</td></tr></tbody></table>

</details>

<details>

<summary><strong><code>status_listings</code></strong></summary>

**Deskripsi**: Definisi set status yang mengontrol nilai status mana yang tersedia untuk perangkat atau karyawan, dengan flag izin (is\_supervisor\_controlled, is\_employee\_controlled) yang menentukan apakah supervisor, karyawan, atau keduanya dapat mengubah nilai status

<table><thead><tr><th width="144">Atribut</th><th>Detail</th></tr></thead><tbody><tr><td><strong>Bidang kunci</strong></td><td>- <code>status_listing_id</code> - Pengenal entitas listing status<br>- <code>user_id</code> - Pengidentifikasi entitas pengguna<br>- <code>status_listing_label</code> - Nilai status dari atribut status_listing_label<br>- <code>is_supervisor_controlled</code> - Jika true, supervisor dapat mengubah status kerja, mis. menggunakan aplikasi pemantauan seluler<br>- <code>is_employee_controlled</code> - Jika true, karyawan dapat mengubah status kerja mereka sendiri, mis. menggunakan aplikasi pelacakan seluler<br>- <code>is_deleted</code> - Atribut is_deleted dari tabel status_listings</td></tr><tr><td><strong>Relasi</strong></td><td>Direferensikan oleh <code>devices.status_listing_id</code> dan <code>statuses.listing_id</code></td></tr><tr><td><strong>Catatan khusus</strong></td><td>Flag kontrol menentukan siapa yang dapat mengubah status: hanya supervisor, layanan mandiri karyawan, atau keduanya</td></tr></tbody></table>

</details>

<details>

<summary><strong><code>status_history</code></strong></summary>

**Deskripsi**: Jejak audit semua transisi status perangkat dengan stempel waktu (changed\_datetime pada perangkat, server\_datetime pada server), atribusi pengguna (updated\_by), dan penangkapan lokasi (latitude, longitude, address) yang memungkinkan analisis geografis perubahan status dan pelaporan lokasi awal/akhir hari kerja

<table><thead><tr><th width="143">Atribut</th><th>Detail</th></tr></thead><tbody><tr><td><strong>Bidang kunci</strong></td><td>- <code>status_history_id</code> - Pengenal entitas riwayat status<br>- <code>device_id</code> - Pengidentifikasi entitas perangkat<br>- <code>old_status_id</code> - Pengenal entitas status lama<br>- <code>new_status_id</code> - Pengenal entitas status baru<br>- <code>updated_by</code> - Tanggal dan waktu yang terkait dengan atribut updated_by<br>- <code>changed_datetime</code> - Tanggal dan waktu penetapan status baru pada perangkat<br>- <code>server_datetime</code> - Tanggal dan waktu penetapan status baru pada server<br>- <code>latitude</code> - Melokalkan perangkat selama perubahan status<br>- <code>longitude</code> - Melokalkan perangkat selama perubahan status<br>- <code>address</code> - Melokalkan perangkat selama perubahan status</td></tr><tr><td><strong>Relasi</strong></td><td>Terkait dengan <code>devices</code>, <code>statuses</code> (lama dan baru), <code>description_parameters</code> (untuk <code>updated_by</code> peran)</td></tr><tr><td><strong>Catatan khusus</strong></td><td>Penangkapan lokasi memungkinkan analisis geografis transisi status; berguna untuk pelaporan lokasi awal/akhir hari kerja</td></tr></tbody></table>

</details>

<details>

<summary><strong><code>tags</code></strong></summary>

**Deskripsi**: Label kategorisasi yang ditentukan pengguna dengan kode warna yang memungkinkan pemfilteran dan pencarian cepat di berbagai jenis entitas (tempat, geofence, karyawan, tugas, pelacak, kendaraan) untuk pengorganisasian yang fleksibel

<table><thead><tr><th width="149">Atribut</th><th>Detail</th></tr></thead><tbody><tr><td><strong>Bidang kunci</strong></td><td>- <code>tag_id</code> - ID entitas tag<br>- <code>user_id</code> - Pengidentifikasi entitas pengguna<br>- <code>tag_label</code> - Atribut tag_label dari tabel tags<br>- <code>color</code> - Atribut color dari tabel tags</td></tr><tr><td><strong>Relasi</strong></td><td>Diterapkan pada entitas melalui <code>tag_links</code>; cakupan ditentukan oleh pengguna</td></tr><tr><td><strong>Catatan khusus</strong></td><td>Sistem kategorisasi fleksibel yang mendukung beberapa tag per entitas</td></tr></tbody></table>

</details>

<details>

<summary><strong><code>tag_links</code></strong></summary>

**Deskripsi**: Tabel relasi polimorfik yang menghubungkan tag dengan jenis entitas apa pun melalui entity\_type dan entity\_id, dengan field ordinal untuk pengelolaan urutan tampilan, memungkinkan penandaan multi-entitas yang fleksibel

<table><thead><tr><th width="127">Atribut</th><th>Detail</th></tr></thead><tbody><tr><td><strong>Bidang kunci</strong></td><td>- <code>tag_id</code> - ID entitas tag<br>- <code>entity_type</code> - Atribut entity_type dari tabel tag_links<br>- <code>entity_id</code> - Pengenal entitas<br>- <code>ordinal</code> - Atribut ordinal dari tabel tag_links</td></tr><tr><td><strong>Konten</strong></td><td><code>entity_type</code> mengidentifikasi tabel (vehicle, employee, task, dll.); <code>ordinal</code> menentukan urutan tampilan</td></tr><tr><td><strong>Catatan khusus</strong></td><td>Relasi polimorfik memungkinkan penandaan di berbagai jenis entitas</td></tr></tbody></table>

</details>

Kelompok dan hierarki

<details>

<summary><strong><code>groups</code></strong></summary>

**Deskripsi**: Struktur pengelompokan organisasi untuk pelacak yang memungkinkan organisasi visual di antarmuka pengguna dengan warna yang dapat disesuaikan (group\_color) dan pengelolaan hierarkis seperti folder, yang saat ini hanya berfungsi secara visual

<table><thead><tr><th width="148">Atribut</th><th>Detail</th></tr></thead><tbody><tr><td><strong>Bidang kunci</strong></td><td>- <code>group_id</code> - Grup pelacak (ditautkan oleh objects.group_id). Pembagian ke dalam grup dapat dilihat dalam daftar beacon, misalnya<br>- <code>client_id</code> - Pengidentifikasi entitas klien<br>- <code>group_label</code> - Judul grup yang ditentukan pengguna, 1 hingga 60 karakter yang dapat dicetak, mis. "Employees"<br>- <code>group_color</code> - Warna grup dalam format web (tanpa #), mis. "FF6DDC". Menentukan warna penanda pelacak pada peta</td></tr><tr><td><strong>Relasi</strong></td><td>Direferensikan oleh <code>objects.group_id</code>; kepemilikan klien melalui <code>client_id</code> (mereferensikan <code>users</code>)</td></tr><tr><td><strong>Catatan khusus</strong></td><td>Memungkinkan organisasi entitas pemantauan seperti folder untuk pelaporan dan izin</td></tr></tbody></table>

</details>

<details>

<summary><strong><code>groups_objects</code></strong></summary>

**Deskripsi**: Relasi banyak-ke-banyak antara grup dan objek menggunakan kunci primer komposit (groups\_client\_id, objects\_client\_id), memungkinkan objek berada dalam beberapa grup secara bersamaan untuk struktur organisasi yang fleksibel

<table><thead><tr><th width="135">Atribut</th><th>Detail</th></tr></thead><tbody><tr><td><strong>Bidang kunci</strong></td><td>- <code>groups_client_id</code> - Pengenal entitas klien untuk grup<br>- <code>objects_client_id</code> - Pengenal entitas klien untuk objek</td></tr><tr><td><strong>Catatan khusus</strong></td><td>Memungkinkan objek berada dalam beberapa grup secara bersamaan; kueri dengan keduanya <code>client_id</code> nilai untuk keanggotaan grup</td></tr></tbody></table>

</details>

Field kustom dan entitas

<details>

<summary><strong><code>entities</code></strong></summary>

**Deskripsi**: Registri jenis entitas yang mendefinisikan entitas bisnis mana yang mendukung field kustom dan struktur tata letak field-nya (sections, field\_order) yang disimpan dalam entity\_label (JSONB), memungkinkan perluasan skema dinamis di seluruh tempat, tugas, dan entitas lain tanpa perubahan basis data

<table><thead><tr><th width="141">Atribut</th><th>Detail</th></tr></thead><tbody><tr><td><strong>Bidang kunci</strong></td><td>- <code>entity_id</code> - Pengenal entitas<br>- <code>user_id</code> - Pengidentifikasi entitas pengguna<br>- <code>entity_label</code> - id - int. Pengenal entitas. type - enum. Saat ini, hanya "place" yang didukung. layout - object yang menjelaskan tata letak field untuk entitas. sections - array object. Setiap bagian dapat berisi satu atau lebih field. Setidaknya satu bagian harus ada dalam sebuah tata letak. label - string. Nama bagian. field_order - array string. Field bawaan dan ID field kustom (sebagai string)<br>- <code>builtin_type</code> - Atribut builtin_type dari tabel entities</td></tr><tr><td><strong>Relasi</strong></td><td>Direferensikan oleh <code>custom_fields</code> untuk menentukan field kustom mana yang berlaku untuk jenis entitas mana</td></tr><tr><td><strong>Catatan khusus</strong></td><td><code>builtin_type</code> menaut ke <code>description_parameters</code> untuk klasifikasi entitas yang ditentukan sistem</td></tr></tbody></table>

</details>

<details>

<summary><strong><code>custom_fields</code></strong></summary>

**Deskripsi**: Definisi field kustom yang memungkinkan perluasan skema dinamis untuk jenis entitas, dengan tipe field yang dapat dikonfigurasi (custom\_field\_type), aturan validasi dan opsi dalam parameters (JSONB), serta flag kewajiban (is\_required) untuk penangkapan data yang fleksibel di seluruh tempat, tugas, dan entitas lain

<table><thead><tr><th width="146">Atribut</th><th>Detail</th></tr></thead><tbody><tr><td><strong>Bidang kunci</strong></td><td>- <code>custom_field_id</code> - Pengenal entitas field kustom<br>- <code>entity_id</code> - Pengenal entitas<br>- <code>custom_field_label</code> - Nama field<br>- <code>custom_field_type</code> - Tipe data pada field<br>- <code>description</code> - Deskripsi field<br>- <code>is_required</code> - Apakah ini wajib atau tidak?<br>- <code>parameters</code> - Parameter field</td></tr><tr><td><strong>Konten</strong></td><td><code>parameters</code> (JSONB) menyimpan konfigurasi khusus tipe field (aturan validasi, opsi dropdown, dll.)</td></tr><tr><td><strong>Relasi</strong></td><td>Menentukan atribut kustom yang tersedia untuk entitas; tipe field menaut ke <code>description_parameters</code></td></tr><tr><td><strong>Catatan khusus</strong></td><td>Memungkinkan perluasan skema dinamis tanpa perubahan basis data; digunakan secara luas dalam <code>places</code> dan <code>tasks</code></td></tr></tbody></table>

</details>

Pelacakan historis

<details>

<summary><strong><code>driver_history</code></strong></summary>

**Deskripsi**: Jejak audit lengkap penugasan karyawan ke kendaraan dari waktu ke waktu yang melacak transisi old\_employee\_id ke new\_employee\_id dengan stempel waktu (changed\_datetime, server\_datetime), data lokasi (latitude, longitude, address), informasi kunci perangkat keras, dan atribusi pengguna (updated\_by) yang memungkinkan analitik khusus pengemudi saat pengemudi berganti kendaraan

<table><thead><tr><th width="146">Atribut</th><th>Detail</th></tr></thead><tbody><tr><td><strong>Bidang kunci</strong></td><td>- <code>driver_history_id</code> - Pengenal entitas riwayat pengemudi<br>- <code>object_id</code> - Pengidentifikasi objek entitas<br>- <code>old_employee_id</code> - Pengenal entitas karyawan lama<br>- <code>new_employee_id</code> - Pengenal entitas karyawan baru<br>- <code>hardware_key</code> - Atribut hardware_key dari tabel driver_history<br>- <code>changed_datetime</code> - Tanggal dan waktu perubahan dilakukan pada perangkat<br>- <code>server_datetime</code> - Tanggal dan waktu perubahan dilakukan pada server<br>- <code>updated_by</code> - Tanggal dan waktu yang terkait dengan atribut updated_by<br>- <code>latitude</code> - Atribut latitude dari tabel driver_history<br>- <code>longitude</code> - Atribut longitude dari tabel driver_history<br>- <code>address</code> - Atribut address dari tabel driver_history</td></tr><tr><td><strong>Relasi</strong></td><td>Melacak penugasan pengemudi ke kendaraan dari waktu ke waktu; menaut ke <code>employees</code> dan <code>objects</code></td></tr><tr><td><strong>Catatan khusus</strong></td><td>Penting untuk pelaporan khusus pengemudi saat pengemudi berganti kendaraan; penangkapan lokasi memungkinkan analisis lokasi perubahan penugasan</td></tr></tbody></table>

</details>

<details>

<summary><strong><code>vehicle_trackers_history</code></strong></summary>

**Deskripsi**: Jejak audit yang melacak perangkat GPS mana (object\_id) yang dipasang di kendaraan mana (vehicle\_id) dari waktu ke waktu dengan stempel waktu perubahan (changed\_datetime), memungkinkan atribusi data historis dan perhitungan jarak tempuh yang akurat saat pelacak dipindahkan antar kendaraan

<table><thead><tr><th width="144">Atribut</th><th>Detail</th></tr></thead><tbody><tr><td><strong>Bidang kunci</strong></td><td>- <code>vehicle_tracker_history_id</code> - Pengenal entitas riwayat pelacak kendaraan<br>- <code>vehicle_id</code> - Pengidentifikasi entitas kendaraan<br>- <code>object_id</code> - Pengidentifikasi objek entitas<br>- <code>changed_datetime</code> - Tanggal dan waktu yang terkait dengan atribut changed_datetime</td></tr><tr><td><strong>Relasi</strong></td><td>Melacak perangkat GPS mana yang dipasang pada kendaraan mana dari waktu ke waktu</td></tr><tr><td><strong>Catatan khusus</strong></td><td>Kritis untuk analisis data historis saat pelacak dipindahkan antar kendaraan; memungkinkan atribusi jarak tempuh dan penggunaan yang akurat</td></tr></tbody></table>

</details>

Data referensi dan lookup

<details>

<summary><strong><code>description_parameters</code></strong></summary>

**Deskripsi**: Data referensi seluruh sistem yang menyediakan label yang dapat dibaca manusia (description) untuk nilai integer terenumerasi (key) yang digunakan di seluruh basis data, diatur berdasarkan field type (misalnya, task\_status, fuel\_type, counter\_type, entity\_classification) untuk konsistensi penerjemahan nilai dalam pelaporan dan tampilan UI

<table><thead><tr><th width="146">Atribut</th><th>Detail</th></tr></thead><tbody><tr><td><strong>Bidang kunci</strong></td><td>- <code>key</code> - Nilai yang mungkin dalam atribut<br>- <code>type</code> - Atribut komposit yang terdiri dari nama tabel diikuti garis bawah dan nama atribut dalam tabel<br>- <code>description</code> - Nilai tersirat dari suatu atribut</td></tr><tr><td><strong>Konten</strong></td><td>Menyediakan label yang mudah dibaca manusia untuk nilai berkode di seluruh basis data (status tugas, jenis bahan bakar, jenis penghitung, dll.)</td></tr><tr><td><strong>Relasi</strong></td><td>Dirujuk melalui kunci asing dari beberapa tabel untuk kategorisasi standar</td></tr><tr><td><strong>Catatan khusus</strong></td><td>Penting untuk menerjemahkan kode integer ke nilai yang mudah dibaca dalam pelaporan; <code>type</code> field groups related enumerations</td></tr></tbody></table>

</details>

<details>

<summary><strong><code>counters</code></strong></summary>

**Deskripsi**: Konfigurasi odometer dan penghitung jam mesin yang menautkan pembacaan sensor perangkat (sensor\_id) ke pengukuran jarak atau waktu dengan koefisien pengali untuk konversi satuan (km, miles, hours) dan counter\_type dari description\_parameters yang mendefinisikan jenis pengukuran

<table><thead><tr><th width="140">Atribut</th><th>Detail</th></tr></thead><tbody><tr><td><strong>Bidang kunci</strong></td><td>- <code>counter_id</code> - ID internal<br>- <code>device_id</code> - Pengidentifikasi entitas perangkat<br>- <code>counter_type</code> - Jenis penghitung<br>- <code>sensor_id</code> - Pengidentifikasi entitas sensor<br>- <code>multiplier</code> - Koefisien untuk mengonversi nilai ke salah satu metrik (km, l, dll.)</td></tr><tr><td><strong>Relasi</strong></td><td>Menautkan perangkat ke pembacaan sensor yang merepresentasikan penghitung jarak atau waktu</td></tr><tr><td><strong>Catatan khusus</strong></td><td><code>multiplier</code> mengonversi pulsa sensor ke satuan aktual (km, miles, hours); <code>counter_type</code> dari <code>description_parameters</code> menentukan jenis pengukuran</td></tr></tbody></table>

</details>

<details>

<summary><strong><code>device_output_name</code></strong></summary>

**Deskripsi**: Label kustom untuk saluran keluaran perangkat yang memetakan pengenal keluaran numerik (number) ke nama yang ditentukan pengguna (label) seperti "Door Lock" atau "Engine Block" untuk pelaporan dan analisis perintah serta status keluaran perangkat yang mudah dibaca

<table><thead><tr><th width="140">Atribut</th><th>Detail</th></tr></thead><tbody><tr><td><strong>Bidang kunci</strong></td><td>- <code>device_id</code> - Pengidentifikasi entitas perangkat<br>- <code>number</code> - Atribut number dari tabel device_output_name<br>- <code>label</code> - Atribut label dari tabel device_output_name</td></tr><tr><td><strong>Konten</strong></td><td>Memetakan nomor saluran keluaran ke nama yang ditentukan pengguna (misalnya, "Door Lock", "Engine Block")</td></tr><tr><td><strong>Catatan khusus</strong></td><td>Memungkinkan pelaporan yang mudah dibaca saat menganalisis perintah dan status keluaran perangkat</td></tr></tbody></table>

</details>

## `raw_telematics_data` struktur

The **`raw_telematics_data`** skema berisi tiga jenis tabel utama yang bekerja bersama untuk menyediakan data perangkat yang komprehensif.

<figure><img src="https://660637463-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoFNFEIINiGFbhi3Px3dE%2Fuploads%2FiTtEgzFgyJKTIl0ZCq7E%2Fv1%20schema%20telematics%20bd.svg?alt=media&#x26;token=b298bab4-ca28-41f8-919b-0948bb436614" alt="Bronze layer raw telematics data ERD"><figcaption><p>ERD data telematika mentah lapisan Bronze</p></figcaption></figure>

{% hint style="info" %}
Diagram interaktif skema raw\_telematics\_data tersedia di **dbdiagram.io**: <https://dbdiagram.io/d/v1-schema-telematics-bd-67a0acef263d6cf9a0d8e750>
{% endhint %}

Temukan detail skema data telematika mentah di bawah ini.

{% code title="skema raw\_telematics\_data" expandable="true" %}

```sql
Table tracking_data_core {

  device_id integer [primary key]

  device_time timestampz [primary key]

  platform_time timestampz

  record_added_at timestampz [default: `now()`]

  latitude integer

  longitude integer

  speed integer

  altitude integer

  satellites integer

  event_id integer

  gps_fix_type integer

  hdop integer

  

  indexes {(device_id, device_time)}

}

  

Table inputs {

  event_id integer [primary key]

  device_id integer [primary key]

  record_added_at timestampz [default: `now()`]

  device_time timestampz [primary key]

  sensor_name text [primary key]

  value text

  indexes {(device_id, device_time)}

}

  

Table states {

  event_id integer [primary key]

  device_id serial [primary key]

  record_added_at timestampz [default: `now()`]

  device_time timestampz [primary key]

  state_name text [primary key]

  value text

  indexes {(device_id, device_time)}

}

  

Ref: inputs.(device_id, device_time) > tracking_data_core.(device_id, device_time)

Ref: states.(device_id, device_time) > tracking_data_core.(device_id, device_time)
```

{% endcode %}

### Tabel kunci menurut kategori

Setiap tabel memiliki tujuan spesifik dalam menangkap berbagai aspek informasi perangkat:

<details>

<summary><code>tracking_data_core</code></summary>

**Tujuan**: Data lokasi dan gerakan inti

<table><thead><tr><th width="181.20001220703125">Atribut</th><th>Detail</th></tr></thead><tbody><tr><td><strong>Bidang kunci</strong></td><td><code>device_id</code>, <code>device_time</code>, <code>platform_time</code>, <code>latitude</code>, <code>longitude</code>, <code>speed</code>, <code>altitude</code>, <code>satellites</code>, <code>hdop</code>, <code>event_id</code></td></tr><tr><td><strong>Pengindeksan</strong></td><td>Dioptimalkan dengan indeks pada (<code>device_id</code>, <code>device_time</code>)</td></tr><tr><td><strong>Catatan khusus</strong></td><td>Data lokasi (latitude dan longitude) menggunakan format integer dengan presisi 10⁷ untuk performa TimescaleDB yang optimal<br><br>Kecepatan juga disimpan dalam integer, sehingga Anda perlu membaginya dengan 100</td></tr></tbody></table>

</details>

<details>

<summary><code>inputs</code></summary>

**Tujuan**: Pembacaan sensor dari perangkat

<table><thead><tr><th width="182">Atribut</th><th>Detail</th></tr></thead><tbody><tr><td><strong>Bidang kunci</strong></td><td><code>input_id</code>, <code>device_id</code>, <code>device_time</code>, <code>sensor_name</code>, <code>value</code></td></tr><tr><td><strong>Konten</strong></td><td>Pembacaan analog (tingkat bahan bakar, suhu, tegangan), nilai yang dihitung (RPM mesin)</td></tr><tr><td><strong>Relasi</strong></td><td><pre data-overflow="wrap"><code>FROM raw_telematics_data.inputs AS i
JOIN raw_business_data.sensor_description AS sd
    ON i.device_id = sd.device_id AND i.sensor_name = sd.input_label
JOIN raw_telematics_data.tacking_data_core AS tdc
    ON i.device_id = tdc.device_id AND i.device_time = tdc.device_time
</code></pre></td></tr></tbody></table>

</details>

<details>

<summary><code>states</code></summary>

**Tujuan**: Indikator status perangkat dan mode operasional

<table><thead><tr><th width="174.800048828125">Atribut</th><th>Detail</th></tr></thead><tbody><tr><td><strong>Field Kunci</strong></td><td><code>state_id</code>, <code>device_id</code>, <code>device_time</code>, <code>state_name</code>, <code>value</code></td></tr><tr><td><strong>Konten</strong></td><td>Indikator mode operasi (bekerja, idle, mati), status komponen (ignition, pintu)</td></tr><tr><td><strong>Format Nilai</strong></td><td>Nilai boolean (1/0) atau kode status tertentu</td></tr></tbody></table>

</details>

Data dalam skema ini diingest langsung dari perangkat, dengan latensi minimal (biasanya beberapa detik). Skema ini dioptimalkan untuk data deret waktu menggunakan TimescaleDB untuk penyimpanan dan pengambilan yang efisien.

## Informasi tambahan

### Validasi data

Basis data menegakkan integritas data melalui beberapa mekanisme:

* **Kendala CHECK** memvalidasi bahwa nilai berada dalam rentang yang dapat diterima
* **Kunci asing** memastikan hubungan antar tabel tetap konsisten
* **Kendala NOT NULL** menjamin bahwa bidang yang diwajibkan selalu memiliki nilai
* **Nilai DEFAULT** menyediakan nilai cadangan ketika data tidak disediakan secara eksplisit

### Optimasi kueri

Tabel diatur dengan strategi pengindeksan tertentu:

* Semua tabel menyertakan **indeks berbasis waktu** pada `record_added_at`
* Kolom kunci asing memiliki indeks khusus untuk kinerja join
* Kombinasi kolom yang sering digunakan memiliki **indeks komposit**
* TimescaleDB menyediakan indeks khusus untuk kueri deret waktu

## `repo` struktur data

{% hint style="warning" %}
**Skema ini saat ini sedang dalam pengembangan.** Jika Anda tertarik untuk mendapatkan akses awal atau memiliki pertanyaan tentang fungsi ini, silakan hubungi <iotquery@navixy.com>.
{% endhint %}

The `repo` Skema ini menyediakan kerangka kerja yang komprehensif untuk mengelola struktur organisasi, aset, perangkat, dan hubungan di antaranya dalam lingkungan multi-tenant. Dibangun di atas PostgreSQL 14+ dengan ekstensi ltree, skema ini mendukung organisasi hierarkis, definisi field kustom untuk semua jenis entitas, kontrol akses berbasis peran dengan pembatasan tingkat objek, dan jejak audit lengkap dengan pelacakan perubahan pada tingkat field. Semua entitas dapat diperluas tanpa modifikasi skema, dilokalkan untuk penerapan internasional, dan dihubungkan melalui hubungan polimorfik yang fleksibel.

Skema ini menangani skenario pengelolaan data yang kompleks, termasuk hierarki aset armada di berbagai tingkat organisasi, platform SaaS multi-tenant yang memerlukan isolasi data, operasi yang didorong kepatuhan dengan persyaratan audit terperinci, dan sistem yang membutuhkan model data dinamis yang dapat disesuaikan melalui field kustom alih-alih migrasi basis data.

<figure><img src="https://660637463-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoFNFEIINiGFbhi3Px3dE%2Fuploads%2FOiyhgXkaS0x3wzKquynf%2FNavixy%20Repo%20data%20schema.svg?alt=media&#x26;token=b3148ca9-9b38-4d7a-b246-01d9bc718ae2" alt=""><figcaption></figcaption></figure>

{% hint style="info" %}
Diagram interaktif dari`repo` skema data tersedia di **dbdiagram.io**: <https://dbdiagram.io/d/Navixy-Repo-data-schema-68ad788c1e7a611967a0930e>
{% endhint %}

Temukan `repo` detail skema di bawah ini.

{% code title="skema data repo" expandable="true" %}

```sql
// ============================================
// Skema DataHub Baru - Customer Journey
// PostgreSQL 14+ dengan ekstensi ltree
// Versi: 2.0 (Konsep)
// ============================================

// ============================================
// TABEL ACUAN DASAR (hierarki ci_base)
// ============================================

Table ci_base {
  id uuid [primary key]
  code text [not null]
  title_en text [not null]
  order int
  is_system boolean [not null, default: false]
  discriminator text [not null]
  catalog_id uuid
  organization_id uuid
  parent_id uuid
  path ltree
  is_hierarchical boolean [default: false]
  extra jsonb
  created_at timestamptz [not null, default: `CURRENT_TIMESTAMP`]
  updated_at timestamptz [not null, default: `CURRENT_TIMESTAMP`]
  deleted_at timestamptz
  
  indexes {
    (parent_id) [name: 'idx_ci_parent']
    (path) [type: gist, name: 'idx_ci_path_gist']
    (catalog_id) [name: 'idx_ci_catalog']
    (organization_id) [name: 'idx_ci_org']
    (discriminator) [name: 'idx_ci_discriminator']
    (code) [unique, name: 'uq_ci_code_per_type']
    (organization_id, code) [unique, name: 'uq_ci_org_code']
  }
}

Table ci_module {
  id uuid [primary key]
}

Table ci_catalog_category {
  id uuid [primary key]
}

Table ci_country {
  id uuid [primary key]
}

Table ci_role {
  id uuid [primary key]
}

Table ci_entity_type {
  id uuid [primary key]
}

Table ci_device_status {
  id uuid [primary key]
}

Table ci_permission_scope {
  id uuid [primary key]
  module_id uuid
  entity_type_id uuid
  category text
}

Table ci_device_type {
  id uuid [primary key]
}

Table ci_asset_type {
  id uuid [primary key]
  category_id uuid
}

Table ci_asset_type_category {
  id uuid [primary key]
}

Table ci_inventory_type {
  id uuid [primary key]
}

Table ci_organization_type {
  id uuid [primary key]
}

Table ci_user_type {
  id uuid [primary key]
}

Table ci_asset_group_type {
  id uuid [primary key]
  max_items int
  color text
  icon text
  allowed_asset_type_id uuid
}

Table ci_device_relation_type {
  id uuid [primary key]
}

Table ci_tag {
  id uuid [primary key]
  entity_type_id uuid
  color text
}

// ============================================
// ENTITAS DASAR DENGAN DUKUNGAN FIELD KUSTOM
// ============================================

Table customizable_entity {
  id uuid [primary key]
  entity_type_id uuid [not null]
  cf_data jsonb
  created_at timestamptz [not null, default: `CURRENT_TIMESTAMP`]
  
  indexes {
    (entity_type_id) [name: 'idx_customizable_entity_type']
  }
}

// ============================================
// ENTITAS BISNIS INTI
// ============================================

Table organization {
  id uuid [primary key]
  parent_id uuid
  path ltree
  organization_type_id uuid [not null]
  title_en text [not null]
  is_active boolean [not null, default: true]
  created_at timestamptz [not null, default: `CURRENT_TIMESTAMP`]
  updated_at timestamptz [not null, default: `CURRENT_TIMESTAMP`]
  deleted_at timestamptz
  deleted_by uuid
  
  indexes {
    (parent_id) [name: 'idx_org_parent']
    (path) [type: gist, name: 'idx_org_path_gist']
    (organization_type_id) [name: 'idx_org_type']
  }
}

Table catalog {
  id uuid [primary key]
  organization_id uuid [not null]
  module_id uuid
  category_id uuid
  title_en text [not null]
  is_system boolean [not null, default: false]
  created_at timestamptz [not null, default: `CURRENT_TIMESTAMP`]
  updated_at timestamptz [not null, default: `CURRENT_TIMESTAMP`]
  
  indexes {
    (organization_id) [name: 'idx_catalog_org']
    (module_id) [name: 'idx_catalog_module']
  }
}

Table user {
  id uuid [primary key]
  organization_id uuid [not null]
  user_type_id uuid [not null]
  identity_provider text [not null]
  identity_provider_id uuid [not null]
  full_name text [not null]
  is_active boolean [not null, default: true]
  created_at timestamptz [not null, default: `CURRENT_TIMESTAMP`]
  updated_at timestamptz [not null, default: `CURRENT_TIMESTAMP`]
  deleted_at timestamptz
  deleted_by uuid
  
  indexes {
    (organization_id) [name: 'idx_user_org']
    (user_type_id) [name: 'idx_user_type']
    (organization_id, identity_provider, identity_provider_id) [unique, name: 'uq_user_org_idp']
  }
}

// ============================================
// KONTROL AKSES (ACL)
// ============================================

Table user_role {
  id uuid [primary key]
  user_id uuid [not null]
  role_id uuid [not null]
  assigned_at timestamptz [not null, default: `CURRENT_TIMESTAMP`]
  assigned_by uuid
  
  indexes {
    (user_id) [name: 'idx_user_role_user']
    (role_id) [name: 'idx_user_role_role']
    (user_id, role_id) [unique, name: 'uq_user_role']
  }
}

Table acl_role_permission {
  id uuid [primary key]
  role_id uuid [not null]
  permission_scope_id uuid [not null]
  target_entity_id uuid
  actions int [not null]
  granted_at timestamptz [not null, default: `CURRENT_TIMESTAMP`]
  granted_by uuid
  
  indexes {
    (role_id) [name: 'idx_acl_role_perm_role']
    (permission_scope_id) [name: 'idx_acl_role_perm_scope']
    (role_id, permission_scope_id, target_entity_id) [unique, name: 'uq_acl_role_permission']
  }
}

Table acl_user_scope {
  id uuid [primary key]
  user_id uuid [not null]
  permission_scope_id uuid [not null]
  target_entity_id uuid [not null]
  actions int [not null]
  
  indexes {
    (user_id, permission_scope_id) [name: 'idx_acl_user_scope_user']
    (user_id, permission_scope_id, target_entity_id) [unique, name: 'uq_acl_user_scope']
  }
}

// ============================================
// ENTITAS BISNIS
// ============================================

Table asset {
  id uuid [primary key]
  organization_id uuid [not null]
  asset_type_id uuid [not null]
  label text [not null]
  description text
  created_at timestamptz [not null, default: `CURRENT_TIMESTAMP`]
  updated_at timestamptz [not null, default: `CURRENT_TIMESTAMP`]
  deleted_at timestamptz
  deleted_by uuid
  
  indexes {
    (organization_id) [name: 'idx_asset_org']
    (asset_type_id) [name: 'idx_asset_type']
  }
}

Table inventory {
  id uuid [primary key]
  organization_id uuid [not null]
  inventory_type_id uuid [not null]
  code text [not null]
  created_at timestamptz [not null, default: `CURRENT_TIMESTAMP`]
  updated_at timestamptz [not null, default: `CURRENT_TIMESTAMP`]
  deleted_at timestamptz
  deleted_by uuid
  
  indexes {
    (organization_id) [name: 'idx_inventory_org']
    (inventory_type_id) [name: 'idx_inventory_type']
    (organization_id, code) [unique, name: 'uq_inventory_org_code']
  }
}

Table device {
  id uuid [primary key]
  organization_id uuid [not null]
  device_type_id uuid [not null]
  status_id uuid [not null]
  hw_id text
  label text [not null]
  created_at timestamptz [not null, default: `CURRENT_TIMESTAMP`]
  updated_at timestamptz [not null, default: `CURRENT_TIMESTAMP`]
  deleted_at timestamptz
  deleted_by uuid
  
  indexes {
    (organization_id) [name: 'idx_device_org']
    (device_type_id) [name: 'idx_device_type']
    (status_id) [name: 'idx_device_status']
    (hw_id) [name: 'idx_device_hw_id']
  }
}

Table device_asset_link {
  id uuid [primary key]
  device_id uuid [unique, not null]
  asset_id uuid [not null]
  linked_at timestamptz [not null, default: `CURRENT_TIMESTAMP`]
  linked_by uuid
  
  indexes {
    (device_id) [unique, name: 'idx_device_asset_link_device']
    (asset_id) [name: 'idx_device_asset_link_asset']
  }
}

Table device_inventory_link {
  id uuid [primary key]
  device_id uuid [unique, not null]
  inventory_id uuid [not null]
  linked_at timestamptz [not null, default: `CURRENT_TIMESTAMP`]
  linked_by uuid
  
  indexes {
    (device_id) [unique, name: 'idx_device_inventory_link_device']
    (inventory_id) [name: 'idx_device_inventory_link_inventory']
  }
}

Table device_relation {
  id uuid [primary key]
  master_id uuid [not null]
  slave_id uuid [not null]
  relation_type_id uuid [not null]
  
  indexes {
    (master_id) [name: 'idx_device_relation_master']
    (slave_id) [name: 'idx_device_relation_slave']
    (master_id, slave_id, relation_type_id) [unique, name: 'uq_device_relation']
  }
}

Table asset_group {
  id uuid [primary key]
  organization_id uuid [not null]
  group_type_id uuid [not null]
  title_en text [not null]
  description text
  created_at timestamptz [not null, default: `CURRENT_TIMESTAMP`]
  updated_at timestamptz [not null, default: `CURRENT_TIMESTAMP`]
  deleted_at timestamptz
  deleted_by uuid
  
  indexes {
    (organization_id) [name: 'idx_asset_group_org']
    (group_type_id) [name: 'idx_asset_group_type']
  }
}

Table asset_group_item {
  id uuid [primary key]
  group_id uuid [not null]
  asset_id uuid [not null]
  attached_at timestamptz [not null, default: `CURRENT_TIMESTAMP`]
  detached_at timestamptz
  
  indexes {
    (group_id) [name: 'idx_asset_group_item_group']
    (asset_id) [name: 'idx_asset_group_item_asset']
    (group_id, asset_id, detached_at) [unique, name: 'uq_asset_group_item']
  }
}

Table entity_tag {
  id uuid [primary key]
  tag_id uuid [not null]
  entity_id uuid [not null]
  tagged_at timestamptz [not null, default: `CURRENT_TIMESTAMP`]
  
  indexes {
    (tag_id) [name: 'idx_entity_tag_tag']
    (entity_id) [name: 'idx_entity_tag_entity']
    (tag_id, entity_id) [unique, name: 'uq_entity_tag']
  }
}

// ============================================
// LOKALISASI
// ============================================

Table i18n_text {
  entity_id uuid [pk]
  field_code text [pk]
  locale text [pk]
  text_value text [not null]
  
  indexes {
    (entity_id) [name: 'idx_i18n_entity']
    (locale) [name: 'idx_i18n_locale']
  }
}

// ============================================
// FIELD KUSTOM - DEFINISI
// ============================================

Table custom_field_def {
  id uuid [primary key]
  organization_id uuid [not null]
  owner_entity_type_id uuid [not null]
  code text [not null]
  title_en text [not null]
  field_type text [not null]
  is_multi boolean [not null, default: false]
  is_required boolean [not null, default: false]
  order int
  ref_entity_type_id uuid
  ref_catalog_id uuid
  created_at timestamptz [not null, default: `CURRENT_TIMESTAMP`]
  updated_at timestamptz [not null, default: `CURRENT_TIMESTAMP`]
  
  indexes {
    (organization_id) [name: 'idx_cfd_org']
    (owner_entity_type_id) [name: 'idx_cfd_owner_type']
    (organization_id, owner_entity_type_id, code) [unique, name: 'uq_cfd_org_type_code']
  }
}

// ============================================
// FIELD KUSTOM - NILAI (berdasarkan tipe)
// ============================================

Table custom_field_value_text {
  customizable_entity_id uuid [pk]
  field_def_id uuid [pk]
  value_index smallint [pk]
  value text [not null]
  
  indexes {
    (field_def_id, value) [name: 'idx_cfv_text_value']
  }
}

Table custom_field_value_number {
  customizable_entity_id uuid [pk]
  field_def_id uuid [pk]
  value_index smallint [pk]
  value numeric [not null]
  
  indexes {
    (field_def_id, value) [name: 'idx_cfv_number_value']
  }
}

Table custom_field_value_boolean {
  customizable_entity_id uuid [pk]
  field_def_id uuid [pk]
  value_index smallint [pk]
  value boolean [not null]
  
  indexes {
    (field_def_id, value) [name: 'idx_cfv_boolean_value']
  }
}

Table custom_field_value_date {
  customizable_entity_id uuid [pk]
  field_def_id uuid [pk]
  value_index smallint [pk]
  value date [not null]
  
  indexes {
    (field_def_id, value) [name: 'idx_cfv_date_value']
  }
}

Table custom_field_value_datetime {
  customizable_entity_id uuid [pk]
  field_def_id uuid [pk]
  value_index smallint [pk]
  value timestamptz [not null]
  
  indexes {
    (field_def_id, value) [name: 'idx_cfv_datetime_value']
  }
}

Table custom_field_value_entity {
  customizable_entity_id uuid [pk]
  field_def_id uuid [pk]
  value_index smallint [pk]
  ref_entity_id uuid [not null]
  
  indexes {
    (field_def_id, ref_entity_id) [name: 'idx_cfv_entity_value']
  }
}

Table custom_field_value_catalog {
  customizable_entity_id uuid [pk]
  field_def_id uuid [pk]
  value_index smallint [pk]
  ref_item_id uuid [not null]
  
  indexes {
    (field_def_id, ref_item_id) [name: 'idx_cfv_catalog_value']
  }
}

// ============================================
// AUDIT
// ============================================

Table audit_event {
  id uuid [primary key]
  event_category text [not null]
  user_id uuid
  identity_provider_id uuid
  ip_address inet
  user_agent text
  aggregate_type text
  aggregate_id uuid
  event_type text [not null]
  event_data jsonb
  occurred_at timestamptz [not null, default: `CURRENT_TIMESTAMP`]
  
  indexes {
    (user_id, occurred_at) [name: 'idx_audit_event_user']
    (aggregate_type, aggregate_id, occurred_at) [name: 'idx_audit_event_aggregate']
    (event_category, occurred_at) [name: 'idx_audit_event_category']
    (event_type, occurred_at) [name: 'idx_audit_event_type']
  }
}

// ============================================
// HUBUNGAN
// ============================================

Ref: ci_base.catalog_id > catalog.id
Ref: ci_base.organization_id > organization.id
Ref: ci_base.parent_id > ci_base.id

Ref: ci_module.id - ci_base.id
Ref: ci_catalog_category.id - ci_base.id
Ref: ci_country.id - ci_base.id
Ref: ci_role.id - ci_base.id
Ref: ci_entity_type.id - ci_base.id
Ref: ci_device_status.id - ci_base.id
Ref: ci_permission_scope.id - ci_base.id
Ref: ci_device_type.id - ci_entity_type.id
Ref: ci_asset_type.id - ci_entity_type.id
Ref: ci_asset_type_category.id - ci_base.id
Ref: ci_inventory_type.id - ci_entity_type.id
Ref: ci_organization_type.id - ci_entity_type.id
Ref: ci_user_type.id - ci_entity_type.id
Ref: ci_asset_group_type.id - ci_entity_type.id
Ref: ci_device_relation_type.id - ci_base.id
Ref: ci_tag.id - ci_base.id

Ref: ci_permission_scope.module_id > ci_module.id
Ref: ci_permission_scope.entity_type_id > ci_entity_type.id
Ref: ci_asset_type.category_id > ci_asset_type_category.id
Ref: ci_asset_group_type.allowed_asset_type_id > ci_asset_type.id
Ref: ci_tag.entity_type_id > ci_entity_type.id

Ref: customizable_entity.entity_type_id > ci_entity_type.id

Ref: organization.id - customizable_entity.id
Ref: organization.parent_id > organization.id
Ref: organization.organization_type_id > ci_organization_type.id
Ref: organization.deleted_by > user.id

Ref: catalog.organization_id > organization.id
Ref: catalog.module_id > ci_module.id
Ref: catalog.category_id > ci_catalog_category.id

Ref: user.id - customizable_entity.id
Ref: user.organization_id > organization.id
Ref: user.user_type_id > ci_user_type.id
Ref: user.deleted_by > user.id

Ref: user_role.user_id > user.id
Ref: user_role.role_id > ci_role.id
Ref: user_role.assigned_by > user.id

Ref: acl_role_permission.role_id > ci_role.id
Ref: acl_role_permission.permission_scope_id > ci_permission_scope.id
Ref: acl_role_permission.granted_by > user.id

Ref: acl_user_scope.user_id > user.id
Ref: acl_user_scope.permission_scope_id > ci_permission_scope.id

Ref: asset.id - customizable_entity.id
Ref: asset.organization_id > organization.id
Ref: asset.asset_type_id > ci_asset_type.id
Ref: asset.deleted_by > user.id

Ref: inventory.id - customizable_entity.id
Ref: inventory.organization_id > organization.id
Ref: inventory.inventory_type_id > ci_inventory_type.id
Ref: inventory.deleted_by > user.id

Ref: device.id - customizable_entity.id
Ref: device.organization_id > organization.id
Ref: device.device_type_id > ci_device_type.id
Ref: device.status_id > ci_device_status.id
Ref: device.deleted_by > user.id

Ref: device_asset_link.device_id - device.id
Ref: device_asset_link.asset_id > asset.id
Ref: device_asset_link.linked_by > user.id

Ref: device_inventory_link.device_id - device.id
Ref: device_inventory_link.inventory_id > inventory.id
Ref: device_inventory_link.linked_by > user.id

Ref: device_relation.master_id > device.id
Ref: device_relation.slave_id > device.id
Ref: device_relation.relation_type_id > ci_device_relation_type.id

Ref: asset_group.id - customizable_entity.id
Ref: asset_group.organization_id > organization.id
Ref: asset_group.group_type_id > ci_asset_group_type.id
Ref: asset_group.deleted_by > user.id

Ref: asset_group_item.group_id > asset_group.id
Ref: asset_group_item.asset_id > asset.id

Ref: entity_tag.tag_id > ci_tag.id

Ref: custom_field_def.organization_id > organization.id
Ref: custom_field_def.owner_entity_type_id > ci_entity_type.id
Ref: custom_field_def.ref_entity_type_id > ci_entity_type.id
Ref: custom_field_def.ref_catalog_id > catalog.id

Ref: custom_field_value_text.customizable_entity_id > customizable_entity.id
Ref: custom_field_value_text.field_def_id > custom_field_def.id

Ref: custom_field_value_number.customizable_entity_id > customizable_entity.id
Ref: custom_field_value_number.field_def_id > custom_field_def.id

Ref: custom_field_value_boolean.customizable_entity_id > customizable_entity.id
Ref: custom_field_value_boolean.field_def_id > custom_field_def.id

Ref: custom_field_value_date.customizable_entity_id > customizable_entity.id
Ref: custom_field_value_date.field_def_id > custom_field_def.id

Ref: custom_field_value_datetime.customizable_entity_id > customizable_entity.id
Ref: custom_field_value_datetime.field_def_id > custom_field_def.id

Ref: custom_field_value_entity.customizable_entity_id > customizable_entity.id
Ref: custom_field_value_entity.field_def_id > custom_field_def.id
Ref: custom_field_value_entity.ref_entity_id > customizable_entity.id

Ref: custom_field_value_catalog.customizable_entity_id > customizable_entity.id
Ref: custom_field_value_catalog.field_def_id > custom_field_def.id
Ref: custom_field_value_catalog.ref_item_id > ci_base.id

Ref: audit_event.user_id > user.id
```

{% endcode %}

### Frekuensi pembaruan

Data dalam `repo` skema ini disinkronkan secara real-time dengan sistem sumber. Pembaruan terjadi segera saat perubahan berlangsung, dengan jejak audit yang menangkap semua modifikasi untuk kepatuhan dan analisis historis.

### `ci_base`

The `repo` skema menggunakan pola Single Table Inheritance untuk semua data acuan melalui `ci_base` tabel:

The `repo` skema menggunakan **Single Table Inheritance** pola untuk semua data acuan melalui `ci_base` tabel. Desain ini mengonsolidasikan kamus sistem, klasifikasi, dan item acuan yang ditentukan pengguna ke dalam satu struktur terpadu, sehingga memberikan konsistensi dan fleksibilitas di seluruh skema.

**Arsitektur:**

The `ci_base` tabel berfungsi sebagai fondasi bagi semua data acuan, menggunakan field `discriminator` untuk mengidentifikasi jenis acuan tertentu. Setiap jenis acuan memiliki tabel yang sesuai (seperti `ci_device_type`, `ci_asset_type`) yang berbagi `id` yang sama dengan `ci_base`, sehingga menciptakan hubungan pewarisan yang aman terhadap tipe.

**Cara entitas bisnis terhubung ke ci\_base:**

Semua entitas bisnis dalam `repo` skema mereferensikan `ci_base` subtipe untuk mendefinisikan klasifikasi dan perilakunya:

* `organization` → mereferensikan `ci_organization_type` (yang mewarisi dari `ci_entity_type` → `ci_base`)
* `user` → mereferensikan `ci_user_type` (yang mewarisi dari `ci_entity_type` → `ci_base`)
* `device` → mereferensikan `ci_device_type` dan `ci_device_status` (keduanya mewarisi dari `ci_base`)
* `asset` → mereferensikan `ci_asset_type` (yang mewarisi dari `ci_entity_type` → `ci_base`)
* `inventory` → mereferensikan `ci_inventory_type` (yang mewarisi dari `ci_entity_type` → `ci_base`)
* `asset_group` → mereferensikan `ci_asset_group_type` (yang mewarisi dari `ci_entity_type` → `ci_base`)

**Kategori jenis acuan:**

| Kategori                   | Tabel                                                                                                                                   | Tujuan                                                                                 |
| -------------------------- | --------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------- |
| **Konfigurasi sistem**     | `ci_module`, `ci_country`, `ci_role`                                                                                                    | Mendefinisikan modul sistem, referensi geografis, dan peran pengguna                   |
| **Definisi jenis entitas** | `ci_entity_type`, `ci_device_type`, `ci_asset_type`, `ci_inventory_type`, `ci_organization_type`, `ci_user_type`, `ci_asset_group_type` | Mengklasifikasikan semua entitas bisnis berdasarkan jenisnya                           |
| **Status dan klasifikasi** | `ci_device_status`, `ci_asset_type_category`                                                                                            | Melacak status entitas dan mengelompokkan jenis ke dalam kategori                      |
| **Kontrol akses**          | `ci_permission_scope`                                                                                                                   | Tentukan izin apa yang dapat diberikan (terhubung ke `ci_module` dan `ci_entity_type`) |
| **Relasi**                 | `ci_device_relation_type`                                                                                                               | Tentukan jenis hubungan antara perangkat (master-slave, cadangan, dll.)                |
| **Pengelompokan**          | `ci_tag`, `ci_catalog_category`                                                                                                         | Memungkinkan penandaan fleksibel dan pengorganisasian katalog                          |

<details>

<summary><strong>Contoh pola kueri</strong></summary>

```sql
-- Dapatkan semua jenis perangkat untuk suatu organisasi (sistem + kustom)
SELECT cb.id, cb.code, cb.title_en, cb.is_system
FROM repo.ci_base cb
JOIN repo.ci_device_type dt ON dt.id = cb.id
WHERE cb.discriminator = 'device_type'
  AND (cb.is_system = true OR cb.organization_id = $org_id)
  AND cb.deleted_at IS NULL;

-- Dapatkan jenis aset beserta kategorinya
SELECT 
  cb.code as asset_type_code,
  cb.title_en as asset_type_name,
  cat_cb.title_en as category_name
FROM repo.ci_base cb
JOIN repo.ci_asset_type at ON at.id = cb.id
LEFT JOIN repo.ci_asset_type_category cat ON cat.id = at.category_id
LEFT JOIN repo.ci_base cat_cb ON cat_cb.id = cat.id
WHERE cb.discriminator = 'asset_type'
  AND cb.deleted_at IS NULL;

-- Dapatkan struktur tag hierarkis
SELECT cb.id, cb.code, cb.title_en, cb.path, cb.parent_id
FROM repo.ci_base cb
JOIN repo.ci_tag t ON t.id = cb.id
WHERE cb.discriminator = 'tag'
  AND cb.deleted_at IS NULL
ORDER BY cb.path;
```

</details>

### Tabel kunci menurut kategori

Tabel dalam `repo` skema diorganisasikan ke dalam kategori fungsional. Deskripsi di bawah ini merangkum tabel-tabel yang paling penting berdasarkan tujuan bisnisnya.

<details>

<summary><code>organization</code></summary>

**Tujuan:** Manajemen organisasi hierarkis

<table><thead><tr><th width="139">Atribut</th><th>Detail</th></tr></thead><tbody><tr><td><strong>Bidang kunci</strong></td><td><code>id</code>, <code>parent_id</code>, <code>path</code>, <code>organization_type_id</code>, <code>title_en</code>, <code>is_active</code>, <code>deleted_at</code></td></tr><tr><td><strong>Pengindeksan</strong></td><td>Indeks GiST pada <code>path</code> untuk kueri hierarkis, indeks pada <code>parent_id</code> dan <code>organization_type_id</code></td></tr><tr><td><strong>Catatan khusus</strong></td><td>Menggunakan ltree untuk hierarki multitingkat, mewarisi dari <code>customizable_entity</code> untuk dukungan bidang kustom</td></tr></tbody></table>

</details>

<details>

<summary><code>user</code></summary>

**Tujuan:** Akun pengguna dan autentikasi

<table><thead><tr><th width="139">Atribut</th><th>Detail</th></tr></thead><tbody><tr><td><strong>Bidang kunci</strong></td><td><code>id</code>, <code>organization_id</code>, <code>user_type_id</code>, <code>identity_provider</code>, <code>identity_provider_id</code>, <code>full_name</code>, <code>is_active</code></td></tr><tr><td><strong>Pengindeksan</strong></td><td>Indeks unik pada (<code>organization_id</code>, <code>identity_provider</code>, <code>identity_provider_id</code>)</td></tr><tr><td><strong>Catatan khusus</strong></td><td>Integrasi penyedia identitas eksternal (Keycloak, Auth0, Okta), mewarisi dari <code>customizable_entity</code></td></tr></tbody></table>

</details>

<details>

<summary><code>device</code></summary>

**Tujuan:** Perangkat pelacakan fisik

<table><thead><tr><th width="139">Atribut</th><th>Detail</th></tr></thead><tbody><tr><td><strong>Bidang kunci</strong></td><td><code>id</code>, <code>organization_id</code>, <code>device_type_id</code>, <code>status_id</code>, <code>hw_id</code>, <code>label</code></td></tr><tr><td><strong>Pengindeksan</strong></td><td>Indeks pada <code>organization_id</code>, <code>device_type_id</code>, <code>status_id</code>, <code>hw_id</code></td></tr><tr><td><strong>Catatan khusus</strong></td><td>Pengidentifikasi perangkat keras untuk pelacakan perangkat, mewarisi dari <code>customizable_entity</code> untuk bidang kustom</td></tr></tbody></table>

</details>

<details>

<summary><code>asset</code></summary>

**Tujuan:** Aset fisik atau virtual

<table><thead><tr><th width="139">Atribut</th><th>Detail</th></tr></thead><tbody><tr><td><strong>Bidang kunci</strong></td><td><code>id</code>, <code>organization_id</code>, <code>asset_type_id</code>, <code>label</code>, <code>description</code></td></tr><tr><td><strong>Pengindeksan</strong></td><td>Indeks pada <code>organization_id</code> dan <code>asset_type_id</code></td></tr><tr><td><strong>Catatan khusus</strong></td><td>Mewarisi dari <code>customizable_entity</code>terhubung ke perangkat melalui <code>device_asset_link</code></td></tr></tbody></table>

</details>

<details>

<summary><code>inventory</code></summary>

**Tujuan:** Catatan inventaris dan gudang

<table><thead><tr><th width="139">Atribut</th><th>Detail</th></tr></thead><tbody><tr><td><strong>Bidang kunci</strong></td><td><code>id</code>, <code>organization_id</code>, <code>inventory_type_id</code>, <code>code</code></td></tr><tr><td><strong>Pengindeksan</strong></td><td>Indeks unik pada (<code>organization_id</code>, <code>code</code>)</td></tr><tr><td><strong>Catatan khusus</strong></td><td>Kode unik di dalam organisasi, terhubung ke perangkat melalui <code>device_inventory_link</code></td></tr></tbody></table>

</details>

<details>

<summary><code>asset_group</code></summary>

**Tujuan:** Pengelompokan aset dengan pelacakan historis

<table><thead><tr><th width="139">Atribut</th><th>Detail</th></tr></thead><tbody><tr><td><strong>Bidang kunci</strong></td><td><code>id</code>, <code>organization_id</code>, <code>group_type_id</code>, <code>title_en</code>, <code>description</code></td></tr><tr><td><strong>Relasi</strong></td><td><code>FROM repo.asset_group AS ag JOIN repo.asset_group_item AS agi ON agi.group_id = ag.id JOIN repo.asset AS a ON a.id = agi.asset_id WHERE agi.detached_at IS NULL</code></td></tr><tr><td><strong>Catatan khusus</strong></td><td>Keanggotaan berbasis waktu melalui <code>asset_group_item</code>, kueri anggota saat ini dengan <code>WHERE detached_at IS NULL</code></td></tr></tbody></table>

</details>

<details>

<summary><code>custom_field_def</code></summary>

**Tujuan:** Definisi bidang kustom dan metadata

<table><thead><tr><th width="139">Atribut</th><th>Detail</th></tr></thead><tbody><tr><td><strong>Bidang kunci</strong></td><td><code>id</code>, <code>organization_id</code>, <code>owner_entity_type_id</code>, <code>code</code>, <code>field_type</code>, <code>is_multi</code>, <code>is_required</code></td></tr><tr><td><strong>Konten</strong></td><td>Jenis bidang mencakup text, number, boolean, date, datetime, entity_ref, catalog_item_ref</td></tr><tr><td><strong>Catatan khusus</strong></td><td>Memungkinkan bidang kustom yang fleksibel untuk jenis entitas apa pun, nilai disimpan dalam <code>custom_field_value_*</code> tabel</td></tr></tbody></table>

</details>

<details>

<summary><code>acl_role_permission</code></summary>

**Tujuan:** Manajemen izin berbasis peran

<table><thead><tr><th width="139">Atribut</th><th>Detail</th></tr></thead><tbody><tr><td><strong>Bidang kunci</strong></td><td><code>id</code>, <code>role_id</code>, <code>permission_scope_id</code>, <code>target_entity_id</code>, <code>actions</code></td></tr><tr><td><strong>Konten</strong></td><td>Bitmask tindakan (READ=1, UPDATE=2, DELETE=4, CREATE=8), izin khusus target atau berlaku untuk seluruh jenis entitas</td></tr><tr><td><strong>Relasi</strong></td><td><code>FROM repo.user_role AS ur JOIN repo.acl_role_permission AS rp ON rp.role_id = ur.role_id WHERE ur.user_id = $user_id</code></td></tr><tr><td><strong>Catatan khusus</strong></td><td>Berfungsi dengan <code>user_role</code> dan <code>acl_user_scope</code> untuk menentukan izin akhir pengguna</td></tr></tbody></table>

</details>

<details>

<summary><code>audit_event</code></summary>

**Tujuan:** Log audit terpadu untuk semua perubahan sistem

<table><thead><tr><th width="139">Atribut</th><th>Detail</th></tr></thead><tbody><tr><td><strong>Bidang kunci</strong></td><td><code>id</code>, <code>event_category</code>, <code>user_id</code>, <code>aggregate_type</code>, <code>aggregate_id</code>, <code>event_type</code>, <code>event_data</code>, <code>occurred_at</code></td></tr><tr><td><strong>Pengindeksan</strong></td><td>Indeks pada (<code>user_id</code>, <code>occurred_at</code>), (<code>aggregate_type</code>, <code>aggregate_id</code>, <code>occurred_at</code>), (<code>event_category</code>, <code>occurred_at</code>)</td></tr><tr><td><strong>Catatan khusus</strong></td><td>Dipartisi berdasarkan <code>occurred_at</code> (bulanan), dua kategori: <code>auth</code> (autentikasi) dan <code>domain</code> (peristiwa bisnis), menyimpan delta perubahan pada tingkat bidang dalam <code>event_data</code> JSONB</td></tr></tbody></table>

</details>

### Relasi data

The `repo` skema mengimplementasikan pola relasi yang canggih untuk pemodelan data yang fleksibel:

**Struktur hierarkis**

* Organisasi menggunakan path ltree untuk kueri pohon yang efisien
* Item referensi (`ci_base`) mendukung hierarki opsional
* Pemeliharaan path otomatis melalui trigger basis data

**Pola pewarisan**

* Pewarisan tabel: `customizable_entity` → entitas bisnis (`organization`, `user`, `device`, `asset`, `inventory`, `asset_group`)
* Pewarisan ID: `ci_base` → tabel jenis referensi
* Pembedaan tipe melalui `entity_type_id` dan `discriminator` bidang

**Relasi polimorfik**

Tabel tertentu menggunakan referensi polimorfik tanpa batasan foreign key demi fleksibilitas maksimal:

* `acl_role_permission.target_entity_id` → apa pun `customizable_entity`
* `acl_user_scope.target_entity_id` → apa pun `customizable_entity`
* `entity_tag.entity_id` → apa pun `customizable_entity`

Relasi-relasi ini divalidasi pada tingkat aplikasi.

### Informasi tambahan

#### Validasi data

The `repo` skema menegakkan integritas data melalui beberapa mekanisme:

**Batasan basis data**

* Batasan UNIQUE dengan dukungan soft delete (indeks parsial WHERE `deleted_at` IS NULL)
* Batasan CHECK (misalnya, `device_relation` memastikan `master_id` ≠ `slave_id`)
* Batasan NOT NULL pada field yang wajib
* Nilai DEFAULT untuk stempel waktu dan flag boolean

**Validasi tingkat aplikasi**

* Validasi jenis entitas untuk referensi polimorfik
* Validasi katalog untuk referensi field kustom
* Validasi tipe field kustom
* Manajemen array field bernilai ganda

#### Optimasi kueri

Tabel diatur dengan strategi pengindeksan tertentu:

**Indeks standar:**

* Semua foreign key memiliki indeks khusus
* Indeks berbasis waktu pada `created_at`, `updated_at`, `deleted_at`
* Indeks komposit untuk kolom yang sering digabungkan

**Indeks khusus:**

* Indeks GiST pada path ltree untuk kueri hierarkis
* Indeks unik parsial yang mendukung soft delete
* Indeks nilai field kustom untuk penyaringan dan pengurutan
* Indeks event audit pada waktu + entitas untuk pencarian yang efisien

**Pertimbangan performa:**

* Disarankan penggunaan connection pooling (PgBouncer)
* Pemeliharaan VACUUM rutin untuk tabel besar
* Potensi partisi di masa depan untuk `device` tabel berdasarkan `organization_id`
* Tampilan termaterialisasi untuk perhitungan kontrol akses yang kompleks
