# XTransformer

Trình chỉnh sửa JSON `aip-304-app` dạng bảng cho macOS + Windows. Thay thế quy trình Google Sheets cũ — full CRUD cho Screens, Banners, Categories, Styles, Media, Countries với cam kết round-trip identity (file xuất ra giống hệt file đầu vào khi không có chỉnh sửa).

---

## 1. Cài đặt

### macOS (Apple Silicon)

1. Tải `release/XTransformer-0.1.0-arm64.dmg`.
2. Mở DMG → kéo **XTransformer.app** vào thư mục **Applications**.
3. Mở app lần đầu: chuột phải → **Open** → **Open** (vì app chưa được Apple notarize, Gatekeeper sẽ cảnh báo).

### Windows (64-bit)

Chọn 1 trong 2:

| File | Khi nào dùng |
|---|---|
| `XTransformer-0.1.0-x64-setup.exe` | Cài cố định — chạy installer → chọn thư mục → tạo Desktop + Start Menu shortcut. |
| `XTransformer-0.1.0-x64-portable.exe` | Chạy thẳng từ USB / Downloads, không cài, không ghi registry. |

Lần đầu mở: Windows SmartScreen có thể chặn → click **More info → Run anyway** (vì .exe chưa có code-sign).

---

## 2. Cách dùng cơ bản

### Mở và lưu file JSON

1. Click **Open JSON** (hoặc `⌘O` / `Ctrl+O`) → chọn file `aip-304-app-*.json`.
2. App load file → mỗi entity hiện ở 1 tab riêng:
   - **Screens**: danh sách màn hình của app
   - **Banners**: banner trong từng screen
   - **Categories**: nhóm style xếp theo screen
   - **Styles**: style đầy đủ + cardPreviews
   - **Media**: thư viện ảnh/video referenced
   - **Countries**: country code i18n
   - **Meta**: version + exportedAt
3. Sửa trực tiếp trong bảng — mọi thay đổi tự validate realtime.
4. Click **Save JSON** (`⌘S` / `Ctrl+S`):
   - Nếu có lỗi validation → dialog hiện errors, phải sửa trước khi xuất.
   - Nếu có warning → dialog hỏi xác nhận, vẫn cho xuất.
   - Hiện diff (added / modified / deleted) trước khi ghi file.

### Phím tắt

| Tổ hợp | Hành động |
|---|---|
| `⌘O` / `Ctrl+O` | Mở file JSON |
| `⌘S` / `Ctrl+S` | Lưu (chạy validate + diff) |
| `⌘⇧V` / `Ctrl+Shift+V` | Validate ngay |
| `Esc` | Đóng dialog đang mở |

### Chỉnh sửa cell

- **Text**: click vào ô → gõ → Enter để commit, Esc để hủy.
- **Foreign key (FK)**: dropdown chỉ liệt kê giá trị hợp lệ — không thể tạo dangling reference.
- **Boolean**: toggle.
- **Tags**: gõ tag → Enter, dùng `×` để xóa.

### Master-detail (Banners, Categories, Styles)

- Click mũi tên `▶` đầu hàng để mở rộng row.
- Detail panel cho phép sửa i18n titles/subtitles theo countryCode, style refs (Categories), card previews (Styles).

### Bộ lọc theo Banner action

- Banner.action chỉ nhận 2 giá trị: `CATEGORY` hoặc `STYLE`.
- Đổi action sẽ tự xóa FK đối ngược (chọn CATEGORY → styleCode về null, ngược lại).
- Cột được dùng (Category hoặc Style) sẽ highlight vàng; cột không dùng mờ đi.

### Validation

- Status bar đáy màn hình hiện số `errors / warnings` realtime.
- Click vào chip màu để mở Validation dialog xem chi tiết.
- Errors block xuất file; warnings chỉ cảnh báo.

### Autosave

