erDiagram %% ======================================== %% CORE ENTITIES dengan RBAC %% ======================================== ROLES ||--o{ USERS : "defines" USERS ||--o{ ITEMS : "reports_found" USERS ||--o{ LOST_ITEMS : "reports_lost" USERS ||--o{ CLAIMS : "submits" USERS ||--o{ CLAIMS : "verifies_as" USERS ||--o{ REVISION_LOGS : "creates" USERS ||--o{ NOTIFICATIONS : "receives" USERS ||--o{ AUDIT_LOGS : "performs" USERS ||--o{ ARCHIVES : "claims_item" %% ======================================== %% CATEGORY & ATTACHMENT RELATIONS %% ======================================== CATEGORIES ||--o{ ITEMS : "categorizes" CATEGORIES ||--o{ LOST_ITEMS : "categorizes" CATEGORIES ||--o{ ARCHIVES : "categorizes" ITEMS ||--o{ ATTACHMENTS : "has_photos" LOST_ITEMS ||--o{ ATTACHMENTS : "has_photos" %% ======================================== %% CORE MATCHING & CLAIM LOGIC %% ======================================== ITEMS ||--o{ CLAIMS : "receives" ITEMS ||--o{ REVISION_LOGS : "tracks_changes" ITEMS ||--|{ ARCHIVES : "becomes_archived" LOST_ITEMS ||--o{ MATCH_RESULTS : "matched_to" ITEMS ||--o{ MATCH_RESULTS : "matched_with" %% ======================================== %% VERIFICATION PIPELINE (ETL) %% ======================================== CLAIMS ||--|| CLAIM_VERIFICATIONS : "verified_by" CLAIM_VERIFICATIONS ||--o{ VERIFICATION_LOGS : "tracks_verification" %% ======================================== %% TABLE DEFINITIONS WITH DETAILED SPECS %% ======================================== ROLES { int id PK "AUTO_INCREMENT" string name UK "UNIQUE, NOT NULL" text description json permissions "RBAC permissions" timestamp created_at timestamp updated_at timestamp deleted_at "SOFT DELETE" } USERS { int id PK "AUTO_INCREMENT" string name "NOT NULL" string email UK "UNIQUE, INDEXED" string password "ENCRYPTED (bcrypt)" string nrp UK "UNIQUE, INDEXED" string phone int role_id FK "→ ROLES, INDEXED" string status "INDEXED, DEFAULT: active" datetime last_login timestamp created_at timestamp updated_at timestamp deleted_at "SOFT DELETE, INDEXED" } CATEGORIES { int id PK "AUTO_INCREMENT" string name "NOT NULL" string slug UK "UNIQUE, INDEXED" text description string icon_url timestamp created_at timestamp updated_at timestamp deleted_at "SOFT DELETE, INDEXED" } ITEMS { int id PK "AUTO_INCREMENT" string name "INDEXED, NOT NULL" int category_id FK "→ CATEGORIES, INDEXED" string location "INDEXED, NOT NULL" text description "SECRET (for verification)" text secret_details "Only for owner/admin" date date_found "INDEXED" string status "INDEXED, DEFAULT: unclaimed" int reporter_id FK "→ USERS, INDEXED" string reporter_name string reporter_contact int view_count "Default: 0" datetime expires_at "INDEXED, TRIGGER" timestamp created_at timestamp updated_at timestamp deleted_at "INDEXED" } LOST_ITEMS { int id PK "AUTO_INCREMENT" int user_id FK "→ USERS, CASCADE" string name "NOT NULL" int category_id FK "→ CATEGORIES, INDEXED" string color string location "INDEXED" text description "For auto-matching" date date_lost "INDEXED" string status "INDEXED, DEFAULT: active" datetime resolved_at timestamp created_at timestamp updated_at timestamp deleted_at "SOFT DELETE, INDEXED" } ATTACHMENTS { int id PK "AUTO_INCREMENT" int item_id FK "nullable, → ITEMS" int lost_item_id FK "nullable, → LOST_ITEMS" string file_url "NOT NULL" string file_type "jpg, png, etc" int file_size "in bytes" string upload_by_user_id FK "→ USERS" int display_order "for ordering" boolean is_primary "DEFAULT: FALSE" timestamp created_at timestamp updated_at } CLAIMS { int id PK "AUTO_INCREMENT" int item_id FK "→ ITEMS, CASCADE, INDEXED" int user_id FK "→ USERS, CASCADE, INDEXED" text description "User's verification desc" string proof_url string contact "NOT NULL" string status "INDEXED, DEFAULT: pending" text notes "Admin notes" datetime verified_at int verified_by FK "→ USERS, nullable" string rejection_reason int attempt_count "Default: 1" timestamp created_at timestamp updated_at timestamp deleted_at "SOFT DELETE, INDEXED" } CLAIM_VERIFICATIONS { int id PK "AUTO_INCREMENT" int claim_id FK "UNIQUE, → CLAIMS" decimal similarity_score "0-100, INDEXED" text matched_keywords "JSON format" text verification_notes boolean is_auto_matched "DEFAULT: FALSE" string verification_method "manual/auto" json metadata "Additional verification data" timestamp created_at timestamp updated_at timestamp deleted_at "SOFT DELETE" } VERIFICATION_LOGS { int id PK "AUTO_INCREMENT" int verification_id FK "→ CLAIM_VERIFICATIONS" int verified_by_user_id FK "→ USERS" string action "approve/reject/pending" text reason timestamp created_at } MATCH_RESULTS { int id PK "AUTO_INCREMENT" int lost_item_id FK "→ LOST_ITEMS, INDEXED" int item_id FK "→ ITEMS, INDEXED" decimal similarity_score "0-100, threshold: 70" text matched_fields "JSON format" string match_reason "color/location/description" datetime matched_at boolean is_notified "INDEXED, DEFAULT: FALSE" datetime notified_at timestamp created_at timestamp updated_at timestamp deleted_at "SOFT DELETE, INDEXED" } ARCHIVES { int id PK "AUTO_INCREMENT" int item_id FK "UNIQUE, Original ID" string name int category_id FK "→ CATEGORIES, INDEXED" string photo_url string location text description date date_found string status string reporter_name string reporter_contact string archived_reason "expired/closed/claimed" int claimed_by FK "→ USERS, SET NULL" datetime archived_at "INDEXED" timestamp created_at timestamp updated_at timestamp deleted_at "SOFT DELETE, INDEXED" } REVISION_LOGS { int id PK "AUTO_INCREMENT" int item_id FK "→ ITEMS, CASCADE, INDEXED" int user_id FK "→ USERS, CASCADE, INDEXED" string field_name "changed field" text old_value text new_value text reason timestamp created_at "INDEXED" timestamp deleted_at "SOFT DELETE" } AUDIT_LOGS { int id PK "AUTO_INCREMENT" int user_id FK "nullable, → USERS, INDEXED" string action "INDEXED (CREATE/READ/UPDATE/DELETE)" string entity_type "INDEXED (table name)" int entity_id "INDEXED" json details "Change details" string ip_address string user_agent timestamp created_at "INDEXED" timestamp deleted_at "SOFT DELETE" } NOTIFICATIONS { int id PK "AUTO_INCREMENT" int user_id FK "→ USERS, CASCADE, INDEXED" string type "INDEXED (match/claim/update)" string title text message string entity_type "INDEXED" int entity_id string channel "email/sms/push" boolean is_read "INDEXED, DEFAULT: FALSE" datetime read_at timestamp created_at "INDEXED" timestamp updated_at timestamp deleted_at "SOFT DELETE" }