ERPFit không bán phần mềm đóng gói. Chúng tôi xây dựng giải pháp cho từng doanh nghiệp, rồi chuyển giao để họ tự vận hành. Điều đó có nghĩa là stack công nghệ phải đáp ứng được hai yêu cầu: chúng tôi phát triển nhanh, và khách hàng không bị phụ thuộc vào bất kỳ ai.
Mã nguồn mở giải quyết cả hai. Không có license fee, không bị khóa vendor, và khi cần — bất kỳ lập trình viên nào cũng có thể đọc code, sửa, hoặc thay thế.
Runtime: Bun
Chúng tôi chọn Bun làm runtime mặc định vì nó nhanh hơn Node.js, hỗ trợ TypeScript native và gom nhiều công cụ vào một. Trước Bun, chúng tôi dùng Node.js. Chuyển sang Bun không phải vì hype — mà vì ba lý do thực tế:
- Startup nhanh hơn đáng kể. Các script tự động hóa chạy hàng ngày (health check, backup verify, data sync) cần khởi động trong mili-giây, không phải giây. Theo benchmark của Bun, runtime này khởi động nhanh hơn Node.js nhiều lần trong các script nhỏ — đúng với trải nghiệm nội bộ của chúng tôi.
- TypeScript native. Không cần
tsc, không cầnts-node, không cầntsx. Viết.ts, chạy trực tiếp. Giảm đáng kể ma sát trong development. - Built-in test runner, bundler, package manager. Ít công cụ hơn = ít thứ phải maintain. Trong một team nhỏ, điều này quan trọng.
Một script tự động hóa điển hình của chúng tôi gọn như thế này:
// health-check.ts — chạy trực tiếp bằng `bun run health-check.ts`
const res = await fetch('https://erpfit.com/health')
if (!res.ok) {
await fetch(process.env.TELEGRAM_WEBHOOK!, {
method: 'POST',
body: JSON.stringify({ text: 'erpfit.com DOWN' }),
})
}
Bun không hoàn hảo. Một số package npm có native binding vẫn gặp vấn đề. Nhưng với stack TypeScript-first, chúng tôi hiếm khi cần native modules. Trade-off xứng đáng.
Web framework: Hono
Hono là web framework nhẹ, chạy trên mọi runtime (Bun, Deno, Cloudflare Workers, Node.js) với API kiểu Express — đó là lý do chúng tôi chọn nó. Cụ thể:
- Nhẹ. Bundle size không đáng kể so với Express hay Fastify. Quan trọng khi chạy trên VPS nhỏ.
- API quen thuộc. Nếu bạn biết Express, bạn biết Hono. Middleware pattern giống nhau.
- JSX support. Hono có JSX renderer riêng — không cần React. Website erpfit.com chạy Hono JSX, server-rendered, không có client-side hydration. Nhanh, đơn giản.
- Runtime-agnostic. Nếu một ngày Bun không còn phù hợp, chuyển sang Deno hoặc Node.js chỉ cần đổi adapter.
Một route Hono cơ bản chỉ vài dòng:
import { Hono } from 'hono'
const app = new Hono()
app.get('/health', (c) => c.json({ ok: true }))
export default app
Hono kết hợp với tRPC cho các API cần type safety end-to-end — client gọi API có autocompletion, server validate tự động. Pattern này hiệu quả với TypeScript monorepo. Chúng tôi cũng dùng cùng nền tảng này cho bộ công cụ Craft.
Database: PostgreSQL (và MariaDB khi cần)
PostgreSQL là lựa chọn mặc định cho mọi dự án mới vì nó làm được gần như mọi thứ trong một engine. Lý do đơn giản: relational, JSON, full-text search, PostGIS cho geolocation, tốt ở scale nhỏ lẫn lớn.
Widget platform dùng PostgreSQL + PostGIS cho store locator — tính khoảng cách, tìm cửa hàng gần nhất. Không cần thêm service riêng cho geo queries. Nền tảng PIM cho thương mại điện tử của chúng tôi cũng đứng trên cùng cơ sở dữ liệu này.
MariaDB vẫn được dùng khi cần — ERPNext chạy trên MariaDB, WordPress dùng MySQL. Chúng tôi không dogmatic về database — dùng cái phù hợp nhất cho từng bài toán.
Infrastructure: Cloudflare + Linux + Docker
Lớp hạ tầng của chúng tôi đứng trên Cloudflare ở rìa và Docker trên Linux ở lõi — gần như miễn phí và hoàn toàn open source. Cloudflare lo DNS, CDN, SSL, DDoS protection, và Cloudflare Tunnel cho các service chạy on-premise mà không cần public IP.
Server chạy trên VPS (Vultr, Hetzner) và Proxmox on-premise. Docker + Coolify để quản lý containers, Traefik làm reverse proxy. Tất cả đều open source.
Sao lưu hàng ngày, lưu trữ 30 ngày, bản sao offsite qua SFTP. Giám sát bằng Uptime Kuma — 19+ service endpoints (dữ liệu nội bộ), cảnh báo qua Telegram trong vài phút khi có sự cố. Chúng tôi đã viết chi tiết cách dựng trong bài giám sát uptime với Uptime Kuma.
Tại sao không dùng cloud managed services?
Với SME Việt Nam, cloud managed services thường đắt và khóa vendor hơn so với vài VPS chạy Docker — nên chúng tôi tránh. AWS, GCP, Azure đều có managed database, managed Kubernetes, managed everything. Nhưng cho doanh nghiệp nhỏ Việt Nam:
- Chi phí không tương xứng. Một RDS instance nhỏ nhất đã tốn nhiều hơn cả VPS chạy PostgreSQL + 5 app containers.
- Vendor lock-in thực sự. Lambda, DynamoDB, Cloud Functions — code viết cho cloud cụ thể khó chuyển đi. Chúng tôi muốn khách hàng tự do.
- Đơn giản hơn cho quy mô SME. 2-3 VPS, Docker Compose, Traefik — đủ cho gần như toàn bộ nhu cầu của khách hàng chúng tôi (dữ liệu nội bộ). Kubernetes là overkill khi bạn chưa có 10 microservices.
Điều này không có nghĩa cloud managed services sai — chỉ là không phù hợp cho đối tượng khách hàng của chúng tôi.
Nguyên tắc chọn công nghệ
Nguyên tắc gọn lại trong một câu: chọn công nghệ "buồn tẻ", ít công cụ, ưu tiên mã nguồn mở và luôn chuyển giao được. Sau vài năm thử nghiệm, chúng tôi rút ra được vài nguyên tắc:
- Ưu tiên boring technology. PostgreSQL boring hơn MongoDB. Linux boring hơn serverless. Boring có nghĩa là ổn định, có documentation tốt, dễ tìm người hỗ trợ.
- Ít tool hơn = ít vấn đề hơn. Mỗi tool thêm vào stack là thêm một thứ phải update, monitor, debug. Bun thay thế Node + tsc + jest + npm bằng một tool duy nhất.
- Open source trước, trả phí khi cần. Dùng Mautic thay Mailchimp, Uptime Kuma thay Datadog, Coolify thay Vercel. Không phải lúc nào open source cũng tốt hơn — nhưng nó luôn là điểm khởi đầu đúng.
- Chuyển giao được. Stack phải là thứ lập trình viên khác có thể tiếp nhận. TypeScript + PostgreSQL + Docker — hầu như ai cũng biết. Đó là lợi thế lớn nhất.
Stack không quan trọng bằng cách bạn dùng nó. Nhưng chọn đúng stack từ đầu tiết kiệm rất nhiều thời gian và tiền bạc về sau — đặc biệt cho doanh nghiệp nhỏ, nơi mỗi quyết định công nghệ đều ảnh hưởng trực tiếp đến chi phí vận hành.