# Hướng dẫn Build & Deploy — MT Promo Tracking

Ứng dụng không dùng framework/bundler ngoài, không có bước "build" (compile)
nào cả — chỉ cần copy code lên server có **Node.js >= 22.5** rồi chạy
`node server.js`. Vì vậy việc "build code" ở đây thực chất là **đóng gói và
đưa code lên hosting**, có 2 hướng chính:

- **Cách A — VPS thông thường** (DigitalOcean, Vultr, AWS Lightsail/EC2,
  Linode...): cài Node.js trực tiếp, dùng PM2 để giữ tiến trình chạy nền,
  Nginx làm reverse proxy + HTTPS.
- **Cách B — Docker** (chạy trên VPS bằng Docker, hoặc các nền tảng hỗ trợ
  Docker như Railway, Render, Fly.io, DigitalOcean App Platform...): dùng
  `Dockerfile`/`docker-compose.yml` đã có sẵn trong project.

> ⚠️ **Lưu ý quan trọng về Node.js version**: App dùng module `node:sqlite`
> (built-in từ Node 22.5, hiện vẫn ở dạng experimental). Rất nhiều nền tảng
> PaaS mặc định dùng Node 18/20 LTS — bạn PHẢI chọn/khai báo rõ Node 22 khi
> deploy, nếu không app sẽ báo lỗi `Cannot find module 'node:sqlite'`.

> ⚠️ **Lưu ý về dữ liệu**: file CSDL nằm ở `data/promo_tracking.db`. Trên các
> nền tảng có filesystem "ephemeral" (Railway, Render free tier, Heroku...),
> dữ liệu sẽ **mất khi container khởi động lại** trừ khi bạn gắn một
> **persistent volume/disk** vào đúng thư mục `data/`. Luôn kiểm tra mục này
> trước khi chọn nền tảng.

---

## Cách A: Deploy lên VPS (Ubuntu 22.04/24.04) — khuyến nghị cho dữ liệu nội bộ

### Bước 1 — Cài Node.js 22 trên VPS
```bash
curl -fsSL https://deb.nodesource.com/setup_22.x | sudo bash -
sudo apt-get install -y nodejs
node --version   # phải >= 22.5.0
```

### Bước 2 — Đưa code lên server
Từ máy của bạn (giải nén sẵn thư mục `mt-promo-app`):
```bash
scp -r mt-promo-app user@YOUR_SERVER_IP:/opt/mt-promo-app
```
Hoặc dùng Git nếu bạn đã đẩy code lên GitHub/GitLab:
```bash
ssh user@YOUR_SERVER_IP
git clone <repo-url> /opt/mt-promo-app
```

### Bước 3 — Cài PM2 để giữ app luôn chạy nền
```bash
sudo npm install -g pm2
cd /opt/mt-promo-app
PORT=3000 HOST=127.0.0.1 SECURE_COOKIES=true pm2 start server.js --name mt-promo-app
pm2 save
pm2 startup   # chạy lệnh nó in ra để PM2 tự khởi động cùng server
```
(App chạy ở `127.0.0.1:3000`, không mở ra Internet trực tiếp — Nginx ở bước
sau sẽ là cửa ngõ duy nhất, an toàn hơn.)

### Bước 4 — Cài Nginx làm reverse proxy
```bash
sudo apt install -y nginx
sudo nano /etc/nginx/sites-available/mt-promo-app
```
Nội dung file:
```nginx
server {
    listen 80;
    server_name your-domain.com;

    location / {
        proxy_pass http://127.0.0.1:3000;
        proxy_http_version 1.1;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}
```
```bash
sudo ln -s /etc/nginx/sites-available/mt-promo-app /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx
```

### Bước 5 — Bật HTTPS miễn phí bằng Let's Encrypt
```bash
sudo apt install -y certbot python3-certbot-nginx
sudo certbot --nginx -d your-domain.com
```
Certbot sẽ tự sửa cấu hình Nginx để chuyển HTTP → HTTPS và tự gia hạn chứng
chỉ. Sau khi có HTTPS, đảm bảo app đang chạy với `SECURE_COOKIES=true` (đã
đặt ở Bước 3) để cookie phiên đăng nhập chỉ gửi qua kết nối mã hóa.

