- Start/stop Node.js projects (
npm run dev,next dev,vite, ...) - Auto-installs
node_moduleswhen missing - Real-time log streaming (SSE)
- Cache cleaning: Quick Cache, Deep Build, Nuke Reinstall
- Environment variables: view/edit
.env.localor.env - Diagnostics: RAM, CPU, Git branch, Node/npm version
- Auto-start with Windows
- Printer list: shows all local + network printers
- Status: Ready, Printing, Error, Out of paper, Paper jam, Offline
- Auto-detection: polls the spooler every 5 seconds β automatically records completed print jobs
- Print statistics: total prints, last print, recent documents
- LASER detection: auto-detects laser printers β skips reminders + π² badge
- Smart reminders: countdown to next print date, red warning when overdue
- Print queue: view and clear pending jobs
- Test print: sends a test page, automatically recorded to history
- Real-time mic monitoring: detects apps using the mic via the Registry
- Session counter: automatically counts seconds while the mic is active
- Session history: saves time, app, and mic name
- Alert sound: beeps when the mic turns on (if enabled in settings)
- Widget mode: draggable 200Γ200 widget showing status + timer
- Auto show/hide widget: shows when mic active, hides when idle
- Widget opacity: slider from 10% β 100%
- Color customization: pick active/inactive colors with a color picker
- Device control: mute/unmute, adjust volume, set default device
- Keyword search: copies audio/video files based on a keyword list
- 6 source folders: Audio TΓ‘ch GhΓ©p Γm, Video TΓ‘ch GhΓ©p Γm, Audio Δα»c 1 LαΊ§n, Tα»« Δiα»n...
- Conflict handling modes: Overwrite, Skip, or Rename
- MD5 verification: ensures copied files are intact
- Dry Run: preview results without actually copying
- Detailed log: real-time progress
- 100% Vietnamese: entire UI, modals, notifications
- Dark/Light mode: smooth switching
- Responsive: optimized for various window sizes
- Micro-interactions: hover, transition, active scale
(Not available yet β you can add them later)
| Component | Requirement |
|---|---|
| π₯ OS | Windows 10 / Windows 11 (64-bit) |
| π Python | β Not required β the backend is bundled inside the build |
| π¨ Printer | Optional (if using the Printer Module) |
| π€ Mic | Optional (if using the Audio Module) |
| Component | Requirement |
|---|---|
| π₯ OS | Windows 10 / Windows 11 (64-bit) |
| π Python | 3.10+ (runs the backend API + PyInstaller) |
| π¦ Node.js | 18+ (frontend build) |
| π¦ Rust | stable (Tauri build) |
pip install -r backend/requirements.txtIncludes: flask, flask-cors, psutil, pywin32, requests, psycopg2-binary, mysql-connector-python, pycaw
Install PyInstaller (only needed when building the portable):
pip install pyinstallerDownload the .msi or .exe from Releases and run it.
β The new builds bundle the Python backend β end users don't need to install Python or any libraries. The app is self-contained: the backend self-extracts and runs in the background at
%LOCALAPPDATA%\multitool-pro\.
The installer will automatically:
- Create Start Menu + Desktop shortcuts
- Configure the backend to run in the background
# Clone repo
git clone https://github.com/hanumin/multitool-pro.git
cd multitool-pro
# Install frontend
npm install
# Build frontend
npm run build
# Install backend deps + run backend
pip install -r backend/requirements.txt
python backend/app.py &
# Open browser
start http://127.0.0.1:5050# Requirements: Rust + Tauri CLI
npm install -g @tauri-apps/cli
npm run tauri buildOutput files (<version> from src-tauri/tauri.conf.json):
- MSI:
src-tauri/target/release/bundle/msi/MultiTool Pro_<version>_x64_en-US.msi - EXE:
src-tauri/target/release/bundle/nsis/MultiTool Pro_<version>_x64-setup.exe
β οΈ Important note: A barenpm run tauri buildruns with the empty placeholderbackend-embed/backend.exeif PyInstaller hasn't been run (build.rs auto-creates a placeholder so the code compiles + warns). The resulting installer will not contain the backend β use Option 4 for a proper self-contained build.
A portable build = a single .exe containing the frontend + Python backend + every dependency. It runs on any Windows machine, no Python install required.
# Run from the project root (PowerShell)
./build-portable.ps1The automated pipeline consists of 4 steps:
npm run buildβ build the frontend intodist/- PyInstaller β package
backend/app.py+ Flask + all dependencies intobackend.exe(~38 MB, also embedsdist/,auto-start.ps1,printer-monitor/) - Embed β copy
backend.exeintosrc-tauri/backend-embed/soinclude_bytes!embeds it directly into the Rust binary npx tauri build --no-bundleβ produce the portable exe + copy intorelease/portable/
Output (<version> from src-tauri/tauri.conf.json):
release/portable/MultiTool Pro_<version>_x64.exe (~47 MB)
Self-contained runtime: on startup, Rust extracts the backend from the embedded bytes into %LOCALAPPDATA%\multitool-pro\backend\backend.exe (only writes when missing/different size) then spawns it. Debug builds prefer running python from source for faster dev; release builds use the embedded backend.
π‘ User data (config, printer settings, debug.log) stays in
%APPDATA%\multitool-pro\β installing a new version won't lose old data.π After building, if the old version is still running it will lock the file β close the app (or run
scripts/cleanup-portable-test.ps1) before rebuilding.
The .github/workflows/build.yml workflow builds multi-platform releases (Windows x64 + macOS universal2):
| Trigger | Result |
|---|---|
Push main |
Build portable + installer NSIS/MSI β upload artifact |
Push tag v* |
Create a GitHub Release with installer + latest.json (auto-update) |
| Run workflow | Manual build from the GitHub UI |
The CI pipeline is identical to build-portable.ps1: npm build β PyInstaller β embed β tauri build (Windows: NSIS/MSI + portable; macOS: .app + .dmg universal). Pushing a v* tag creates a GitHub Release with the installer + latest.json (auto-update).
π Auto-update needs a signing key: generate one with
npx tauri signer generate -w ~/.tauri/multitool-pro.key, then add it to GitHub Secrets asTAURI_SIGNING_PRIVATE_KEY(+TAURI_SIGNING_PRIVATE_KEY_PASSWORDif set). With a key, Tauri signs the installer and generates a.sigβlatest.jsonis created β installed apps pick up the new version automatically. Without a key, CI still builds and releases normally, just without auto-update.
The app uses shared Supabase Auth with the ecosystem (the web app english-topics β one shared account pool). Log in once, use it everywhere in the ecosystem.
βββββββββββββββββββββββββββ ββββββββββββββββββββββββββββββββ
β App desktop (Tauri) β β Web english-topics β
β - Supabase anon key βββauthβββΆ - Supabase anon key (client) β
β (embedded, public) β β - SERVICE ROLE key (server) β
ββββββββββββββ¬βββββββββββββ ββββββββββββββββ¬ββββββββββββββββ
β β
ββββββββββββββββΆ Supabase Auth (xjfttrbucggqieykjqxu) ββββββ
β’ 1 shared account pool
β’ RLS protects each app's data
- URL + anon key are PUBLIC keys (Supabase's official design for clients) β safe to embed in the app.
- The service role key MUST NEVER be embedded in the app β it lives only on the web server (Vercel) because it bypasses RLS.
- Email + password (with optional Stay signed in β the session persists across app launches)
- Forgot password: checks whether the email is registered first (calls the web endpoint
POST /api/auth/check-emailβ the service role key stays server-side, never exposed to the app) β only real emails get a reset link - Sidebar avatar: click it β popup to change avatar, sign out, or change password
1. Supabase Dashboard β Authentication β URL Configuration:
| Item | Value |
|---|---|
| Site URL | https://english.luongphamhanhnguyen.com |
| Redirect URLs | https://english.luongphamhanhnguyen.com/** (add the /forgot-password path too if needed) |
β οΈ If missing, the password reset link in the email falls back tolocalhost:3000β users won't be able to reset their password.
2. Vercel (web project) β Environment Variables (Production):
NEXT_PUBLIC_SITE_URL=https://english.luongphamhanhnguyen.com
Used by the
POST /api/auth/forgot-passwordroute (web) to build a recovery link with the correct domain. After changing the env β redeploy production.
Edit 2 places in src/lib/supabase.ts: SUPABASE_URL + SUPABASE_ANON_KEY, and change the CHECK_EMAIL_API endpoint in src/components/LoginScreen.tsx (if using a different web).
- Left sidebar: choose a module
- Bottom status bar: shows system notifications
- Top-right: general settings, light/dark mode, minimize to tray
1οΈβ£ Add project: Settings β "Add project" β enter name, path, port, command
2οΈβ£ Start: click the Play button next to the project
3οΈβ£ View logs: click the project tab to see real-time logs
4οΈβ£ Stop: click the Stop button
5οΈβ£ Clean: click "Clean" β choose a level (Quick Cache / Deep Build / Nuke Reinstall)
6οΈβ£ Environment variables: click "Environment variables" β edit .env.local
1οΈβ£ Open the Printers module β the printer list loads automatically 2οΈβ£ Monitoring: the app auto-selects the default printer; click any printer to change it 3οΈβ£ Test print: click "π¨ Test print" (only for non-laser printers) 4οΈβ£ Queue: click "π Print queue" β view/clear jobs 5οΈβ£ Statistics: click "π Statistics" β see total print counts 6οΈβ£ Settings: adjust the days between prints and the reminder interval
π‘ Laser printers (name contains "laser") are auto-detected and skip reminders.
1οΈβ£ Open the Audio module β see real-time mic status 2οΈβ£ Counter: counts automatically while the mic is active 3οΈβ£ History: click "π History" β view previous sessions 4οΈβ£ Widget: click "π² Minimize" β a draggable 200Γ200 widget appears 5οΈβ£ Settings: click "βοΈ Settings" β customize:
- Alert sound when the mic turns on
- Auto show/hide widget when the mic turns on/off
- Widget opacity (10% β 100%)
- Active/inactive colors
π‘ The widget auto-appears when the mic is active (if enabled in settings).
1οΈβ£ Open the Copy module β enter keywords (manually or from a .txt file) 2οΈβ£ Choose source folders (up to 6) 3οΈβ£ Choose the destination folder 4οΈβ£ Customize: file extensions, MD5 verification, conflict mode 5οΈβ£ Click "π Dry Run" to preview 6οΈβ£ Click "π Start copying" to run it
multitool-pro/
βββ backend/ # Python Flask API
β βββ app.py # Main backend server
β βββ requirements.txt # Python dependencies
βββ src/ # React frontend (TypeScript)
β βββ App.tsx # Root component
β βββ index.css # Global styles
β βββ types/ # TypeScript interfaces
β βββ components/ # Sidebar, modals, modules/
βββ src-tauri/ # Tauri desktop wrapper
β βββ src/lib.rs # Rust β spawn backend (embedded / python fallback)
β βββ build.rs # Ensures backend-embed/backend.exe exists for embedding
β βββ backend-embed/ # Built backend.exe (gitignored) β include_bytes!
β βββ tauri.conf.json
β βββ Cargo.toml
βββ scripts/ # Utility scripts (cleanup-portable-test.ps1, ...)
βββ build-portable.ps1 # Build the self-contained 1-file portable
βββ .github/workflows/ # CI: ci.yml + why-check.yml + build.yml (multi-platform build & release)
βββ release/ # Output: installers + portable/ (gitignored)
βββ dist/ # Built frontend
βββ package.json
MultiTool Pro was developed with the help of Freebuff, an AI coding agent.
I am a scientist rather than a professional software developer, so my development workflow focuses on describing the problems and workflows I want to solve. Freebuff helps translate those requirements into implementation, while I review, test, and iterate on the resulting application.
I have used Freebuff for feature implementation, investigating the existing codebase, debugging, refactoring, and integrating the different components of the project β iterating on features based on how they behave in real-world use. Before Freebuff, the project was developed with other AI coding tools, including Claude, Codex, and Antigravity, and parts of the codebase and documentation reflect that history.
The repository also makes use of AI-agent skills and workflows where they are useful, such as spec-driven development plans and specs (docs/superpowers/, .superpowers/sdd/), the GitNexus code-intelligence skills for exploring, impact analysis, and refactoring (AGENTS.md, CLAUDE.md), and the web-design-guidelines skill for UI review.
Backend runs at http://127.0.0.1:5050
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/projects |
List projects |
| POST | /api/projects/{name}/start |
Start |
| POST | /api/projects/{name}/stop |
Stop |
| GET | /api/projects/{name}/logs |
Get logs |
| GET | /api/projects/{name}/logs/stream |
Real-time logs (SSE) |
| GET | /api/projects/{name}/diagnostics |
Diagnostics (RAM, CPU, Git) |
| GET/PUT | /api/projects/{name}/env |
Environment variables |
| POST | /api/projects/{name}/clean |
Clean |
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/printers |
List printers |
| GET | /api/printers/{name}/jobs |
Print queue |
| DELETE | /api/printers/{name}/jobs |
Clear queue |
| POST | /api/printers/{name}/default |
Set default |
| POST | /api/printers/{name}/test |
Test print |
| GET | /api/printer/stats |
Print statistics |
| GET | /api/printer/activity |
Current print activity |
| POST | /api/printer/auto-detect |
Auto-detect print |
| GET | /api/printer/reminder-check |
Check reminders |
| GET/POST | /api/printer/settings |
Printer settings |
| GET/POST | /api/printer/log |
Print log |
| GET/POST/DELETE | /api/printer/history |
Print history |
| GET | /api/printer/wmi-status |
WMI status |
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/audio/devices |
List devices |
| GET | /api/audio/mic-status |
Mic status |
| POST | /api/audio/devices/{id}/mute |
Mute/unmute |
| PUT | /api/audio/devices/{id}/volume |
Adjust volume |
| POST | /api/audio/devices/{id}/default |
Set default |
| GET/POST | /api/audio/settings |
Audio settings |
| GET | /api/audio/session-history |
Session history |
| POST | /api/audio/session-log |
Log session |
| GET | /api/audio/sound-files |
List sound files |
| Method | Endpoint | Description |
|---|---|---|
| POST | /api/file-copier/count |
Count files in folder |
| POST | /api/file-copier/read-keywords |
Read keyword file |
| POST | /api/file-copier/run |
Run copy |
- π Forgot password: when rate-limited, the wait message now shows "59 seconds / 5 minutes / 1 hour" instead of raw seconds (e.g. "3600 seconds")
- βοΈ Reset emails from a dedicated domain: now sent from
auth.luongphamhanhnguyen.com(via Resend SMTP) instead ofnoreply@supabase.coβ less likely to land in spam - β¬οΈ Reset email limit raised to 60 emails/hour (previously 2/hour)
- π Fixed password reset link: it previously pointed to a dead domain (
english-topics.vercel.app) so Supabase fell back tolocalhost:3000β broken link. Now points to the LIVE web's password reset page (english.luongphamhanhnguyen.com/forgot-password) - π§ Forgot password: checks whether the email is registered first β if not, shows "Email not registered" instead of a fake success message (checked via the web server, without exposing the Supabase service role key)
- π§Ή Removed the tooltip when hovering the system-account login label
- πΌ Compact avatar popup: removed the "Local pets" and "Custom input" tabs β only Codex Pets + Emojis (simpler, less clutter)
- π System Configuration popup: brighter left menu, unselected labels + icons switched to light readable colors (previously dark gray, hard to read)
- π Old avatars stored as URL/file names still render correctly (only the picker options changed, saved data is intact)
- πΌ Change avatar from sidebar: click the avatar in the sidebar corner (or the "Change avatar" item) β popup: choose Codex Pets (self-hosted library on R2), emoji, or paste a custom image link
- π¨ Avatar background color (12 swatches) β saved with the avatar, synced with the web english-topics (change it once, seen everywhere)
- π Fixed old Codex pet avatars displayed as raw text
codex:xxxβ now resolved to the correct animated image from the library - π§ Login screen: title & description moved closer together with consistent spacing to the features block β more balanced left panel
- π Professional auto-update popup: one popup handles both checking and installing with clear states (checking, update available, downloading %, installing, done, error)
- πͺ Floating popup with no dimmed backdrop β the app below stays visible during updates
- π Repair feature: re-downloads the exact current version and installs over it β restores broken/missing files without upgrading
- π Shows real download progress (%, downloaded/total size) + expandable release notes right in the popup
- β± Auto-checks for updates on startup β only shows the popup when an update exists (no nagging)
- π¦ Cleaner GitHub releases: only installers (.msi/.exe/.dmg/.app.tar.gz) + signature, removed extra raw binaries
- π Completed auto-update: installers are code-signed in CI, the app detects new versions via the "Check updates" button
- π Multi-platform builds: GitHub Actions builds Windows + macOS Universal (runs on both Intel and Apple Silicon Macs)
- π Mac builds auto-hide Windows-only modules (Audio, Printers, Tunnel) β cleaner UI, no crashes
- πͺ Window size picker: 7 levels from 720p to 1440p + warning when larger than the screen
- πΎ Saves and restores window position + size on close/open (including maximized state)
- β¨ Smooth animations for server cards, sidebar, titlebar, Settings/Changelog modals, and status text
- π§ Polling fixes: longer retry delay, cancel overlapping requests, stagger initial load between modules
- π· Changed the label "Reconnecting..." to "Loading data..." for the first load
- π¦ Self-contained portable: Python backend (Flask + all deps) packaged with PyInstaller β embedded directly into the Tauri binary (
include_bytes!) β runs without installing Python, a single.exe(~47 MB) - π₯ Fluent UI tray menu: custom system tray menu (glassmorphism, zero left padding) β module navigation, Start/Stop All, audio widget toggle, auto-hide on focus loss, IPC event bus (
tray-command) - π¨ LAN Printer Scan: auto-scans the network for unconfigured printers β Windows toast with an "β‘ Assign IP" button (deep-link opens the Printers tab directly), periodic scans + retry when toast fails
- π¨ Supplies & Consumables: configure a network printer IP β auto-reads toner/drum/ink % via SNMP (RFC 3805, pure Python), or manual input for USB printers; low-supply thresholds
- π¨ Background Print Listener: detects completed print jobs with
FindFirstPrinterChangeNotification(event-driven, catches even <100ms laser jobs) β no missed jobs when the UI is on another tab - βοΈ CI release builds: GitHub Actions workflow (
build.yml) β npm build β PyInstaller β embed β tauri build (Windows NSIS/MSI + macOS universal) β artifact + GitHub Release +latest.json(signed auto-update) onv*tags - π§
build-portable.ps1: automated self-contained portable build script covering the whole pipeline
- π€ Audio set-default v2 rewrite: setting the default mic now works reliably (Core Audio GUID instead of device index), verifies the change with backoff retry, comtypes crash protection
- π§© Centralized audio widget management (
audioWidget.ts) β syncs state between the module, tray menu & Rust
- π¨ Major UI overhaul: redesigned server cards (compact footer, removed duplicate tunnel URL), consolidated into 1 settings button
- π»π³ 100% Vietnamese UI (fully completed vs. the previous version)
- π Fixed tunnel metrics polling (metrics weren't refreshing on schedule)
- π₯ Servers: reworked the follow flow, batch actions & improved npm scripts runner
- π Increased window size + font, responsive sidebar auto-collapse on small screens
- π¨ GDI printer detection: auto-detects GDI (host-based) printers β
driver_typebadge, skips empty EventLog, WMI fallback
- π¨ Printer page count fixes: C#/PowerShell monitor module (fast XPath query), fixed Properties[3]β[4] for printer names (tested on real Windows 11)
- π Fixed PermissionError when starting projects, fixed audio API 501, updated dependencies
- π Database Export: export data as CSV/JSON, SQL syntax highlighting
- π Logs Download: download logs, improved accessibility
- π Database Manager: connect to SQLite/PostgreSQL/MySQL, SQL editor, view tables/data
- β‘ Batch Actions: Start/Stop/Restart All
- π Port Scanner: detect port conflicts, Quick SSL
- π Log Search: log search + npm Scripts runner
- π Performance History + Disk Usage cache
- π»π³ Vietnamese main UI (fully completed in v1.11.2)
- π¨ Printer: auto-watching + auto-detect print + laser detection + statistics
- π€ Audio: auto show/hide widget, opacity slider, session timer
- π Single Instance Lock (prevents running 2 windows)
- π Fixes:
globalkeyword, thread safety, Promise.all crash
- π¨ Printer Module: WMI status, reminder, history
- π€ Audio Module: Widget mode, color themes, alert sound
- πΌ Custom icon from
icon.png
- π File Copier Module: keyword copy, MD5, dry run
- β‘ Optimized polling intervals
Contributions are welcome! Please:
- Fork the repo
- Create a new branch (
git checkout -b feature/feature-name) - Commit your changes (
git commit -m 'Add feature X') - Push the branch (
git push origin feature/feature-name) - Create a Pull Request
Distributed under the MIT license.
Built with β€οΈ by hanumin