Database Schema
PostgreSQL schema — core tables and relationships.
PostgreSQL 18 via GORM. cmd/main.go runs AutoMigrate against all models on startup. init.sql enables the uuid-ossp extension and declares enum types.
Entity relationships
Core tables
users
| Field | Type | Notes |
|---|---|---|
username | varchar | unique |
email | varchar | unique, nullable |
password | varchar | bcrypt hash, hidden in responses |
nik | varchar | unique, AES-GCM encrypted |
nama_ktp | varchar | full legal name |
nama_samaran | varchar | forum pseudonym |
nomor_hp | varchar | unique, normalized to 62-prefix |
role | varchar(20) | default "user"; "admin" for admins |
preferences | text[] | content/religion categories |
refresh_token | varchar | stored JWT refresh |
timezone | varchar | default "Asia/Makassar" |
is_verified | bool | |
password_reset_token | uuid | nullable |
pengingats (reminders)
| Field | Type | Notes |
|---|---|---|
user_id | uint FK | cascade |
tipe | varchar(20) | obat / makan / kontrol / terapi |
judul | varchar(100) | |
waktu | time | indexed with user_id |
timezone | varchar | |
is_done | bool | |
is_sent | bool | true when all schedules sent |
details | JSONB | schedule array + per-schedule send state |
Composite index idx_userid_waktu.
forum_threads / forum_replies
Threads and replies both support image_url, use_pseudonym, likes (composite-PK join tables), and saves. Replies nest via nullable parent_id.
Content tables
articles— scraped from Kemenkes or manually added;urlunique,tagJSON, FK tokategoris.videos/video_details— YouTube catalog;video_idunique.saved_articles/saved_videos— composite-PK(user_id, article_url|video_id).
faskes / dokters
faskes—place_id(Google) unique, lat/lng,status_operasional.dokters— many2many tofaskesviadokter_faskes;jadwal_praktikstored as JSONB array.
Logging
log_users and log_admins use UUID primary keys (uuid_generate_v4()), are written via an async queue, and carry rich analytics fields (event_type, event_name, screen_name, activity, action_status, error_message).
Known schema inconsistency
init.sql declares enum types role_display_type, reminder_status, reminder_type, while database/enum.go separately creates a kategori_type enum at startup. The in-code KategoriType Scan/Value methods treat it as a plain string, so the dynamic kategoris table is what articles/videos actually FK-link to.