### Bước 6 — Mở firewall (nếu dùng ufw)
```bash
sudo ufw allow 'Nginx Full'   # mở 80 + 443
sudo ufw allow OpenSSH
sudo ufw enable
```
Không cần mở port 3000 ra ngoài vì Nginx đã proxy nội bộ.

### Cập nhật code sau này
```bash
cd /opt/mt-promo-app
git pull                 # hoặc scp code mới đè lên
pm2 restart mt-promo-app
```

### Sao lưu dữ liệu
```bash
cp /opt/mt-promo-app/data/promo_tracking.db ~/backup-$(date +%F).db
```
Nên đặt cron job chạy lệnh này định kỳ (hàng ngày).

---

## Cách B: Deploy bằng Docker

Project đã có sẵn `Dockerfile`, `.dockerignore`, `docker-compose.yml`.

### B.1 — Chạy trên VPS bằng Docker Compose
```bash
# Cài Docker (nếu chưa có)
curl -fsSL https://get.docker.com | sudo sh

cd /opt/mt-promo-app
sudo docker compose up -d --build
```
Dữ liệu SQLite được lưu ở thư mục `./data` trên máy host (đã khai báo volume
trong `docker-compose.yml`) nên an toàn khi rebuild/redeploy container.

Muốn đặt phía sau Nginx + HTTPS như Cách A: làm y hệt Bước 4–5 ở trên, chỉ
đổi `proxy_pass` trỏ vào `http://127.0.0.1:3000` (cổng compose đã map), và
sửa `docker-compose.yml` set `SECURE_COOKIES=true`.

Cập nhật code:
```bash
git pull
sudo docker compose up -d --build
```

### B.2 — Deploy lên nền tảng PaaS hỗ trợ Docker (Railway / Render / Fly.io...)

Các bước chung:
1. Đẩy code (kèm `Dockerfile`) lên GitHub.
2. Trên nền tảng, chọn **"Deploy from Dockerfile"** / **"New Web Service"**
   trỏ tới repo.
3. Khai báo biến môi trường: `PORT` (một số nền tảng tự inject, không cần
   set tay), `SECURE_COOKIES=true` (các nền tảng này luôn có HTTPS sẵn).
4. **Bắt buộc** gắn một **Persistent Volume/Disk** vào đường dẫn `/app/data`
   — nếu không dữ liệu sẽ mất mỗi lần deploy lại hoặc container restart:
   - Railway: mục "Volumes" → mount path `/app/data`
   - Render: "Disks" → mount path `/app/data`
   - Fly.io: `fly volumes create data --size 1` rồi khai báo `[mounts]`
     trong `fly.toml` trỏ tới `/app/data`
5. Deploy. Nền tảng sẽ build Docker image từ `Dockerfile` có sẵn và chạy.

> Nếu nền tảng không hỗ trợ Docker mà chỉ nhận Node.js buildpack thuần, bạn
> cần đảm bảo họ cho chọn Node 22 (khai báo trong `package.json` đã có sẵn
> field `"engines": {"node": ">=22.5.0"}` — một số nền tảng như Render đọc
> field này để chọn version, nhưng không phải tất cả, nên kiểm tra tài liệu
> riêng của từng nền tảng).

---

## Sau khi deploy — việc cần làm ngay
1. Truy cập domain/IP, đăng nhập bằng `admin` / `admin123`.
2. Vào **Quản lý tài khoản** đổi mật khẩu quản trị (sửa tài khoản `admin`, nhập mật khẩu mới).
3. Tạo các tài khoản Người dùng gắn đúng cửa hàng.
4. Thiết lập sao lưu định kỳ cho `data/promo_tracking.db`.
5. Đảm bảo đang chạy HTTPS + `SECURE_COOKIES=true` trước khi dùng thật (để cookie đăng nhập không bị lộ qua kết nối không mã hóa).