- Mỗi 5 giây khi có thay đổi chưa lưu, app backup vào localStorage.
- Mở app lần sau nếu phát hiện draft → prompt **Restore / Discard**.

---

## 3. Upload media lên CMS

Tích hợp Strapi CMS để upload ảnh/file thay vì phải vào trình duyệt → upload thủ công → copy URL → paste.

### Setup lần đầu

1. Tab **Media** → click ⚙ **Settings**.
2. Confirm **Base URL** (mặc định `https://cms.aperogroup.ai`) → **Save URL**.
3. Click **Sign in to Strapi** → cửa sổ login mở ra → đăng nhập Google bằng tài khoản công ty.
4. App tự thu thập JWT-looking tokens trong localStorage/sessionStorage/cookies/URL của cửa sổ login → test từng cái với `/upload/folders` → cái nào trả 200 sẽ được lưu.
5. Nếu auto-detect fail → hiện danh sách candidates để pick thủ công, hoặc dán token trực tiếp từ DevTools.
6. Set **Default upload folder** từ dropdown (có search theo tên).

### Upload

1. Tab **Media** → click ☁ **Upload to CMS** (hoặc dialog tự mở khi chưa đăng nhập).
2. Chọn folder đích (dropdown có search — gõ tên folder).
3. Pick file: hỗ trợ chọn nhiều file cùng lúc (`⌘`/`Ctrl` + click), mọi định dạng (image, video, zip, json, etc.).
4. Click **Upload N files** → progress bar realtime, mỗi file có status: ⏱ pending → ⟳ uploading → ✓ done / ⚠ error.
5. File upload thành công → tự thêm row mới vào Media table với `strapi_id`, `url`, `name`, `mime` đã fill, **highlight vàng 60 giây** để dễ nhận.

### Đổi tài khoản Google

Trong **Settings** → click **Switch account** → app xóa cookies/storage của cửa sổ login → lần sign-in sau Google sẽ hiện lại màn chọn account.

### Fallback dán token thủ công

Nếu Strapi setup khác lạ làm auto-detect fail:
1. Đăng nhập Strapi trong browser bình thường.
2. DevTools → Application → Local Storage → `https://cms.aperogroup.ai`.
3. Tìm key có giá trị dạng `eyJhbGci...` (JWT).
4. Settings → **Paste token manually** → dán → **Save token**.

---

## 4. Build & phát triển

```bash
# Cài dependencies
npm install

# Chạy dev mode (hot reload)
npm run dev

# Build production bundle
npm run build

# Type check
npm run typecheck

# Chạy test (Vitest round-trip)
npm test

# Đóng gói installer
npm run package:mac    # → release/XTransformer-*-arm64.dmg
npm run package:win    # → release/XTransformer-*-x64-setup.exe + portable
npm run package:all    # cả 2
```

---

## 5. Kiến trúc tóm tắt

```
src/
├── main/        Electron main process (file dialogs, IPC, Strapi handlers)
├── preload/     contextBridge (window.api)
└── renderer/    React app
    ├── lib/    schema · import · export · validate (port từ Sheets tool)
    ├── store/  Zustand (editor + diff-tracker + autosave + Strapi config)
    ├── components/  data-table · cells · dialogs · upload · folder-picker
    └── pages/  1 tab cho mỗi entity group
```

**Tech stack:** Electron 33 · Vite 5 · React 18 + TypeScript 5 · TanStack Table v8 · Tailwind 3 · Zustand 5 · Zod · Vitest · electron-builder

---

## 6. Không thuộc phạm vi (out of scope)

- Multi-user collab (single-user only)
- Cloud sync / backend riêng
- Schema editor (schema khoá ở `aip-304-app v1.0`)
- Sửa media trực tiếp (chỉ link URL)
- i18n cho UI app (chỉ data có i18n, UI dùng tiếng Anh)
- Code signing / notarization (skip cho nội bộ)

---

Made by **Bạch Tử Hoạ**
