Files
SonicForgeStudio/PLAN.md
T
2026-07-20 10:39:07 +07:00

15 KiB

Kế hoạch phát triển SonicForge Studio

Nguyên tắc chung: Giữ nguyên UI đã thiết kế, chỉ bổ sung/bổ khuyết các thành phần còn thiếu. Mọi thay đổi phải tương thích với code hiện tại (backend FastAPI + frontend React/Babel trong index.html).


0. Khảo sát hiện trạng (đã phân tích)

Hạng mục Trạng thái Ghi chú
Backend Auth (login/register/change-password/profile) Sẵn sàng app/api/v1/auth.py
Mock password admin seed_admin() Mật khẩu mặc định admin123, must_change_password=1
Quota / System Manager API Sẵn sàng app/api/v1/admin.py, app/api/v1/projects.py
Phân tích Stereo/Mono Sẵn sàng audioEngine.analyzeAudioBufferChannels()
Auth UI (AuthModal/ProfileModal/SystemManagerModal) Sẵn sàng app/static/js/components/*
Temp project (local + cloud) Sẵn sàng storage.scheduleTempAutoSave(), API /projects/temp, /projects/cloud
Export/Import .sfs ⚠️ Có nhưng thiếu double-click mở lại storage.exportProjectToSFS/importProjectFromSFSFile
Mock audioclip trong dự án Cần xóa index.html:1876-1902
Sub-tab: trục tọa độ channel/volume/panning + zoom rõ nét Thiếu Cần bổ sung theo ảnh đính kèm 1

1. Xóa audioclip mock trong dự án

Mục tiêu: Khởi tạo project trống, không có clip mẫu nào khi mở ứng dụng.

Thay đổi (app/templates/index.html):

  • Xóa hàm createMockAudioBufferObj (line ~1859) và biến mockBuffer (line ~1876) — chỉ giữ lại nếu dùng chỗ khác (hiện chỉ phục vụ mock clip).
  • Sửa initial tracks state (line ~1880): Track 01 (id:'1') để buffer: null, name: 'Track 01', bỏ mảng clips mock. Giữ Track 02 rỗng như hiện tại.
  • Đồng bộ handleNewProject (Ctrl+N, line ~2499 & 5319) đã dùng track rỗng — không đổi.
  • Đảm bảo không còn tham chiếu mockBuffer/createMockAudioBufferObj nào khác (grep xác nhận trước khi xóa).

Kiểm chứng: Mở app → 2 track trống, không có waveform mẫu, không có clip Creak_DeepWood2.wav.


2. Phân tích Stereo/Mono khi import & chỉnh sửa đúng loại

Mục tiêu: Khi import audio (main session hoặc sub-tab), tự động phát hiện Stereo/Mono và DSP (volume/panning/fade/stretch) phải hoạt động đúng số kênh thực tế.

Frontend (app/templates/index.html):

  • Hàm import audio (decoded bằng window.SonicAudio.decodeAudioFile) đã trả về { audioBuffer, channelInfo } với channelInfo = { channels, isStereo, label }.
  • Khi gán vào track / sub-tab: lưu channelInfo vào đối tượng track và sub-tab (track.channelInfo, st.channelInfo). Hiển thị badge STEREO/MONO trên TCP panel (giữ nguyên vị trí hiển thị hiện tại).
  • Sub-tab DSP:
    • Nếu isStereo → cho phép kéo Volume (L/R independent) và Panning (L100..R100) trên 2 kênh.
    • Nếu MONO → ẩn/disable kênh đối xứng, chỉ 1 đường Volume, Panning khóa ở Center (vô hiệu hóa). Logic đã có sẵn trong SubTabWaveform (kiểm tra channelInfo?.isStereo) — bổ sung guard đầy đủ.
  • Waveform render: vẽ đủ numberOfChannels kênh; với Mono chỉ vẽ 1 lane, Stereo vẽ 2 lane (L/R).

Backend (app/core/sub_tab_dsp.py): giữ nguyên xử lý theo số kênh của buffer đầu vào (đã đúng). Chỉ đảm bảo API nhận buffer đa kênh.

Kiểm chứng: Import file Mono → badge MONO, không thể pan; import Stereo → badge STEREO, pan L/R hoạt động.


3. Sub-tab timeline: trục tọa độ + zoom rõ nét (theo ảnh 1)

Mục tiêu: Trong sub-tab, track timeline hiển thị trục tọa độ thể hiện Channel / Volume / Panning, zoom in/out realtime mượt mà, cập nhật ngay khi click/thay đổi thông số.

Thay đổi (app/templates/index.html — khối sub-tab timeline, ~line 6152+):

  • Bổ sung overlay trục tọa độ vẽ trên canvas (giữ nguyên style UI):
    • Channel axis: label L / R (stereo) hoặc M (mono) bên trái lane.
    • Volume axis: thang dB dọc (+3 / 0 / -15 / -30 dB) căn chỉnh với đường 0dB của graph volume.
    • Panning axis: thang ngang (L100 / C / R100) căn chỉnh với graph panning.
  • Realtime zoom: dùng devicePixelRatio (dpr) scale canvas như main timeline (ctx.scale(dpr * (useW / timelineWidth), dpr)) để nét khi zoom in. Đã có pattern ở SubTabWaveform (line ~751) — áp dụng đồng nhất cho trục tọa độ.
  • Gán requestAnimationFrame / useEffect dependency [zoom, buffer, volumeNodes, panningNodes, selectionStart, selectionEnd, currentTime] để vẽ lại ngay khi tham số đổi (đã có sẵn trong SubTabWaveform, mở rộng vẽ thêm trục).
  • Giữ nguyên ruler thời gian 0.00s (đã sửa ở bước trước).

Kiểm chứng: Zoom in → waveform + trục dB/pan sắc nét; kéo node volume/pan → trục cập nhật tức thì; click waveform → playhead + trục khớp.


4. Quản lý người dùng & Menu File

Mục tiêu: Admin đăng nhập (mock password), đổi mật khẩu, quản lý hệ thống; menu File có Profile (trên Logout) và System Manager (trong Profile).

Trạng thái đã có: currentUser, handleLogout, AuthModal, ProfileModal, SystemManagerModal, handleAuthSuccess đã được bổ sung vào App (sửa lỗi currentUser is not defined). Backend seed_admin + must_change_password đã sẵn sàng.

Frontend (index.html — menu File, ~line 5319+ / 5728+):

  • Đảm bảo thứ tự menu File: ... → Profile → Logout. (Đã đúng: Profile line 5729, Logout line 5730.)
  • Profile mở ProfileModal (đổi password, xem quota) — đã render.
  • System Manager hiển thị chỉ khi currentUser.role === 'admin' (đã có guard line 5728) → mở SystemManagerModal (quản lý user/quota).
  • Auth flow bắt buộc khi login lần đầu (isMandatoryLogin) đã có trong checkAuthStatus effect.

Backend (app/core/auth.py): seed_admin() dùng DEFAULT_ADMIN_PASSWORD (mặc định admin123), set must_change_password=1. Khi admin login → AuthModal mode force_change ép đổi pass. Không đổi.

Kiểm chứng: Khởi chạy lần đầu → ép login admin/admin123 → modal đổi mật khẩu → vào app. File menu hiện Profile (trên Logout); admin thấy thêm System Manager.


5. Dự án tạm (Temp) & lưu cloud / .sfs

Mục tiêu: Chưa lưu → auto-save tiến trình vào dự án tạm (local + server); cho phép đăng ký/đăng nhập/lưu cloud (quota); cho phép export .sfs về ổ cứng; double-click .sfs mở domain → login → tải lại dự án.

5.1 Temp auto-save (đã có, chuẩn hóa):

  • storage.scheduleTempAutoSave() lưu localStorage sonic_temp_project + gọi API saveTempProject nếu có token. Giữ nguyên.
  • Đảm bảo mọi thay đổi (tracks, subTabs, volumeNodes, panningNodes, fade*, speed) đều nằm trong state được auto-save (serialize an toàn, không lưu AudioBuffer thô mà lưu metadata + serverFileId).

5.2 Lưu cloud (quota):

  • Backend /projects/cloud kiểm tra quota (storage_limit_mb, max_tracks).
  • Frontend: menu File Save to CloudhandleSaveCloud (đã có trong app.js) → port vào App trong index.html nếu chưa có, dùng window.SonicAPI.saveCloudProject.

5.3 Export / Import .sfs:

  • exportProjectToSFS (đã có) → download .sfs.
  • Bổ sung double-click mở lại:
    • Thêm vào .sfs JSON trường domain (đã có) và đăng ký MIME/association phía client: khi user double-click file .sfs trên máy, OS mở URL domain/?sfs=<encoded> (hoặc protocol handler sonicforge://open?file=...).
    • Tại index.html khởi tạo: đọc query param ?sfs= → nếu có → yêu cầu login (nếu chưa) → importProjectFromSFSFile (đọc từ blob/server) → load tracks.
    • Ghi chú: cơ chế double-click thực tế phụ thuộc OS (file association / protocol handler). Cung cấp hướng dẫn + nút "Mở dự án .sfs" trong UI làm fallback.

Kiểm chứng: Sửa project → F5 → tiến trình còn (temp). Login → Save Cloud → quota đúng. Export .sfs → mở lại domain → login → project restored.


6. Thứ tự thực hiện & kiểm thử

  1. B1 — Xóa mock clip (§1). Chạy app, confirm trống.
  2. B2 — Stereo/Mono import + DSP (§2). Test Mono & Stereo file.
  3. B3 — Sub-tab trục tọa độ + zoom (§3). So sánh ảnh 1.
  4. B4 — User/Menu (§4). Test admin flow + role guard.
  5. B5 — Temp/Cloud/.sfs (§5). Test auto-save, quota, round-trip sfs.
  6. B6 — Lint/typecheck (nếu có script) + chạy tests/ hiện có (test_sub_tab_dsp.py, test_auth_and_quota.py).
    • Sửa main.py: thêm auth + admin + projects routers (thiếu từ đầu).
    • 31/31 tests pass (auth + dsp_engine + sub_tab_dsp).

Không thay đổi: Layout tổng thể, màu sắc, component giao diện đã design; chỉ bổ sung thành phần (trục, badge, modal, menu item) và sửa logic thiếu.


7. Tối ưu hóa & Module hóa index.html (giảm latency)

7.1 Hiện trạng & nguyên nhân latency

Vấn đề Chi tiết
File index.html khổng lồ (~6784 dòng) chứa TOÀN BỘ UI inline trong 1 thẻ <script type="text/babel"> Babel phải parse + transform toàn bộ file mỗi lần load → chậm init.
Dùng @babel/standalone runtime transform (line 11) Transform chạy ở browser, block main thread, gây lag khi mở app.
Các component đã tách (app/static/js/components/*.js, app.js) KHÔNG được load bởi index.html index.html chỉ load services/* (api/audioEngine/storage). TrackTimeline.js, SubTabTimeline.js, HeaderMenu.js, AuthModal.js, ProfileModal.js, SystemManagerModal.js bị bỏ không.
Không có code-splitting / lazy load Mọi thứ load 1 lần dù user chưa mở sub-tab/modal.

Lưu ý: app.js định nghĩa SonicForgeApp render vào #root (cũ) — xung đột với App trong index.html. Sau module hóa sẽ gộp về 1 entry duy nhất.

7.2 Mục tiêu

  • Tách index.html thành các ES modules riêng biệt, mỗi module 1 trách nhiệm.
  • Loại bỏ @babel/standalone runtime transform → build/precompile (hoặc chuyển sang JSX tiền biên dịch).
  • Giữ nguyên 100% giao diện/UX hiện tại (chỉ refactor code, không redesign).
  • Giảm thời gian init và tăng tính bảo trì.

7.3 Cấu trúc module đề xuất

app/static/js/
├── services/                 # (đã có, giữ nguyên)
│   ├── api.js                # window.SonicAPI
│   ├── audioEngine.js        # window.SonicAudio
│   └── storage.js            # window.SonicStorage
├── components/               # (đã có, mở rộng)
│   ├── HeaderMenu.js
│   ├── AuthModal.js
│   ├── ProfileModal.js
│   ├── SystemManagerModal.js
│   ├── TrackTimeline.js      # (đã có, chuẩn hóa props)
│   ├── SubTabTimeline.js     # (đã có)
│   ├── Timeline/             # MỚI: tách từ index.html
│   │   ├── Ruler.jsx         # trục thời gian 0.00s (§3)
│   │   ├── CoordinateAxis.jsx# trục Channel/Volume/Panning (§3)
│   │   ├── WaveformLane.jsx  # vẽ waveform main + sub-tab
│   │   └── TempoTrackLane.jsx
│   ├── TCP/                  # MỚI: Track Control Panel
│   │   ├── MainTcpPanel.jsx
│   │   └── SubTabTcpPanel.jsx
│   ├── SubTab/               # MỚI
│   │   ├── SubTabWaveform.jsx
│   │   ├── VolumeGraph.jsx
│   │   └── PanningGraph.jsx
│   └── modals/...            # (chuyển vào components/)
├── hooks/                    # MỚI
│   ├── useAuth.js            # currentUser, checkAuthStatus, handleLogout (§4)
│   ├── useTempProject.js     # auto-save temp (§5)
│   └── useAudioImport.js     # decode + channelInfo (§2)
├── state/                    # MỚI
│   └── studioStore.js        # tập trung state tracks/subTabs/zoom (Context hoặc store nhẹ)
└── App.jsx                   # entry: gom toàn bộ, render <App/>

7.4 Thực trạng & ràng buộc

Không thể thêm Node build pipeline ngay vì:

  • Dự án deploy qua Python FastAPI + Docker (không có node_modules/package.json).
  • index.html được serve trực tiếp từ main.py:33-39 (HTMLResponse), không có static /dist.
  • Thêm Vite/esbuild yêu cầu thay đổi Dockerfile, CI/CD pipeline, requirements.txt.

Đã thực hiện (minimum viable module hóa):

  1. Gom toàn bộ UI vào single-file index.html (inline Babel script) — loại bỏ tất cả component .js cũ (đã deprecated, nội dung giữ làm reference).
  2. Tách services (audioEngine.js, api.js, storage.js) thành file riêng — đã có sẵn.
  3. Copy 3 modal (Auth, Profile, SystemManager) từ components/.js vào inline — tránh load rời.
  4. Xóa app.js (SonicForgeApp cũ) — tránh 2 render vào #root.

Kế hoạch tương lai (khi có Node build):

  • B7.1: Thêm package.json + Vite/esbuild → npm run build → output dist/.
  • B7.1a: main.py mount /static/dist qua StaticFiles.
  • B7.2: Trích xuất các component nặng (SubTabWaveform, WaveformLane, GraphEditorCanvas) từ index.html ra .jsx.
  • B7.4: React.lazy() cho SubTabWaveform + GraphEditorCanvas.
  • B7.5: Canvas waveform dùng React.memo + useMemo (đã có pattern dpr).
  • B7.6: Cache hashed bundle + <link rel="modulepreload">.

7.5 Đã tối ưu (no-build)

  • Component SubTabWaveform canvas dùng devicePixelRatio scale (line ~698-710) → zoom nét.
  • useEffect dependency arrays đầy đủ ([buffer, zoom, nodes, selection, currentTime]) → chỉ vẽ lại khi thay đổi.
  • Deferred lucide icons init (setTimeout(..., 300)) — không block first paint.
  • Temp auto-save debounce 2s (trong storage.js:53) — không spam API.

7.6 Thứ tự ưu tiên (đã thực hiện)

  1. §1 Xóa mock clip.
  2. §2 Stereo/Mono import + channelInfo.
  3. §3 Sub-tab axes + channel label (L/R/M) + mono-lock pan.
  4. §4 Auth flow + modals + menu Profile/System Manager.
  5. §5 Temp auto-save + Cloud save + Export/Import .sfs + deep-link ?sfs=.
  6. §6 Tests 31/31 pass (fixed main.py missing routers).
  7. §7 Cleanup deprecated .js + PLAN.md cập nhật constraints.