# PRD — Wavora ## 1. Ringkasan Produk **Nama aplikasi:** Wavora **Tagline:** WhatsApp Gateway SaaS untuk bisnis, notifikasi, automation, dan integrasi aplikasi. Wavora adalah aplikasi SaaS multi-tenant untuk mengelola koneksi WhatsApp multi-device, mengirim pesan via API, mengelola device, webhook, log pesan, retry queue, serta menyediakan dashboard admin bagi tenant. Core WhatsApp engine memakai GOWA (`aldinokemal/go-whatsapp-web-multidevice`) sebagai service backend WhatsApp. Produk ini bukan pengganti WhatsApp Business API resmi. Wavora diposisikan sebagai gateway operasional untuk sistem internal, UMKM, aplikasi kos/CRM/ERP, automation, dan integrasi notifikasi. ## 2. Tujuan - Menyediakan platform WA gateway siap pakai berbasis subscription/SaaS. - Tenant bisa punya satu atau beberapa device WhatsApp. - Developer tenant bisa mengirim pesan via REST API dengan API key. - Tenant bisa memantau status device, QR login/pairing code, log pesan, webhook, dan kuota. - Sistem punya queue async + retry agar pengiriman stabil. - Admin platform bisa mengelola tenant, paket, limit, billing, abuse control, dan monitoring. ## 3. Nama Alternatif Jika nanti ingin opsi branding lain: - **Wavora** — utama; WA + aura; terdengar SaaS modern. - **Pesanika** — lokal, mudah diingat. - **Kirimwa** — sangat jelas, SEO-friendly. - **Wazala** — pendek, unik. - **Notifwa** — fokus notifikasi. Rekomendasi: **Wavora**. ## 4. Target Pengguna ### 4.1 Tenant Owner Pemilik bisnis/produk yang butuh integrasi WA untuk notifikasi, customer support, OTP ringan, reminder, dan automation. ### 4.2 Developer Tenant Developer yang memakai API Wavora untuk mengirim pesan dari aplikasi internal. ### 4.3 Operator/CS Tim yang memantau pesan, device status, delivery log, dan reconnect device. ### 4.4 Platform Admin Pengelola SaaS Wavora: mengatur tenant, paket, billing, kuota, abuse/rate limit, dan kesehatan server. ## 5. Scope MVP ### 5.1 Public Website - Landing page. - Pricing page. - Login/register. - Dokumentasi API dasar. - Status page sederhana. ### 5.2 Auth & Tenant - Register tenant. - Login/logout. - Captcha 4 digit untuk form sebelum auth. - Email/username + password. - Role minimal: - platform_admin - tenant_owner - tenant_admin - tenant_operator - tenant_developer - Tenant isolation wajib. ### 5.3 Dashboard Tenant - Ringkasan: - jumlah device - device online/offline - pesan hari ini - pesan gagal - kuota tersisa - Device management: - tambah device slot - QR login - pairing code login - status device - reconnect - logout - remove device - API key management: - create/revoke API key - label key - permission/scope key - last used timestamp - Send message manual: - text - image - file - video - audio - sticker - contact - location - Message logs: - filter status/date/device/recipient - retry failed - detail request/response sanitized - Webhook settings: - endpoint URL - secret - event filter - test webhook - retry history ### 5.4 Platform Admin - Tenant list. - Tenant detail. - Suspend/activate tenant. - Paket/subscription. - Pengaturan billing global (DOKU, fee, expiry, instruksi transfer). - Verifikasi pembayaran manual (QRIS helper & transfer bank). - Global device status. - Global message throughput. - Error logs. - Abuse/rate-limit monitor. ### 5.5 Paket SaaS, Billing & Subscription Wavora wajib punya sistem paket SaaS yang bisa dikonfigurasi admin tanpa edit kode. ### 5.5.0 Rules Per WhatsApp Number/Device - Setiap WhatsApp number/device **wajib** punya paket SaaS aktif. - Saat device/number ditambahkan → otomatis assign paket default: **Free** (kecuali admin set lain). - Aktivasi paket berbayar dilakukan **per device/number** (bukan hanya per tenant global). - Jika paket device `inactive/expired/past_due/suspended` → API send untuk device tsb ditolak. ### 5.5.0.1 Free Plan Requirements - Free plan limit: **300 pesan/hari per WhatsApp number/device**. - Free plan wajib menambahkan **footer/branding mandatory** pada pesan keluar: - berlaku untuk outgoing **text** dan **caption media** (image/video/file) jika field caption ada. - tidak boleh bisa dimatikan oleh tenant. - contoh (placeholder): `\n\n— Sent via Wavora`. #### 5.5.1 Paket SaaS Admin platform bisa membuat dan mengatur paket: - nama paket - kode paket - harga bulanan - harga tahunan opsional - jumlah device maksimal - kuota pesan bulanan - limit API key - limit webhook endpoint - akses fitur: queue, webhook, media, group API, Chatwoot, dedicated node - status aktif/nonaktif - urutan tampil di pricing page Contoh paket awal: | Paket | Device | Kuota Pesan/Bulan | API Key | Webhook | Catatan | |---|---:|---:|---:|---:|---| | Starter | 1 | 5.000 | 2 | 1 | UMKM kecil/dev | | Growth | 3 | 25.000 | 5 | 3 | bisnis aktif | | Business | 10 | 100.000 | 15 | 10 | operasional besar | | Custom | custom | custom | custom | custom | dedicated/support khusus | Rules: - Limit paket dicek saat tambah device, create API key, create webhook, dan kirim pesan. - Jika kuota habis → request kirim pesan ditolak atau masuk pending sesuai setting admin. - Jika subscription expired/past_due → device tetap tersimpan, tapi pengiriman API diblokir. - Admin bisa override limit per tenant. #### 5.5.2 Subscription Lifecycle Status subscription: - `trial` - `active` - `past_due` - `suspended` - `cancelled` - `expired` Flow normal: ```text trial → active → active renewed active → past_due → suspended → expired active → cancelled ``` Rules: - Invoice dibuat otomatis per periode billing. - Tenant melihat paket aktif, kuota, masa aktif, invoice, dan riwayat pembayaran. - Upgrade paket membuat invoice prorata opsional; untuk MVP boleh full-cycle/manual adjustment. - Downgrade efektif periode berikutnya, kecuali admin override. #### 5.5.3 Metode Pembayaran MVP mendukung tiga metode bayar: 1. **DOKU Hosted Checkout** - Tenant klik bayar. - Sistem buat payment intent/order ke DOKU. - Tenant diarahkan ke hosted checkout. - DOKU callback/webhook mengubah status payment. - Callback wajib validasi signature dan idempotent. 2. **QRIS Manual Helper** - Admin platform menyimpan QRIS statis/platform. - Sistem generate QRIS nominal dinamis sesuai invoice jika payload valid. - Tenant scan QRIS dan upload bukti bayar. - Admin verifikasi manual sebelum invoice paid. - Ini bukan payment gateway; tidak ada auto-paid tanpa verifikasi. 3. **Transfer Bank Manual** - Admin set nama bank, nomor rekening, nama rekening, instruksi. - Tenant upload bukti transfer. - Admin approve/reject manual. #### 5.5.4 Biaya Layanan Invoice harus mendukung biaya tambahan: - `subtotal` = harga paket/add-on. - `service_fee` = biaya layanan/platform fee. - `admin_fee` = biaya admin channel/gateway fee. - `grand_total` = subtotal + service_fee + admin_fee. Fee setting: - flat nominal. - persentase dari subtotal. - bisa global default. - bisa override per tenant. Rules: - Fee dihitung dan disimpan saat invoice diterbitkan. - Invoice lama tidak boleh berubah jika setting fee berubah. - Semua nominal dibulatkan ke rupiah integer untuk QRIS/transfer. #### 5.5.5 Invoice Lifecycle Status invoice: ```text draft → issued → pending_payment → paid ↘ expired ↘ cancelled ``` Rules: - `draft`: invoice belum dikirim/ditampilkan final. - `issued`: invoice resmi sudah dibuat. - `pending_payment`: tenant sudah memilih metode bayar/payment intent dibuat. - `paid`: pembayaran valid. - `expired`: melewati due date. - `cancelled`: dibatalkan admin/sistem. #### 5.5.6 Payment Lifecycle Status payment: ```text pending → waiting_verification → verified ↘ rejected pending → expired ``` Rules: - DOKU bisa langsung `verified` jika callback valid. - QRIS manual dan transfer manual harus `waiting_verification` sampai admin approve. - Reject wajib menyimpan alasan. - Semua perubahan status masuk audit log. #### 5.5.7 Billing Admin Requirement Admin platform bisa: - CRUD paket. - Atur harga dan limit paket. - Atur DOKU credential di environment/config aman. - Atur QRIS platform/manual helper. - Atur rekening transfer manual. - Atur service fee dan admin fee global/per tenant. - Melihat invoice semua tenant. - Melihat antrean pembayaran manual. - Approve/reject bukti bayar. - Suspend/unsuspend tenant. - Override kuota/limit tenant. ### 5.6 API Gateway Wavora Wavora menyediakan API sendiri di depan GOWA. Tenant **tidak langsung** mengakses Basic Auth GOWA. Contoh endpoint MVP: - `GET /api/v1/devices` - `POST /api/v1/devices` - `GET /api/v1/devices/{id}` - `POST /api/v1/devices/{id}/login-qr` - `POST /api/v1/devices/{id}/login-code` - `POST /api/v1/devices/{id}/reconnect` - `POST /api/v1/devices/{id}/logout` - `DELETE /api/v1/devices/{id}` - `POST /api/v1/messages/text` - `POST /api/v1/messages/image` - `POST /api/v1/messages/file` - `POST /api/v1/messages/video` - `POST /api/v1/messages/audio` - `GET /api/v1/messages/{id}` - `GET /api/v1/message-logs` - `POST /api/v1/webhooks/test` Auth tenant API: ```http Authorization: Bearer X-Tenant-Id: ``` ## 6. Core GOWA Reference Core engine memakai OpenAPI GOWA dari repo: `https://github.com/aldinokemal/go-whatsapp-web-multidevice` OpenAPI source: `docs/openapi.yaml` ### 6.1 GOWA Core Tags - `app` — initial WhatsApp connection. - `device` — multi-device management. - `user` — user/contact info. - `send` — send text/image/file/video/audio/etc. - `message` — revoke/react/update/read/star/download. - `chat` — chats and messages. - `group` — group management. - `newsletter` — newsletter setting. - `chatwoot` — Chatwoot integration. ### 6.2 GOWA Device Scope Rule GOWA v8 requires device scoping for device-specific REST calls: - header: `X-Device-Id: ` - or query: `device_id=` - websocket: `/ws?device_id=` Wavora must map tenant device UUID/internal ID to GOWA `device_id` safely. ### 6.3 GOWA Endpoint Coverage for MVP MVP Wavora wraps these GOWA capabilities: **App/device connection** - `GET /app/status` - `GET /devices` - `POST /devices` - `GET /devices/{device_id}` - `DELETE /devices/{device_id}` - `GET /devices/{device_id}/login` - `POST /devices/{device_id}/login/code` - `POST /devices/{device_id}/logout` - `POST /devices/{device_id}/reconnect` - `GET /devices/{device_id}/status` **Send** - `POST /send/message` - `POST /send/image` - `POST /send/audio` - `POST /send/file` - `POST /send/sticker` - `POST /send/video` - `POST /send/contact` - `POST /send/link` - `POST /send/location` - `POST /send/poll` - `POST /send/presence` - `POST /send/chat-presence` **Message** - `POST /message/{message_id}/revoke` - `POST /message/{message_id}/delete` - `POST /message/{message_id}/reaction` - `POST /message/{message_id}/update` - `POST /message/{message_id}/read` - `GET /message/{message_id}/download` **Chat/user** - `GET /chats` - `GET /chat/{chat_jid}/messages` - `GET /user/info` - `GET /user/check` - `GET /user/avatar` - `GET /user/my/contacts` - `GET /user/my/groups` Group/newsletter/chatwoot can be phase 2 unless needed early. ## 7. Arsitektur Teknis ### 7.0 Default Async Send Behavior - Default: API send message jalan **async/background**. - API harus cepat merespons **`202 Accepted`** + `message_id/job_id`. - Queue/worker yang melakukan send ke GOWA belakangan. - Mode **sync/live** hanya opsional untuk admin/dev (fallback) saat worker/cron bermasalah. ### 7.1 Stack Dasar Mengikuti Aturan Coding Claw dari Notes.app: - PHP 7.4. - MySQL 8. - Tanpa framework berat; routing manual via `index.php` front controller. - TailwindCSS CDN + Parker CSS. - SweetAlert2 untuk alert/flash. - Clean URLs. - Mobile-first. ### 7.2 Service Layout ```text User Browser / Tenant App ↓ Wavora SaaS App (PHP) ↓ Wavora Queue / Cron Worker ↓ GOWA Container(s) ↓ WhatsApp Web Multi Device ``` MVP bisa memakai satu GOWA instance dulu, lalu phase 2 mendukung multiple GOWA nodes/shards. ### 7.3 Deployment MVP - App PHP: MAMP/cPanel-compatible. - DB: MySQL 8. - GOWA: Docker container. - Storage: persistent Docker volume for GOWA `/app/storages`. - Cron: unified runner. ### 7.4 Cron & Queue Rule Mengikuti aturan Notes.app: - Gunakan satu entry point: `cron/run.php --task=nama-task`. - Task minimal: - `wa-queue` - `webhook-retry` - `device-health` - `billing-check` - `cleanup` - Heartbeat: `/tmp/wavora_cron_heartbeat`. - Disable flag: `/tmp/wavora_cron_disabled`. - Jika cron aktif → kirim via queue async. - Jika cron mati → fallback live untuk traffic rendah/dev. Rule: ```text heartbeat < 120 detik → queue async heartbeat tidak ada/lama → live fallback ``` ## 8. Database Design ### 8.1 Naming Rule - `m_` = master tables. - `t_` = transaction tables. - ID: `CHAR(36)` UUID. - Migration: `database/migrations/YYYY_MM_DD_HHmm_deskripsi.sql`. - Backup: `database/backups/`. ### 8.2 Core Tables MVP **Auth & Permission** - `m_user` - `m_group` - `m_module` - `m_module_action` - `m_rule` - `m_user_token` **Tenant** - `m_tenant` - `m_tenant_user` - `m_tenant_setting` - `m_tenant_billing_setting` - `m_plan` - `m_subscription` **API & Device** - `m_api_key` - `m_wa_device` - `m_wa_gateway_node` - `m_webhook_endpoint` **Transactions** - `t_wa_message` - `t_wa_message_log` - `t_wa_queue` - `t_webhook_event` - `t_webhook_delivery` - `t_usage_daily` - `t_billing_invoice` - `t_billing_payment` - `t_billing_payment_proof` - `t_billing_transaction` - `t_audit_log` ### 8.3 Important Fields `m_wa_device` - `id CHAR(36)` - `tenant_id CHAR(36)` - `gateway_node_id CHAR(36)` - `gowa_device_id VARCHAR(191)` - `label VARCHAR(100)` - `phone VARCHAR(30)` - `status ENUM('pending','qr','connected','disconnected','logged_out','error')` - `last_seen_at DATETIME NULL` - `created_at DATETIME` - `updated_at DATETIME` `t_wa_queue` - `id CHAR(36)` - `tenant_id CHAR(36)` - `device_id CHAR(36)` - `message_type VARCHAR(30)` - `recipient VARCHAR(50)` - `payload_json JSON/TEXT` - `status ENUM('pending','processing','sent','failed','cancelled')` - `attempt_count INT` - `next_attempt_at DATETIME` - `last_error TEXT NULL` - `created_at DATETIME` - `updated_at DATETIME` `t_wa_message_log` - request/response sanitized. - no full secrets. - no raw credentials. - store message_id from GOWA/WA if available. `t_billing_invoice` - `id CHAR(36)` - `tenant_id CHAR(36)` - `plan_id CHAR(36)` - `subscription_id CHAR(36) NULL` - `invoice_no VARCHAR(64)` - `period_start DATE` - `period_end DATE` - `subtotal DECIMAL(14,2)` - `service_fee DECIMAL(14,2)` - `admin_fee DECIMAL(14,2)` - `grand_total DECIMAL(14,2)` - `status ENUM('draft','issued','pending_payment','paid','expired','cancelled')` - `due_at DATETIME` - `paid_at DATETIME NULL` - `created_at DATETIME` - `updated_at DATETIME` `t_billing_payment` - `id CHAR(36)` - `tenant_id CHAR(36)` - `invoice_id CHAR(36)` - `method ENUM('doku_hosted_checkout','qris_manual','bank_transfer_manual')` - `channel_code VARCHAR(50)` - `amount DECIMAL(14,2)` - `external_ref VARCHAR(191) NULL` - `status ENUM('pending','waiting_verification','verified','rejected','expired')` - `paid_at DATETIME NULL` - `verified_at DATETIME NULL` - `verified_by CHAR(36) NULL` - `reject_reason TEXT NULL` - `created_at DATETIME` - `updated_at DATETIME` `m_tenant_billing_setting` - `id CHAR(36)` - `tenant_id CHAR(36)` - `is_auto_billing TINYINT(1)` - `invoice_due_days INT` - `service_fee_type ENUM('flat','percent')` - `service_fee_value DECIMAL(14,2)` - `admin_fee_type ENUM('flat','percent')` - `admin_fee_value DECIMAL(14,2)` - `qris_helper_name VARCHAR(100) NULL` - `qris_helper_phone VARCHAR(30) NULL` - `bank_account_name VARCHAR(100) NULL` - `bank_name VARCHAR(100) NULL` - `bank_account_number VARCHAR(50) NULL` - `created_at DATETIME` - `updated_at DATETIME` ## 9. Permission Modules BRAC modules: - `dashboard` - `tenants` - `users` - `roles` - `plans` - `subscriptions` - `wa_devices` - `wa_messages` - `wa_logs` - `api_keys` - `webhooks` - `billing` - `settings` - `audit_logs` - `system_health` Actions: - `view` - `create` - `update` - `delete` - `send` - `retry` - `reconnect` - `logout` - `export` - `manage` Access check: ```php Auth::hasAccess('wa_devices', 'reconnect') ``` ## 10. UX Requirement ### 10.1 Design Parker design tokens: - Off-black: `#1b1d20` - White: `#ffffff` - Border: `#e1dfd8` - Blue accent: `#5196fe` - Orange accent: `#f9754e` - Ash gray bg: `#f2f1ec` - Font: Inter + Gambetta if available. - Mobile-first. ### 10.2 Key Screens Tenant: 1. Login/Register. 2. Tenant dashboard. 3. Device list. 4. Device detail + QR/pairing code. 5. Send message manual. 6. Message logs. 7. API keys. 8. Webhooks. 9. Usage/quota. 10. Paket aktif & subscription. 11. Invoice list/detail. 12. Payment page: DOKU, QRIS manual, transfer bank. 13. Upload bukti bayar. 14. Settings. Platform Admin: 1. Admin dashboard. 2. Tenant management. 3. Plans/subscription. 4. Payment settings: DOKU, QRIS, transfer, fee. 5. Invoice management. 6. Manual payment verification queue. 7. Global devices. 8. Global logs. 9. Queue monitor. 10. System health. ## 11. Security Requirements Mengikuti Aturan Coding Claw: - Semua SQL pakai prepared statement. - Semua output pakai `e()` / `htmlspecialchars`. - Semua POST pakai CSRF: `Auth::checkToken()` + `csrf_field()`. - Password pakai `password_hash(PASSWORD_BCRYPT)` dan `password_verify()`. - Session ID regenerate after login. - Cookie `httponly`; `secure` jika HTTPS. - Form sebelum auth wajib captcha gambar 4 digit. - File upload validasi tipe, ekstensi, ukuran. - Upload media client-side compress jika gambar. - Jangan expose stack trace. - Security headers: - `X-Frame-Options: DENY` - `X-Content-Type-Options: nosniff` - API key disimpan hashed, tampilkan plain hanya saat dibuat. - GOWA Basic Auth/secret tidak diekspos ke tenant. - Tenant isolation di setiap query wajib filter `tenant_id`. - Rate limit per tenant, per API key, per device. - Audit log untuk action sensitif. ## 12. Rate Limit & Abuse Control MVP: - Limit pesan per menit per tenant. - Limit pesan per hari sesuai plan. - Limit device per plan. - Cooldown reconnect/login QR. - Blocklist recipient optional. - Detect repeated failed sends. - Suspend tenant jika abuse. Plan example: - Starter: 1 device, 5k msg/month. - Growth: 3 devices, 25k msg/month. - Business: 10 devices, 100k msg/month. - Custom: dedicated node/shard. ## 13. Webhook Tenant bisa menerima event dari Wavora: - `message.sent` - `message.failed` - `message.received` - `message.ack` - `device.connected` - `device.disconnected` - `device.logged_out` - `queue.failed` Webhook delivery: - HMAC signature. - Retry exponential backoff. - Delivery log. - Test webhook button. - Disable webhook otomatis jika gagal terus. ## 14. Observability - Dashboard queue depth. - Device connection status. - Per-tenant usage daily. - GOWA node health. - Failed message rate. - Webhook failed rate. - Cron heartbeat status. - Error logs sanitized. Optional infra: - Netdata for host health. - Uptime Kuma for service uptime. - Claw daily health snapshot. ## 15. Non-Goals MVP - Tidak membangun WhatsApp protocol sendiri. - Tidak mengganti GOWA core. - Tidak menjanjikan official WhatsApp Business API compliance. - Tidak auto-spam/blast unlimited. - Tidak expose raw GOWA credentials. - Tidak multi-region di MVP. - Tidak built-in CRM penuh di MVP. ## 16. Acceptance Criteria MVP ### 16.1 Acceptance Criteria Tambahan (Plan/Branding/Async) - Free plan enforce **300 pesan/hari/device**. - Outgoing text/caption pada free plan otomatis append footer/branding mandatory. - Setiap device punya paket aktif; saat add device default paket **Free** ter-assign. - Paket berbayar bisa diaktifkan **per device**. - API send default async → respon `202 Accepted` + `job_id/message_id`. - Worker memproses queue dan update status `sent/failed` + retry. - Sync/live mode hanya untuk admin/dev fallback dan ter-audit. - Tenant bisa register/login dengan captcha. - Tenant bisa membuat device slot. - Tenant bisa login device via QR/pairing code. - Tenant bisa melihat status connected/disconnected. - Tenant bisa generate API key. - Tenant bisa kirim text message via API. - Tenant bisa kirim media dasar via API/manual UI. - Semua send tercatat di `t_wa_message_log`. - Queue async berjalan jika cron aktif. - Fallback live berjalan jika cron mati. - Webhook event terkirim dan tercatat. - Admin bisa suspend tenant. - Rate limit per plan bekerja. - Tenant bisa melihat paket aktif, invoice, dan status pembayaran. - Admin bisa CRUD paket SaaS dan set limit/kuota. - Invoice menghitung subtotal + service fee + admin fee dengan benar. - DOKU Hosted Checkout bisa membuat payment intent dan menerima callback valid. - QRIS manual dan transfer bank masuk antrean verifikasi manual. - Admin bisa approve/reject bukti bayar dan audit log tercatat. - Tenant tidak bisa akses data tenant lain. - Lint/test basic pass sebelum deploy. ## 17. Coding Workflow Aturan kerja: - Claw tidak hand-coding langsung saat Kakak bilang coding/kerjakan. - Coding ringan: pakai opencode. - Fitur/refactor besar: pakai sub-agent/opencode. - Progress wajib dilaporkan: checking → running → editing → testing → done/blocker. - Lint PHP dulu sebelum commit. - Review diff sebelum final. ## 18. API & Admin Requirement (Billing) - API tenant wajib bisa: - lihat paket aktif dan kuota billing. - lihat list invoice + detail invoice. - buat payment intent DOKU Hosted Checkout. - submit bukti bayar untuk QRIS manual/transfer manual. - API admin wajib bisa: - list payment pending verifikasi. - approve/reject verifikasi manual. - set service/admin fee per tenant. - set helper QRIS dan rekening transfer tenant. - Webhook payment (DOKU callback) harus: - validasi signature. - idempotent by `external_ref`. - update lifecycle invoice/payment secara atomik. ## 19. Open Questions - Nama final tetap **Wavora** atau mau pilih alternatif? - Domain produk apa? - MVP target single GOWA node dulu atau langsung multi-node? - DOKU dipakai langsung MVP atau setelah manual payment stabil? - QRIS manual pakai QRIS platform saja atau per tenant juga nanti? - Biaya layanan ditanggung tenant sebagai tambahan invoice atau diserap platform? - Tenant signup public atau approval manual? - Perlu Chatwoot integration di MVP atau phase 2? - Perlu group/newsletter API di MVP atau phase 2?