Skip to content

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

Codeverta Relay

Platform email self-hosted (Go + React + MariaDB) yang menggabungkan mail server multi-domain ala cPanel dan Sending API ala Amazon SES/Postmark dalam satu binary cvrelay. Lisensi MIT.

Status: v0.1, irisan pertama MVP: Fondasi + Sending API. Mail server (SMTP inbound :25, IMAP/POP3, Sieve) belum ada; lihat Roadmap.

Yang sudah jalan

Area Isi
Multi-tenant Tenant, kuota harian, pause, isolasi data per tenant_id di setiap query (dites)
API key cv_live_ / cv_test_, scope, batasan stream dan IP, disimpan sebagai hash
Domain DNS wizard (DKIM RSA-2048 + Ed25519, SPF, return-path, DMARC, MX), verifikasi DNS, rotasi DKIM dengan overlap 48 jam
Sending API POST /v1/messages, batch 500, template, lampiran, scheduled_at + batal, Idempotency-Key 24 jam, mode test
Antrean & MTA Antrean per Recipient di MariaDB (FOR UPDATE SKIP LOCKED + lease), prioritas transactional, MX lookup + fallback A, null MX, TLS oportunistik, DKIM dual signing, VERP return-path
Retry & bounce 1m, 5m, 15m, 30m, 1j, 2j, 4j, lalu tiap 4 jam sampai 5 hari; klasifikasi hard/soft/block/mailbox_full/policy; hard bounce masuk suppression
Suppression Per tenant + global, manual, hard bounce, one-click unsubscribe (RFC 8058) untuk stream broadcast
Event & webhook queued, sent, deferred, bounced, rejected, unsubscribed; webhook HMAC-SHA256, retry sampai 24 jam, dead-letter, replay, proteksi SSRF
Panel React console (embed di binary) untuk tim Codeverta: tenant, domain & DNS, aktivitas + timeline, template + preview, API key, webhook, suppression

Mulai cepat (Docker)

cp .env.example .env
docker compose run --rm cvrelay ctl genkey     # isi ke CVRELAY_MASTER_KEY
# isi juga CVRELAY_ADMIN_TOKEN, password MariaDB, domain platform
docker compose up -d
open http://localhost:8080                      # login dengan CVRELAY_ADMIN_TOKEN

Membuat tenant dan API key lewat CLI:

docker compose exec cvrelay cvrelay ctl tenant create "Toko ABC"
docker compose exec cvrelay cvrelay ctl apikey create tnt_01J... --scopes=send,read_logs

Kirim email

curl https://relay.codeverta.com/v1/messages \
  -H "Authorization: Bearer cv_live_..." \
  -H "Idempotency-Key: order-12345-receipt" \
  -H "Content-Type: application/json" \
  -d '{
    "from": "Toko ABC <no-reply@tokoabc.id>",
    "to": ["budi@example.com"],
    "subject": "Invoice #12345",
    "html": "<p>Halo Budi, total Rp 250.000</p>",
    "tags": ["invoice"],
    "metadata": {"order_id": "12345"}
  }'
# 202 {"id":"msg_01J...","status":"queued"}

Spesifikasi lengkap: api/openapi.yaml.

Verifikasi webhook

Setiap POST membawa X-CV-Timestamp (unix) dan X-CV-Signature: v1=<hex>, di mana hex = HMAC-SHA256(secret, "<timestamp>.<body>"). Tolak jika timestamp lebih dari 5 menit.

import crypto from "node:crypto";
const expected = "v1=" + crypto.createHmac("sha256", secret).update(`${ts}.${rawBody}`).digest("hex");
const ok = crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(signature));

Pengembangan

Kebutuhan: Go 1.24+, Node 22+, MariaDB 10.6+ (11.4 disarankan).

# MariaDB lokal untuk tes integrasi: user butuh hak CREATE/DROP DATABASE
mysql -uroot -e "CREATE USER 'cvrelay'@'%' IDENTIFIED BY 'cvrelay'; GRANT ALL ON *.* TO 'cvrelay'@'%';"

make test        # go test -race ./... dengan MariaDB sungguhan
make build       # build React lalu binary bin/cvrelay
cd web && npm run dev   # UI dev server, /v1 diproksi ke :8080

Tes integrasi membuat database sekali pakai per tes (internal/testkit); tanpa CVRELAY_TEST_DSN tes tersebut dilewati.

Cara kode ini dibangun

Dibangun dengan skill mattpocock/skills:

  • domain-modeling: glosarium di CONTEXT.md dan keputusan di docs/adr/. Pakai istilah di glosarium (Tenant, Recipient, Suppression, ...) di kode, tes, dan diskusi.
  • tdd: tes hanya di empat seam yang disepakati, lewat interface publik, bukan internals:
    1. REST API v1 (internal/api/*_test.go): httptest ke router asli + MariaDB asli.
    2. Delivery worker (internal/delivery/delivery_test.go): worker mengirim ke MX palsu (go-smtp in-process), DKIM diverifikasi independen.
    3. Modul murni: retry, bounce, webhook signer, dkim, mime, secret.
    4. Webhook dispatcher (internal/webhook/dispatcher_test.go): penerima httptest memverifikasi signature.

Struktur

cmd/cvrelay/        binary: serve, migrate, ctl
internal/
  app/              composition root (merakit semua layanan)
  api/              REST API v1 + tes seam API
  sending/          menerima permintaan kirim, log pengiriman
  delivery/         MTA keluar: klaim antrean, DKIM, SMTP, retry, bounce, unsubscribe
  webhook/          signer, CRUD webhook, dispatcher
  domain/  tenant/  template/  suppression/  events/
  dkim/  mime/  bounce/  retry/  secret/  blob/  dnsx/  store/  id/
  testkit/          DB sekali pakai, DNS palsu, MX palsu, jam palsu
migrations/         skema MariaDB (di-embed)
web/                React console (Vite + TanStack Query + Tailwind)
api/openapi.yaml
docs/adr/

Penyimpangan dari spesifikasi awal

  • MariaDB, bukan PostgreSQL (ADR 0001): tanpa RLS, jadi isolasi tenant ditegakkan di repository dan dites.
  • Satu SPA untuk admin + tenant console (ADR 0004).
  • Router chi ditulis tangan, belum di-generate dari OpenAPI; migrasi memakai runner kecil sendiri (goose terbaru butuh Go 1.26).
  • Event delivered belum dikirim terpisah; untuk SMTP keluar sent sudah berarti diterima MX tujuan.

Roadmap

Irisan berikut, kira-kira urut prioritas:

  1. SMTP relay (submission 587/465, user apikey) untuk Laravel/WordPress/Nodemailer.
  2. Pemroses bounce async (DSN via VERP) dan complaint (ARF/FBL), auto-pause tenant pada bounce > 5% / complaint > 0,1%.
  3. Integrasi API Cloudflare untuk membuat record DNS otomatis + cek DNS terjadwal tiap 10 menit.
  4. Throttling adaptif per provider, warmup IP, relay fallback (smart host), monitoring blocklist.
  5. Mail server: SMTP inbound :25, mailbox store, IMAP/POP3 (go-imap/v2), ManageSieve, import IMAP.
  6. Observability: /metrics Prometheus, OpenTelemetry, ACME/TLS bawaan.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages