2. SQL Injection Protection
Legacy application sering memiliki query seperti:
$sql = "SELECT * FROM leads WHERE email='$email'";
Jika input berasal langsung dari HTTP request, pola tersebut dapat membuka SQL Injection vulnerability.
Versi modern akan menggunakan:
$stmt = $pdo->prepare(
'SELECT * FROM leads WHERE email = :email'
);
$stmt->execute([
'email' => $email
]);
Semua query yang menerima input eksternal harus mengikuti pendekatan serupa.
Targetnya sederhana:
Tidak ada lagi user input yang langsung digabungkan ke SQL statement.
3. Menghapus Hardcoded Credentials
Salah satu technical debt yang umum ditemukan pada aplikasi legacy adalah konfigurasi seperti:
$dbUser = 'root';
$dbPassword = 'password';
atau bahkan admin credentials yang tersimpan langsung dalam source code.
Pendekatan ini tidak cocok untuk repository modern, terlebih jika project nantinya menjadi open source.
Arsitektur konfigurasi akan diubah menjadi:
Environment Variables
│
▼
Application Config
│
▼
Application
Contohnya:
DB_HOST=localhost
DB_DATABASE=autoresponder
DB_USERNAME=autoresponder
DB_PASSWORD=
MAIL_DRIVER=smtp
SMTP_HOST=
SMTP_USERNAME=
SMTP_PASSWORD=
Repository hanya akan menyediakan:
.env.example
sedangkan:
.env
akan dimasukkan ke .gitignore.
Dengan model seperti ini aplikasi dapat dijalankan pada:
development
staging
production
Docker
VPS
cloud environment
tanpa mengubah source code.
4. Password Hashing dan Authentication
Legacy authentication sering menggunakan pola sederhana:
if ($username === $adminUser &&
$password === $adminPassword) {
}
Versi baru tidak akan menyimpan password dalam plaintext.
PHP sudah menyediakan:
password_hash()
password_verify()
Contoh:
$passwordHash = password_hash(
$password,
PASSWORD_DEFAULT
);
dan login:
if (password_verify(
$password,
$storedHash
)) {
// authenticated
}
Selain itu session management juga akan diperbaiki dengan:
HttpOnly cookies
Secure cookies
SameSite
session_regenerate_id()
session timeout
5. CSRF dan XSS Protection
Aplikasi legacy sering mengandalkan HTML form sederhana.
Misalnya:
Add Lead
Delete Lead
Create Message
Edit Message
Semua operasi tersebut akan dilindungi dengan CSRF token.
Secara konseptual:
Browser
│
▼
Form + CSRF Token
│
▼
Server
│
├── validate session
├── validate CSRF
└── execute request
Untuk mencegah Cross-Site Scripting, setiap user-generated output juga harus di-escape.
Contohnya:
htmlspecialchars(
$value,
ENT_QUOTES,
'UTF-8'
);
6. Modern Unsubscribe Mechanism
Versi legacy menggunakan identifier lead seperti:
unsubscribe.php?id=10&email=user@example.com
Pendekatan ini terlalu mudah ditebak.
Versi modern akan menggunakan token:
unsubscribe.php?token=<random-token>
Token dapat berupa random cryptographically secure value atau signed HMAC token.
Selain itu unsubscribe tidak seharusnya langsung menghapus lead.
Lebih baik menyimpan:
status = unsubscribed
unsubscribed_at = timestamp
Dengan demikian sistem memiliki:
audit trail
suppression list
compliance history
campaign analytics
7. Menggantikan PHP mail()
Versi lama menggunakan:
mail();
Untuk project modern, pengiriman email akan menggunakan transport abstraction.
Target awalnya:
SMTP
Amazon SES
Arsitekturnya:
Application
│
▼
Mail Transport Interface
│
├───────────────┐
▼ ▼
SMTP Amazon SES
Dengan model ini aplikasi tidak bergantung pada satu provider.
Inilah dasar dari prinsip:
No vendor lock-in.
Pada masa depan transport tambahan juga dapat dibuat untuk:
Mailgun
SendGrid
Postmark
Brevo
Resend
tanpa mengubah campaign engine.
8. Queue dan Worker
Pada aplikasi lama, scheduler dapat langsung mengirim email ketika menemukan message yang harus dikirim.
Pendekatan ini cukup untuk volume kecil.
Namun sistem modern sebaiknya memisahkan:
menentukan email yang harus dikirim
dari:
mengirim email
Target architecture:
Scheduler
│
▼
Campaign Resolver
│
▼
email_jobs
│
▼
Worker
│
▼
Email Provider
Untuk mempertahankan positioning lightweight, queue tidak harus menggunakan Redis atau RabbitMQ.
Versi awal dapat menggunakan database-backed queue.
Contohnya:
email_jobs
dengan field:
id
lead_id
campaign_id
message_id
status
attempts
scheduled_at
sent_at
last_error
Pendekatan ini cukup untuk small VPS deployment.
9. Modern Data Model
Legacy system pada dasarnya hanya membutuhkan:
leads
messages
Tetapi jika ingin mendukung multiple campaigns, schema harus dikembangkan.
Target model:
leads
campaigns
campaign_messages
campaign_subscriptions
email_jobs
email_deliveries
unsubscribe_tokens
Relasi sederhananya:
Lead
│
▼
Campaign Subscription
│
▼
Campaign
│
├── Message Day 0
├── Message Day 2
├── Message Day 5
└── Message Day 10
Dengan model tersebut, satu lead dapat bergabung dengan beberapa campaign.
10. REST API
Salah satu tujuan modernization adalah membuat aplikasi menjadi automation friendly.
Karena itu aplikasi akan menyediakan REST API.
Contohnya:
POST /api/leads
GET /api/leads
GET /api/leads/{id}
Campaign:
POST /api/campaigns
GET /api/campaigns
Subscription:
POST /api/campaigns/{id}/subscribe
Unsubscribe:
POST /api/unsubscribe
Versi awal cukup menggunakan:
API Key authentication
Tidak perlu langsung menggunakan OAuth karena akan menambah kompleksitas.
11. Webhook Architecture
REST API menangani komunikasi masuk.
Webhook menangani event keluar.
Misalnya ketika sebuah lead dibuat:
lead.created
atau email terkirim:
email.sent
Autoresponder akan dapat mengirim event ke external system.
Contohnya:
Autoresponder
│
▼
Webhook
│
▼
External Application
Event awal yang direncanakan:
lead.created
lead.unsubscribed
campaign.subscribed
email.queued
email.sent
email.failed
Webhook juga akan memakai HMAC signature agar penerima dapat memverifikasi authenticity dari request.
12. n8n Integration
Salah satu positioning utama project ini adalah:
n8n friendly
Tetapi kompatibilitas tidak cukup hanya dengan menyediakan REST API.
Project juga akan menyediakan beberapa contoh workflow.
Contoh:
Website Form
│
▼
n8n
│
▼
Autoresponder API
│
▼
Email Campaign
Use case lainnya:
Autoresponder
│
webhook
▼
n8n
│
├── Google Sheets
├── CRM
├── Slack
└── Telegram
Repository nantinya dapat memiliki:
examples/
└── n8n/
├── lead-capture.json
├── crm-sync.json
└── campaign-notification.json
13. Target Application Structure
Struktur aplikasi akan diubah dari banyak standalone PHP script menjadi struktur yang lebih modular.
Contoh target:
autoresponder/
│
├── public/
│ ├── index.php
│ ├── subscribe.php
│ └── unsubscribe.php
│
├── src/
│ ├── Auth/
│ ├── Lead/
│ ├── Campaign/
│ ├── Mail/
│ ├── Database/
│ └── Security/
│
├── config/
│ └── app.php
│
├── database/
│ ├── migrations/
│ └── schema.sql
│
├── bin/
│ ├── scheduler.php
│ └── worker.php
│
├── templates/
├── tests/
├── docs/
├── examples/
│
├── composer.json
├── .env.example
├── .gitignore
├── README.md
├── SECURITY.md
└── LICENSE
14. Composer dan PSR-4
Aplikasi modern akan menggunakan Composer untuk dependency management.
Contohnya:
composer install
Composer juga digunakan untuk PSR-4 autoloading.
Dengan demikian kita tidak lagi bergantung pada banyak:
require_once 'file1.php';
require_once 'file2.php';
require_once 'file3.php';
Class dapat di-load otomatis berdasarkan namespace.
Misalnya:
use App\Campaign\CampaignService;
use App\Mail\SMTPTransport;
15. Lightweight Tetap Menjadi Prinsip Utama
Modernisasi bukan berarti semua teknologi modern harus digunakan.
Project ini sengaja tidak akan menjadikan hal-hal berikut mandatory:
Kubernetes
Redis
RabbitMQ
Kafka
Elasticsearch
microservices
service mesh
Targetnya tetap:
1 small VPS
+
Nginx
+
PHP-FPM
+
MariaDB/MySQL
Misalnya:
1 vCPU
1 GB RAM
10–20 GB storage
sudah seharusnya cukup untuk penggunaan skala kecil.
Docker dapat disediakan sebagai pilihan, bukan keharusan.
16. Target Architecture
Arsitektur akhirnya dirancang seperti berikut:
Internet
│
▼
Nginx
│
▼
┌─────────────────────┐
│ PHP Application │
│ │
│ Authentication │
│ Leads │
│ Campaigns │
│ REST API │
│ Webhooks │
└──────────┬──────────┘
│
┌───────────┴────────────┐
▼ ▼
MySQL / MariaDB Email Jobs
│
▼
Worker
│
┌───────────┴──────────┐
▼ ▼
SMTP Amazon SES
17. Development Roadmap
Modernisasi akan dilakukan secara incremental.
v0.1 — Secure Legacy Foundation
Fokus:
PDO
prepared statements
PHP 8 compatibility
environment variables
secure authentication
CSRF protection
XSS protection
secure unsubscribe
Project masih private pada tahap ini.
v0.2 — Modern PHP Foundation
Fokus:
Composer
PSR-4
modular architecture
database migrations
structured configuration
documentation
basic tests
Setelah security review selesai, repository dapat mulai dijadikan public.
v0.3 — Email Delivery
Fokus:
SMTP
Amazon SES
mail transport abstraction
queue
worker
retry
delivery logs
v0.4 — Campaign Engine
Fokus:
multiple campaigns
campaign subscriptions
message scheduling
personalization
delivery history
pause/resume
v0.5 — API & Automation
Fokus:
REST API
API Key authentication
webhooks
HMAC signatures
n8n examples
v1.0 — Stable Release
Target v1.0:
Lead Management
Campaign Management
Drip Email
SMTP
Amazon SES
Queue Worker
REST API
Webhook
n8n Integration
Secure Unsubscribe
PHP 8.x
MySQL / MariaDB
Self-hosted Installation Guide
Basic Automated Testing
18. CI/CD dan Code Quality
Repository juga akan menggunakan GitHub Actions.
Pipeline minimal:
Pull Request
│
▼
composer install
│
▼
PHP Syntax Check
│
▼
PHPUnit
│
▼
PHPStan
│
▼
Composer Security Audit
Tujuannya bukan sekadar automation.
Pipeline tersebut menjadi quality gate sebelum code masuk ke branch main.
19. Dokumentasi Architecture
Sebagai bagian dari project modernization, repository akan memiliki architecture documentation.
Contohnya:
docs/
├── architecture/
│ ├── legacy-architecture.md
│ ├── target-architecture.md
│ ├── data-model.md
│ ├── campaign-engine.md
│ └── email-delivery.md
│
├── security/
│ ├── threat-model.md
│ └── security-design.md
│
├── deployment/
│ ├── nginx.md
│ └── small-vps.md
│
└── integrations/
├── smtp.md
├── amazon-ses.md
└── n8n.md
Dokumentasi ini penting karena project bukan hanya tentang code.
Project juga harus dapat menjelaskan:
Why?
What?
How?
Trade-off?
Security?
Scalability?
Operational model?
20. Mengapa Tidak Langsung Rewrite?
Salah satu keputusan architecture yang penting adalah tidak melakukan complete rewrite sejak awal.
Rewrite memang terlihat menarik.
Tetapi complete rewrite memiliki risiko:
business logic hilang
feature regression
scope membesar
development tidak pernah selesai
Pendekatan yang dipilih adalah:
Understand
↓
Secure
↓
Modernize
↓
Refactor
↓
Extend
Dengan begitu setiap milestone menghasilkan aplikasi yang tetap dapat dipahami dan diuji.
21. Modernisasi sebagai Engineering Exercise
Project ini bukan sekadar mengubah syntax PHP lama menjadi syntax PHP baru.
Modernisasi mencakup beberapa area sekaligus:
Software Architecture
Application Security
Database Engineering
Email Infrastructure
API Design
Automation
DevOps
Observability
Documentation
Dan mungkin bagian terpentingnya adalah:
membuat keputusan teknis yang proporsional terhadap kebutuhan aplikasi.
Tidak semua aplikasi membutuhkan microservices.
Tidak semua queue membutuhkan Kafka.
Tidak semua aplikasi membutuhkan Kubernetes.
Salah satu tujuan project ini justru membuktikan bahwa aplikasi modern juga dapat tetap:
simple
small
maintainable
secure
portable
Penutup
Autoresponder ini dimulai sebagai aplikasi PHP sederhana dengan satu tujuan utama:
mengirimkan email otomatis kepada leads berdasarkan waktu sejak mereka bergabung.
Business logic tersebut tetap relevan.
Yang sudah berubah adalah ekspektasi terhadap software modern.
Hari ini aplikasi harus memiliki:
secure database access
safe authentication
modern PHP compatibility
environment-based configuration
reliable email delivery
API integration
automation support
good documentation
Modernisasi ini bertujuan menjembatani kedua dunia tersebut.
Dari:
Legacy PHP Autoresponder
menuju:
Lightweight
Self-hosted
Secure
API-driven
Automation-friendly
Email Automation Platform
tanpa kehilangan filosofi awalnya:
Keep it simple.
Project ini juga akan menjadi sebuah perjalanan untuk mengeksplorasi bagaimana legacy application dapat dimodernisasi secara incremental—bukan hanya dari sisi source code, tetapi juga dari sisi security, architecture, deployment, integration, dan operational model.
