FEAT: thêm nút bypass cho track strip để bypass không qua mastering panel

This commit is contained in:
2026-08-03 15:47:10 +07:00
parent 6f55d36085
commit a9da813cb1
28 changed files with 2076 additions and 233 deletions
+36
View File
@@ -1,3 +1,39 @@
### [2026-08-03] Task: Nút Bypass Mastering cho từng track strip trong Mixer Panel
- **Tóm tắt thay đổi:** Thêm nút **B** (Bypass) trong mỗi track strip của Mixer Panel (cạnh M/S). Khi bật ON: âm thanh track đi qua **dry bus mới** (`masterBus.dryInput → dryOutput → output`) — **bỏ qua toàn bộ chuỗi mastering** (EQ / Imager / Maximizer) nhưng vẫn qua master volume + metering ở Main out. Cơ chế: `createMasteringRoute()` tạo 2 đường gain bù nhau (routeGain → `masterBus.input` qua mastering, dryGain → `dryInput`); `setMasteringRoute()` crossfade 20ms khi toggle (không click). Áp dụng tại: `getOrCreateTrackNode` (node track chính, toggle live qua `node.route`), `startSubTabPlayback` (clip playback). Map trạng thái `trackMasteringBypassMap` sync từ tracks state qua useEffect; `window.__setTrackMasteringBypass` toggle ngay cho track đang phát. Lưu/đọc project: `mastering_bypass` trong serialize/deserialize (schema không chặn additionalProperties nên không cần sửa).
- **Các file ảnh hưởng:** `app/static/js/app.jsx`, `app/static/js/app.precompiled.js` (rebuild), `app/templates/index.html` (bump v=202608031800)
- **Ghi chú/Test (nếu có):** `node build.mjs` rebuild OK, syntax OK, `pytest` 83 passed. **Giới hạn:** track MIDI/SoundFont dùng chung 1 bộ render FluidSynth (1 worklet → 1 gain) nên bypass hiện áp dụng cho track AUDIO (clip) + oscillator fallback; track MIDI dùng FluidSynth WASM chưa tách được theo track (cần refactor renderer) — sẽ làm tiếp nếu cần.
---
### [2026-08-03] Task: Rebuild app.precompiled.js từ app.jsx (fix "handleOpenProject is not defined")
- **Tóm tắt thay đổi:** Lỗi `Uncaught ReferenceError: handleOpenProject is not defined` khi click Open → bundle `app.precompiled.js` mà trình duyệt tải bị lệch với `app.jsx` (bundle cũ không chứa định nghĩa hàm ở scope đúng). `npm run build` không chạy được vì Babel 8 ESM-only (`ERR_REQUIRE_ESM`). Giải pháp: build lại bundle bằng **@babel/standalone@7** qua `build.mjs` (script mới, mirror đúng lệnh build trong package.json), tạo `app.precompiled.js` mới (858KB, syntax OK, đủ `const handleOpenProject` + 3 references, kèm fix restoreLastSessionProject). Đã smoke-test: trích deserializer từ bundle mới chạy với 6 project khôi phục → 6/6 OK, "Rose (autosave 03/08)" đủ 39 MIDI notes. Bump cache-buster lên `v=202608031700`.
- **Các file ảnh hưởng:** `app/static/js/app.precompiled.js` (rebuild), `build.mjs` (NEW — rebuild thủ công khi Babel 8 lỗi), `app/templates/index.html`
- **Ghi chú/Test (nếu có):** `pytest tests/` → 83 passed. Node portable dùng: `/tmp/node-v20.18.0-linux-x64/bin/node` (máy không có node hệ thống). Trên máy deployment: copy 3 file (app.jsx, app.precompiled.js, index.html) hoặc chạy `node build.mjs` rồi hard refresh.
---
### [2026-08-03] Task: Fix auto-restore dự án lỗi "Không tìm thấy dự án" sau khi khôi phục DB
- **Tóm tắt thay đổi:** Sau khi DB bị xóa/tạo lại, `localStorage.sonic_project_id` của trình duyệt vẫn trỏ tới project cũ đã mất → mỗi lần tải trang `restoreLastSessionProject` gọi API, nhận 404 "Không tìm thấy dự án" và chỉ `console.warn` vĩnh viễn. Fix: khi restore thất bại, tự xóa `sonic_project_id` + `sonic_project_name` khỏi localStorage để lỗi không lặp lại. Bump cache-buster precompiled lên `v=202608031600`.
- **Các file ảnh hưởng:** `app/static/js/app.jsx`, `app/static/js/app.precompiled.js`, `app/templates/index.html`
- **Ghi chú/Test (nếu có):** Verified qua API: cả 6 project khôi phục mở được (GET /cloud/{id} → 200 + main_session đầy đủ). Người dùng cần hard refresh (Ctrl+Shift+R) để nạp bundle mới, mở "Rose (autosave 03/08)" 1 lần để ghim project hiện tại.
---
### [2026-08-03] Task: Khôi phục các dự án cloud cũ bị mất (git recovery)
- **Tóm tắt thay đổi:** Các dự án cloud cũ ('Test' x4, 'Rose' từ 22/07) và project đang làm dở "Rose" (autosave 03/08, 2 track MIDI+AUDIO, 39 notes, bpm 128) đã được khôi phục vào `app/storage/sonicforge.db` dưới user_id admin hiện tại từ **git history** (`app/storage/sonicforge.db` từng được commit trước khi vào `.gitignore`). Nguyên nhân mất: DB bị xóa/tạo lại nhiều lần trong quá trình dev (test suite `test_auth_and_quota` xóa DB → admin được re-seed với UUID mới → project cũ gắn với user_id cũ không hiển thị). Đã dọn các project/user test rác, backup DB trước khi khôi phục tại `/tmp/sonicforge_db_before_restore.db`.
- **Các file ảnh hưởng:** `app/storage/sonicforge.db` (dữ liệu), `tools/restore_cloud_projects.py` (NEW — script khôi phục cho deployment khác), `tools/cloud_projects_backup.json` (NEW — 6 project dạng portable)
- **Ghi chú/Test (nếu có):** Verified qua API: login admin → `GET /api/v1/projects/cloud` trả đủ 6 project; mở "Rose (autosave 03/08)" đủ 39 MIDI notes. Trên máy deployment thật (nếu DB khác): `python3 tools/restore_cloud_projects.py <duong-dan>/sonicforge.db`. Từ giờ test suite không đụng DB dev (xem entry conftest).
---
### [2026-08-03] Task: Cô lập test suite khỏi DB dev + khôi phục mật khẩu admin
- **Tóm tắt thay đổi:** (1) `DB_PATH` trong `app/models/user.py` giờ có thể override bằng env `SONICFORGE_DB_PATH`. (2) Thêm `tests/conftest.py` set env này sang `/tmp/sonicforge_test.db` trước khi mọi app module được import → pytest không bao giờ sửa DB dev nữa (trước đây `test_auth_and_quota` seed + đổi mật khẩu admin ngay trong `app/storage/sonicforge.db`, khiến login `admin123` fail). (3) Reset mật khẩu admin DB dev về `admin123` (`must_change_password=0`).
- **Các file ảnh hưởng:** `app/models/user.py`, `tests/conftest.py` (NEW)
- **Ghi chú/Test (nếu có):** `pytest tests/` → 83 passed, 5 skipped. Đã verify live: login admin/admin123 → 200, sai mật khẩu → 400. Nếu deployment khác cũng bị dính (chạy test trên cùng DB), reset thủ công: `UPDATE users SET hashed_password='<hash_of_admin123>', must_change_password=0 WHERE username='admin'` hoặc xóa DB để `seed_admin` tạo lại.
---
### [2026-08-03] Task: Security audit + bug fixes (bảo mật, bug chức năng, cải thiện)
- **Tóm tắt thay đổi:** (1) **SSRF** `/api/v1/ai/proxy`: thêm auth bắt buộc + chặn cloud metadata/link-local (169.254.0.0/16), chặn IP private trừ khi host nằm trong danh sách AI provider user đã cấu hình (cho phép Ollama localhost:11434), chặn scheme không phải http/https, không forward header X-Auth-Token lên upstream. (2) **Path traversal** `/plugins/render`: `output_filename` chỉ lấy basename + ép đuôi .wav. (3) **Path traversal** toàn bộ `/audio/*`: helper `_safe_file_id`/`_resolve_storage_path` (basename + chỉ đọc trong uploads/processed). (4) **SECRET_KEY**: bỏ hardcode, tự sinh random bền vững lưu `app/storage/.secret_key` (ưu tiên env SECRET_KEY). (5) **media.py** (`computer`/`browse`/`file`): yêu cầu auth — login giờ set HttpOnly cookie `sf_token`, `get_current_user` nhận token từ Bearer / X-Auth-Token / cookie nên frontend raw fetch vẫn hoạt động. (6) Upload audio + soundfont: streaming theo chunk + giới hạn size (1GB/2GB) thay vì đọc cả file vào RAM. (7) **Quota bypass**: `update_cloud_project` giờ kiểm tra quota như `save_cloud_project`. (8) `enforce_password_changed` (bắt buộc đổi mật khẩu lần đầu) được wire vào upload/edit/render/ai-scan/ai-cut/python-tool/upload-soundfont. (9) **render_engine**: fix resample bị bỏ qua (`sr != sample_rate` trước là no-op → giờ resample_poly), render tôn trọng **solo** track, cache buffer section theo `section_id`, thay print → logger. (10) **vst_engine**: thống nhất FluidSynth API low-level CFFI (high-level `Synth()`/`FluidSynth()` không tồn tại trong binding này). (11) Rate-limit login theo IP (10 lần/15 phút), validate độ mạnh password khi register. (12) main.py: `on_event``lifespan`, CORS `allow_credentials=False`, xóa stub rỗng. (13) SQLite: WAL + foreign_keys=ON + seed user `anonymous` placeholder (FK hợp lệ cho project ẩn danh). (14) Pydantic v2 `model_dump()` thay `dict()`.
- **Các file ảnh hưởng:** `app/core/auth.py`, `app/api/v1/auth.py`, `app/api/v1/ai_proxy.py`, `app/api/v1/plugins.py`, `app/api/v1/audio.py`, `app/api/v1/media.py`, `app/api/v1/projects.py`, `app/api/v1/multitrack.py`, `app/api/v1/user_config.py`, `app/core/render_engine.py`, `app/core/vst_engine.py`, `app/models/user.py`, `app/main.py`, `app/static/js/services/aiGateway.js` (gửi X-Auth-Token khi gọi proxy), `tests/test_security_hardening.py` (NEW, 14 test), `tests/test_plugin_api.py`
- **Ghi chú/Test (nếu có):** `pytest tests/` → 83 passed, 5 skipped. Đã verify live: proxy không token → 401, metadata → 403; media không token → 401 / có cookie → 200; render `output_filename=/tmp/x.wav` → path nằm trong PROCESSED_DIR. Lưu ý: nếu triển khai cũ đang chạy, restart server để tạo `.secret_key` (token cũ sẽ hết hạn vì secret đổi). Login mật khẩu admin mặc định vẫn `admin123` (đã khôi phục trong DB dev).
---
### [2026-07-31 07:03] Task: Fix Lucide icons not rendering on new tracks (TCP + SECTION-TAB)
- **Tóm tắt thay đổi:** `useEffect` gọi `lucide.createIcons()` thiếu `activeTracks` trong dependency array → khi track được tạo (user/AI/MIDI import/clone section), DOM nodes mới có `data-lucide` nhưng không được chuyển thành SVG → icon ẩn hoặc hiển thị sai. Fix: thêm `activeTracks` vào deps để auto-refresh icons sau mỗi lần track list thay đổi.
- **Các file ảnh hưởng:** `app/static/js/app.jsx`