# Bố cục thư mục

Sửa ngày 17/09/2026. Trước đó gốc kho mã **chính là** thư mục web, nên
`system/`, `cron/`, `sql/`, `deploy/`, `.env` đều nằm trong vùng internet
với tới được. Cách duy nhất chặn chúng là một danh sách đen trong
`.htaccess` — mỗi thư mục mới là một dòng phải nhớ thêm, quên một dòng là
rò. Chuyện đó đã xảy ra một lần: ghi chú cũ trong `.htaccess` viết *"Thêm
15/09/2026 khi triển khai VPS: `/system/auth.php` và `/deploy/*.sh` đều
truy cập được từ internet."*

Nay chỉ những thứ **đáng được tải về qua HTTP** mới nằm trong thư mục web.
Danh sách đen không còn nữa, vì không còn gì để chặn.

## Hai nhánh

```
public/     → /home/admin/web/tradingauto.org/public_html   ← DocumentRoot
private/    → /home/admin/web/tradingauto.org/private       ← ngoài thư mục web
```

Tên miền: `tradingauto.org` (bí danh `www`) — một thư mục, một CSDL, một chứng chỉ.

Kho mã phản chiếu **đúng** bố cục máy chủ, nên mọi đường dẫn tương đối
chạy giống hệt nhau ở cả hai nơi. Không có bước "sửa đường dẫn khi lên
máy chủ".

Không phải sửa vhost: `DocumentRoot` vẫn là `public_html` như Webuzo đặt,
và `private/` vốn đã nằm trong `open_basedir` của PHP-FPM.

## Trong public/ — thư mục web

| Thư mục | Nội dung |
|---|---|
| `index.php` | Trang chủ |
| `.htaccess` | Bảng định tuyến. **Không còn dòng chặn nào** |
| `assets/` | Ảnh, CSS, JS, font |
| `pages/` | Trang khách |
| `admin/` | Trang quản trị |
| `api/` | Điểm nhận hành động — trước đây tên là `progress/` |

## Trong private/ — ngoài thư mục web

| Thư mục | Nội dung |
|---|---|
| `app/lib/` | Thư viện dùng chung — trước đây là `system/` |
| `app/shell/app/` | Khung trang **đã đăng nhập** — trước đây là `core/` |
| `app/shell/site/` | Khung trang **công khai** — trước đây là `pages/header.php`, `menu.php`, `footermain.php` |
| `cron/` | Việc chạy theo giờ |
| `services/` | Dịch vụ nền: `chatbot` (chạy thẳng từ đây), `key_sync`, `mt5_stream_server`, `giam_sat`, `sao_luu`, `sao_luu_redis` (các dịch vụ này cài ở `/opt` / systemd, đây là mã nguồn) |
| `sql/` | Lệnh chuyển đổi CSDL |
| `deploy/` | Kịch bản triển khai |
| `logs/` | Nhật ký |
| `.env` | Cấu hình thật. **Không nằm trong git, không nằm trong thư mục web** |

## Hai bộ khung, giờ gọi đúng tên

Đây là chỗ gây hiểu lầm nhiều nhất trước đây: hai tệp cùng tên
`header.php` làm hai việc hoàn toàn khác nhau.

- `private/app/shell/app/` — khung của khu vực **đã đăng nhập**. Dùng
  giao diện mua sẵn cộng `assets/css/tradingauto.css`.
- `private/app/shell/site/` — khung của trang **công khai** (giới thiệu,
  bảng giá, hướng dẫn, FAQ). Nạp Bootstrap 5 từ CDN cộng
  `assets/css/trangcong.css`.

Sửa màu ở bên nào thì chỉ bên đó đổi. Muốn đổi cả hai thì phải sửa cả
hai — đó là sự thật của hệ thống này, tên thư mục nay nói thẳng điều đó.

## Trang khách: chia theo KHUNG mà trang đó dùng

Đo trước khi sắp: 13 trang nhúng khung `shell/app`, 37 trang nhúng khung
`shell/site`, và **không một trang nào nhúng cả hai**. Ranh giới là có
thật, chỉ chưa được thể hiện ra thư mục.

```
public/pages/
├─ app/          cần đăng nhập  — khung shell/app
│  ├─ recharge/  user/  receipt/
│  └─ dashboard  orders  products  product
├─ auth/         đăng nhập / đăng ký — có _shell.php riêng
├─ site/         công khai — khung shell/site
│  └─ botvip/  funds/  guilde/  toolintroduce/  codeservice/  update/  faq/
└─ (điểm cuối)   json/  function/  signal_stream/  mt5_stream/
                 qr_code.php  download.php  goto_product.php
```

**Địa chỉ không đổi** — chỉ đích của 48 dòng định tuyến đổi.

Tên thư mục bỏ hết chữ HOA (`Auth` → `auth`, `Recharge` → `app/recharge`,
`Pricing.php` → `site/pricing.php`). Trên Windows gõ sai hoa thường vẫn
chạy, trên Linux thì 404 — một loại lỗi chực sẵn. **Đổi tên chỉ khác
hoa/thường thì phải đi vòng qua một tên tạm**, vì Windows coi hai tên là
một và lệnh đổi tên sẽ không làm gì cả; git thì ghi tên mới còn đĩa vẫn
tên cũ, và sai lệch đó chỉ nổ khi lên máy chủ. Đóng gói bằng `git archive`
để lấy đúng tên git ghi nhận, không lấy tên trên đĩa.

