Tampilan
Arsitektur Sistem
Gaya arsitektur
Backend ATE menggunakan layered architecture klasik berbasis Express dengan pemisahan tanggung jawab:
| Layer | Lokasi | Tanggung jawab |
|---|---|---|
| Routes | routes/ | Definisi endpoint, pemasangan middleware, dokumentasi Swagger (JSDoc) |
| Controllers | controllers/ | Layer HTTP (req/res), memanggil service, membentuk response |
| Service | controllers/<fitur>/<aksi>/...Service.js | Logika bisnis, validasi Joi, orkestrasi integrasi |
| Repositories | repositories/ | Akses data Sequelize (query, join, transaksi) |
| Models | models/ | Definisi tabel & relasi Sequelize |
| Helpers | helpers/ | Wrapper integrasi eksternal & utilitas |
Pola folder controller
Setiap fitur biasanya berupa subfolder, mis. controllers/user/login/ berisi loginController.js (HTTP), loginService.js (logika + validasi), dan index.js (re-export). Pola yang sama dipakai untuk company, admin, biliings (perhatikan typo folder ini), dll.
Titik masuk aplikasi (entry points)
server.js— bootstrap: memuat env, memanggilcron.runnerJob()(saat ini stub kosong),app.listen(), dan menangani graceful shutdown (SIGTERM/SIGINT).app.js— membangun Express app, memasang middleware, dan me-mount 4 router.models/index.js— inisialisasi Sequelize, auto-load semua model dan asosiasinya.job-runner.js— loader untuk skrip job/cron di foldercron/(dijalankan sebagai proses terpisah).
Middleware chain (app.js)
| Mount point | File router | Isi |
|---|---|---|
/api/v1 | routes/index.js | API utama (user, admin, company, billing, domain, reports, dll.) |
/public | routes/publicRouter.js | Endpoint publik (download setup script) |
/callback | routes/callbackRoutes.js | Webhook SparkPost |
/api/internal | routes/internalRoutes.js | Endpoint internal (API key) |
Detail lengkap endpoint ada di Referensi API.
Bidang sinkron vs asinkron
Sistem memiliki dua "bidang" eksekusi:
- Sinkron: request HTTP ditangani langsung oleh proses web (PM2
backend-ate). - Asinkron: pekerjaan berat (kirim email, generate billing, sinkron domain) di-offload dengan cara:
- Menulis baris ke tabel
Jobs(statuson-queue) viarepositories/job.repository.js. - Men-spawn proses Node baru:
node job-runner.js <script> [jobId]melaluihelpers/cp.helper.js. - Skrip worker di
cron/mem-pollJobs, memprosesnya, lalu setdone/error.
- Menulis baris ke tabel
Penting untuk diketahui
- Bull/Redis tidak dipakai meskipun terpasang di
package.json. Queue asinkron sepenuhnya berbasis tabelJobs+ child process (fire-and-forget, tanpa backpressure). - Scheduler in-process non-aktif:
cron/scheduledFunctions/runnerJob.jsadalah stub kosong. Semua penjadwalan dilakukan eksternal (crontab VPS menjalankannpm run cron:*).
Lihat detail di Background Jobs & Cron.
Struktur folder tingkat atas
| Folder | Isi |
|---|---|
routes/ | Definisi endpoint Express (21 file) |
controllers/ | Controller + service per fitur |
repositories/ | Akses data Sequelize (~22 file) |
models/ | Model Sequelize (~29 model) |
migrations/ | Migrasi Sequelize (47 file) |
seeders/ | Seeder data awal |
helpers/ | Wrapper integrasi & utilitas (~31 file) |
middleware/ | Auth, RBAC, error handler, upload, dll. |
cron/ | Skrip job & cron (worker asinkron) |
callbacks/ | Handler webhook (SparkPost) |
views/ | Template Pug untuk email & halaman |
config/ | Konfigurasi Sequelize |
errors/ | Custom error classes |
utils/ | Utilitas umum |
public/ | Aset statis |
test/ | Unit & e2e test |
automation/ | TestCafe spec (Zoho OAuth) |
Penanganan error
express-async-errorsmembuatthrowdi handler async terpropagasi ke error handler global.middleware/error-handler.jsmenangani: error Multer, subclassCustomAPIError(mis.BadRequestError,UnauthenticatedErrordi foldererrors/), dan fallback 500.- Namun, banyak controller menangkap error secara lokal dan memanggil
response.failed(...)— sehingga pola penanganan error tidak konsisten di seluruh codebase (lihat Known Issues).