Skip to content

Arsitektur Sistem

Gaya arsitektur

Backend ATE menggunakan layered architecture klasik berbasis Express dengan pemisahan tanggung jawab:

LayerLokasiTanggung jawab
Routesroutes/Definisi endpoint, pemasangan middleware, dokumentasi Swagger (JSDoc)
Controllerscontrollers/Layer HTTP (req/res), memanggil service, membentuk response
Servicecontrollers/<fitur>/<aksi>/...Service.jsLogika bisnis, validasi Joi, orkestrasi integrasi
Repositoriesrepositories/Akses data Sequelize (query, join, transaksi)
Modelsmodels/Definisi tabel & relasi Sequelize
Helpershelpers/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, memanggil cron.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 folder cron/ (dijalankan sebagai proses terpisah).

Middleware chain (app.js)

Mount pointFile routerIsi
/api/v1routes/index.jsAPI utama (user, admin, company, billing, domain, reports, dll.)
/publicroutes/publicRouter.jsEndpoint publik (download setup script)
/callbackroutes/callbackRoutes.jsWebhook SparkPost
/api/internalroutes/internalRoutes.jsEndpoint 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:
    1. Menulis baris ke tabel Jobs (status on-queue) via repositories/job.repository.js.
    2. Men-spawn proses Node baru: node job-runner.js <script> [jobId] melalui helpers/cp.helper.js.
    3. Skrip worker di cron/ mem-poll Jobs, memprosesnya, lalu set done/error.

Penting untuk diketahui

  • Bull/Redis tidak dipakai meskipun terpasang di package.json. Queue asinkron sepenuhnya berbasis tabel Jobs + child process (fire-and-forget, tanpa backpressure).
  • Scheduler in-process non-aktif: cron/scheduledFunctions/runnerJob.js adalah stub kosong. Semua penjadwalan dilakukan eksternal (crontab VPS menjalankan npm run cron:*).

Lihat detail di Background Jobs & Cron.

Struktur folder tingkat atas

FolderIsi
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-errors membuat throw di handler async terpropagasi ke error handler global.
  • middleware/error-handler.js menangani: error Multer, subclass CustomAPIError (mis. BadRequestError, UnauthenticatedError di folder errors/), 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).