## Nhật ký: chỉ một chỗ duy nhất

Mọi nhật ký nằm ở `private/logs/`. Không có ngoại lệ.

```
private/logs/   auto_bank  auto_momo binance_deposit
                ledger_check  mail_send  php_error
```

Ba nơi cùng quyết định chỗ ghi, **phải khớp nhau**:

| Nơi | Đặt gì |
|---|---|
| `private/app/lib/database.php` | `ini_set('error_log', env('ERROR_LOG', __DIR__ . '/../../logs/php_error.log'))` |
| `private/.env` | `ERROR_LOG=<...>/private/logs/php_error.log` |
| crontab của user `admin` | `>> <...>/private/logs/<tên>.log` |

Ngày 17/09/2026 chúng từng lệch nhau: `.env` trỏ `private/php_error.log`
còn mặc định trong mã trỏ `private/logs/php_error.log`, thành ra hai tệp
cùng tên ở hai chỗ, một cái rỗng. Đã gộp và cho khớp.

**Dời tệp nhật ký thì phải sửa crontab cùng lúc.** Cron chạy mỗi phút,
nên chỉ dời tệp thôi là một phút sau nó tạo lại y nguyên ở chỗ cũ —
chuyện này đã xảy ra thật ngay trong lúc dọn.

Dòng cron dọn nhật ký quá 50 MB dùng `find` trên cả `private/` nên vẫn
quét đúng sau khi gom.

## Thư viện: mỗi trang chỉ nạp thứ nó dùng

Trước đây mọi trang chỉ `require database.php`, mà tệp đó kéo theo **cả 19
thư viện** — trang bảng giá cũng nạp `binance.php`, `totp.php`, `smtp.php`.
Đọc đầu một trang không biết được nó động chạm vào gì.

Đo trên 123 điểm vào: mỗi trang thực sự cần nhiều nhất 11 thư viện, trung
vị 0.

**Ba tầng:**

1. **Lõi** — `database.php` nạp sẵn cho mọi trang:
   `env` `function` `auth` `cache` `csrf` `credit`.
   Ba cái đầu chính `database.php` dùng; `csrf` thì bộ khung nào cũng gọi;
   `credit` thì cột phải của bảng điều khiển gọi.

2. **Thư viện tự khai phụ thuộc của nó** bằng `require_once`:
   ```
   purchase.php        -> invoice, product, wallet
   crypto_deposit.php  -> binance, invoice, wallet
   invoice.php         -> wallet
   mailer.php          -> smtp
   oauth.php           -> account
   ```
   Nhờ vậy trang gọi `purchase.php` không phải biết đến ba phụ thuộc kia.

3. **Trang khai thứ nó TRỰC TIẾP dùng.** Ví dụ:
   ```php
   require       __DIR__ . '/../../../private/app/lib/database.php';
   require_once  __DIR__ . '/../../../private/app/lib/binance.php';
   require_once  __DIR__ . '/../../../private/app/lib/crypto_deposit.php';
   ```
   Đọc ba dòng này là biết ngay trang nạp crypto nói chuyện với Binance.

Kết quả: trung vị mỗi trang nạp **7** tệp thư viện thay vì 20; 109/123 trang
nạp dưới 10 tệp.

**Thêm thư viện mới thì phải khai ở trang dùng nó.** Quên là trang đó chết
bằng `Fatal error: Call to undefined function` — và chỉ lộ ra khi có người
mở đúng trang đó. Chạy `scratchpad/tham_dinh_lib.py` để bắt trước: nó duyệt
cả 123 điểm vào, dựng đúng tập tệp thực sự được nạp, và báo mọi hàm được gọi
mà không có nơi định nghĩa.

## Đường dẫn trong mã nguồn

Mọi `require`/`include` đều viết theo dạng:

```php
require __DIR__ . '/../../private/app/lib/database.php';
```

`__DIR__` là dạng **duy nhất** không phụ thuộc vào thư mục làm việc hiện
hành. Trước đợt này có 171 câu dùng chuỗi tương đối kiểu
`require('../../system/database.php')` — dạng đó phụ thuộc vào
`include_path` và vào nơi PHP được gọi, nên nó chạy được ở trang này mà
hỏng ở trang khác. Đã đổi hết.

Kiểm lại bằng `scratchpad/kiemtra.py`: mọi đường dẫn trong mã phải trỏ
tới một tệp có thật.

## Chạy ở máy local

Thư mục web của XAMPP phải trỏ vào `htdocs/public`, không phải `htdocs`.
Trong `httpd.conf`:

```apache
DocumentRoot "G:/Xampp/htdocs/public"
<Directory "G:/Xampp/htdocs/public">
```

Không đổi thì trình duyệt sẽ thấy danh sách thư mục thay vì trang chủ.
