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:
- Tenant Context Extraction: Setiap request yang melewati gateway divalidasi oleh middleware
TenantResolveruntuk mengekstraktenant_id/organization_iddari JWT token. - Query Scoping Otomatis: Semua operasi ORM GORM diwajibkan menggunakan klausa
WHERE organization_id = ?danWHERE event_id = ?. - 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)
- Saat perangkat bekerja offline, data transaksi check-in ditampung di penyimpanan lokal browser (IndexedDB).
- Ketika koneksi internet pulih, antrean dikirim ke server secara batch.
- Server memvalidasi stempel waktu (timestamp) dan memastikan hanya transaksi pertama yang diakui sebagai check-in sah, sementara pemindaian berikutnya dicatat sebagai duplikasi audit.