Skip to main content

Arsitektur Sistem & Model Data Database

Dokumentasi ini menjelaskan arsitektur internal backend, relasi entitas basis data, prinsip isolasi data multi-organisasi (multi-tenancy), serta mekanisme concurrency control dan offline sync.


1. Arsitektur Komponen Sistem

graph TB
subgraph ClientLayer["🌐 Client & Front Desk Tier"]
AdminDashboard["Dashboard Web (Next.js)"]
ScannerDesk["Meja Resepsi / PWA Scanner"]
LEDDisplay["Layar Sambutan Kiosk (LED)"]
GuestPublic["Halaman Undangan Publik (Mobile)"]
end

subgraph GatewayAuth["🛡️ Gateway & Middleware (Go Gin)"]
JWTAuth["JWT Authentication Middleware"]
TenantResolver["Multi-Tenant Resolver Middleware"]
end

subgraph ServiceModules["⚙️ Core Business Engines"]
EventEngine["Event & Schedule Service"]
GuestEngine["Guest & RSVP Service"]
CheckInEngine["Check-in & Anti-Duplicate Engine"]
SouvenirEngine["Souvenir Inventory & Reversal Service"]
ReportEngine["Analytics & CSV Export Service"]
WAEngine["WhatsApp Meta Cloud Client"]
end

subgraph DataStorage["💾 Storage Tier"]
PostgresDB[("PostgreSQL (ACID & Row-Locking)")]
RedisCache[("Redis (JWT & Tenant Cache)")]
end

AdminDashboard --> JWTAuth
ScannerDesk --> JWTAuth
LEDDisplay --> JWTAuth
GuestPublic --> TenantResolver

JWTAuth --> TenantResolver
TenantResolver --> EventEngine
TenantResolver --> GuestEngine
TenantResolver --> CheckInEngine
TenantResolver --> SouvenirEngine
TenantResolver --> ReportEngine
TenantResolver --> WAEngine

EventEngine --> PostgresDB
GuestEngine --> PostgresDB
CheckInEngine --> PostgresDB
SouvenirEngine --> PostgresDB
TenantResolver --> RedisCache

2. Diagram Relasi Entitas Database (ERD)

erDiagram
ORGANIZATION ||--o{ USER : "memiliki"
ORGANIZATION ||--o{ CONTACT : "memiliki"
ORGANIZATION ||--o{ EVENT : "mengelola"
ORGANIZATION ||--o{ WHATSAPP_CONNECTION : "mengonfigurasi"

EVENT ||--o{ EVENT_GUEST : "mendaftarkan"
EVENT ||--o{ WEDDING_CHECK_IN : "mencatat"
EVENT ||--o{ WEDDING_SOUVENIR_ITEM : "menyediakan"
EVENT ||--o{ WEDDING_SOUVENIR_PICKUP : "membagikan"
EVENT ||--o{ GUEST_MESSAGE_TEMPLATE : "mengatur"

CONTACT ||--o{ EVENT_GUEST : "terhubung"
EVENT_GUEST ||--o| WEDDING_CHECK_IN : "memiliki"
EVENT_GUEST ||--o{ WEDDING_SOUVENIR_PICKUP : "menerima"
WEDDING_SOUVENIR_ITEM ||--o{ WEDDING_SOUVENIR_PICKUP : "berkurang"
WEDDING_SOUVENIR_ITEM ||--o{ WEDDING_SOUVENIR_STOCK_ADJUSTMENT : "disesuaikan"

ORGANIZATION {
uuid id PK
string name
string slug
string status
}

CONTACT {
uuid id PK
uuid organization_id FK
string name
string phone
string email
}

EVENT {
uuid id PK
uuid organization_id FK
string title
string slug
string status
jsonb couple_details
jsonb ceremony_details
jsonb reception_details
jsonb operational_settings
}

EVENT_GUEST {
uuid id PK
uuid event_id FK
uuid contact_id FK
string category
string priority
string table_number
string session_name
int invitation_quota
int companion_count
int souvenir_allowance
int souvenir_claimed
string rsvp_status
string invitation_code UK
datetime whatsapp_opened_at
}

WEDDING_CHECK_IN {
uuid id PK
uuid event_id FK
uuid event_guest_id FK
string scan_method
int actual_pax
string device_info
datetime checked_in_at
}

WEDDING_SOUVENIR_ITEM {
uuid id PK
uuid event_id FK
string name
string sku
int initial_stock
int current_stock
int low_stock_threshold
boolean is_active
}

WEDDING_SOUVENIR_PICKUP {
uuid id PK
uuid event_id FK
uuid event_guest_id FK
uuid souvenir_item_id FK
int quantity
string client_operation_id UK
string status
datetime picked_up_at
}

WEDDING_SOUVENIR_STOCK_ADJUSTMENT {
uuid id PK
uuid souvenir_item_id FK
int adjustment_amount
string reason
datetime created_at
}

3. Isolasi Multi-Tenant & Keamanan Data

Sistem menerapkan model isolasi Shared Database, Multi-Tenant Scoping:

  1. Tenant Context Extraction: Setiap request yang melewati gateway divalidasi oleh middleware TenantResolver untuk mengekstrak tenant_id / organization_id dari JWT token.
  2. Query Scoping Otomatis: Semua operasi ORM GORM diwajibkan menggunakan klausa WHERE organization_id = ? dan WHERE event_id = ?.
  3. Pencegahan Akses Ilegal (IDOR): Pengguna dari Tenant A tidak akan dapat membaca atau memperbarui data milik Tenant B, meskipun mengetahui ID entitas secara langsung.

4. Mekanisme Konsistensi & Offline Reception Sync

Row-Level Locking Transaksional

Untuk mencegah kondisi balapan (race condition) saat ratusan tamu memindai QR secara bersamaan:

SELECT * FROM event_guests WHERE id = ? FOR UPDATE;
SELECT * FROM wedding_souvenir_items WHERE id = ? FOR UPDATE;

Operasi penyerahan souvenir dan check-in dibungkus dalam blok transaksi database PostgreSQL yang atomik.

Idempotensi Operasi (client_operation_id)

Setiap request penyerahan souvenir dan check-in menyertakan UUID unik client_operation_id dari frontend. Jika request terkirim ulang akibat gangguan jaringan, server mengenali ID tersebut dan mengembalikan status transaksi sebelumnya tanpa memproses duplikasi data.

Sinkronisasi Offline (Server-Authoritative)

  1. Saat perangkat bekerja offline, data transaksi check-in ditampung di penyimpanan lokal browser (IndexedDB).
  2. Ketika koneksi internet pulih, antrean dikirim ke server secara batch.
  3. Server memvalidasi stempel waktu (timestamp) dan memastikan hanya transaksi pertama yang diakui sebagai check-in sah, sementara pemindaian berikutnya dicatat sebagai duplikasi audit.