Skip to content

Commit 7fd6c23

Browse files
committed
Install/launch UX audit: 12 problems + 12 recommendations (no code yet)
1 parent d7a55b6 commit 7fd6c23

1 file changed

Lines changed: 148 additions & 0 deletions

File tree

INSTALL-LAUNCH-IMPROVEMENTS.md

Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
# Install + Launch UX — current state + recommendations
2+
3+
## Current state (what works today)
4+
5+
- **Windows**: Double-click `AdForge.bat` → first-run installs deps, writes `.env.local`, creates Desktop shortcut. Subsequent runs: port resolver picks a free pair, sidecar starts hidden, browser opens to launcher.
6+
- **macOS / Linux**: Double-click `AdForge.command` → same flow.
7+
- **Online install**: `curl …/install.sh | bash` or `iwr …/install.ps1 | iex` clones the repo + runs the launcher.
8+
- **Port resolver** (`scripts/resolve-ports.cjs`): handles 5 conflict cases (reuse / restart_stale / shifted / start / error) and walks **3010 → 5010** in pairs (even/odd) looking for a free pair.
9+
10+
### What's still rough (real user pain points)
11+
12+
| # | Problem | Why it bites |
13+
|---|---|---|
14+
| 1 | **Port defaults are 3005/3006** — the most-collided ports in dev (every Next.js app uses 3000-3010). | New users hit port conflicts immediately, fall through to "shifted" path. Their saved bookmark / Desktop shortcut may go stale. |
15+
| 2 | **Walks 3010 → 5010 sequentially** — predictable, so a 2nd AdForge install always lands at 3010 and a 3rd at 3012, never far from contested space. | Same as above — collision-prone. |
16+
| 3 | **No Node detection on first run** — user double-clicks, sees a stack trace, doesn't know what's missing. | Currently the .bat does check, the .command doesn't. |
17+
| 4 | **`.command` files don't always run on macOS** — Gatekeeper blocks unsigned scripts; user has to right-click → Open → Confirm the first time. | Newcomer doesn't know this and assumes "it's broken." |
18+
| 5 | **No graphical installer** — every install path requires command line or shell file. Non-technical users can't onboard. | Limits audience. |
19+
| 6 | **Browser doesn't refresh open tabs** when the user runs the launcher a second time. | They see a stale page from a previous session, think it's broken. |
20+
| 7 | **Desktop shortcut is a `.lnk` to a `.bat`** — runs in a CMD window for ~2s on every launch. Not "click → app opens" feel. | Looks janky. Also: shortcut points at a fixed path; if user moves the install folder, shortcut breaks. |
21+
| 8 | **No version / update check on launch** — user runs an old version without knowing newer one exists. | Stale install drift. Auto-update endpoint exists but only fires from the launcher UI, not on launch. |
22+
| 9 | **No "is this thing already running?" check before spawning** — port resolver handles it, but there's no fast-path for "user just clicked AdForge.bat twice in 2 seconds." Both processes try to write to .env.local. | Theoretical race. |
23+
| 10 | **Settings + saved data live in the install folder** (`data/snapshot.json`, `.env.local`). If user upgrades by re-cloning into a new folder, their data doesn't follow. | Migration friction. |
24+
| 11 | **No "uninstall" path** — leaves the Desktop shortcut, IndexedDB data (which is per-origin, so per-port → multiple stale entries if port shifted multiple times). | Cleanup debt. |
25+
| 12 | **Browser opens to the launcher control panel, not the app** by default. User has to click "Open Web App" then. | One extra click every launch. |
26+
27+
---
28+
29+
## Recommendations — ranked by impact vs effort
30+
31+
### Tier 1 — Ship now (high impact, small change)
32+
33+
#### R1. Move default ports out of the 3000-range entirely
34+
**Change:** Default to `41573` (web) + `41574` (sync), or another high-numbered pair (40000–49999 range is least-collided IANA registered-but-rarely-used).
35+
- Tradeoff: less guessable, but the launcher already shows the URL clearly.
36+
- Implementation: `scripts/resolve-ports.cjs` default + `AdForge.bat` / `AdForge.command` initial `.env.local` writers.
37+
- **Bonus**: deterministically derive the default port from the install folder path (`hash(cwd) % 10000 + 40000`) so two installs in different folders start at different bases without ever colliding.
38+
39+
#### R2. Use OS-assigned random ports on first run
40+
**Change:** When `.env.local` doesn't exist, ask the OS for two ephemeral free ports (bind to `:0`, read back the assigned port, immediately release) → write THOSE to `.env.local`. Zero chance of collision because the OS just told us the port is free at that moment.
41+
- Tradeoff: same install gets a different port next time the OS hands a different ephemeral. So: only do this ONCE (first run), then persist.
42+
- Implementation: ~10 lines in `resolve-ports.cjs`.
43+
44+
#### R3. Add browser tab refresh trigger on launch
45+
**Change:** Sidecar `/health` endpoint already returns when it starts. Have the launcher write a "session ID" the page can check via `EventSource` or simple polling; when it changes, force a soft reload.
46+
- Better UX: user clicks AdForge.bat → existing tab in their browser reloads itself, no new tab opened.
47+
48+
#### R4. Fix the `.command` Gatekeeper issue
49+
**Change:** Add a `chmod +x AdForge.command` + a one-page README chunk explaining the macOS first-launch right-click flow. Ideally bundle a `.app` (see Tier 2).
50+
51+
### Tier 2 — High effort, transformative UX
52+
53+
#### R5. Real native installer / `.app` / `.exe` wrapper
54+
**Options:**
55+
56+
- **Tauri** (Rust+web — produces a tiny native binary, ~10MB):
57+
```
58+
npx create-tauri-app
59+
```
60+
Wraps the Next.js export in a webview, runs the sidecar as a child process, auto-detects ports. Native menu bar / system tray.
61+
- **Electron** (heavier, ~100MB) — more battle-tested but big.
62+
- **Nativefier / pake** (zero-code wrapper) — fast hack, ugly result.
63+
64+
**My recommendation: Tauri.** Three reasons:
65+
1. The app IS already a static-export-ready Next.js build — Tauri loads it from disk.
66+
2. Bundle size matters when distributing to users who'll run AdForge locally; Electron's 100MB-per-install is overkill.
67+
3. Tauri's child-process API can launch + supervise the sidecar without spawning a visible CMD window.
68+
69+
After Tauri integration:
70+
- User downloads `AdForge.dmg` (Mac) or `AdForge.msi` (Windows) or `.AppImage` (Linux)
71+
- Double-clicks installer → drag to Applications / Next-Next-Finish
72+
- Icon on desktop / Launchpad → click → app opens in its own native window (or system browser if user prefers)
73+
- Auto-update via Tauri's built-in updater pulling from GitHub releases
74+
- Zero CMD/terminal windows ever
75+
76+
#### R6. Move data out of install folder → user-level config dir
77+
**Change:** Use OS conventions:
78+
- Windows: `%APPDATA%\AdForge\`
79+
- macOS: `~/Library/Application Support/AdForge/`
80+
- Linux: `~/.config/adforge/`
81+
82+
So updating AdForge = replace the binary, data follows the user. Aligns with what every native app does.
83+
84+
- Implementation: change `DATA_DIR` resolution in `scripts/local-sync.cjs` to a per-OS path with fallback to project-local for dev.
85+
86+
#### R7. Auto-update on launch (silent or prompted)
87+
**Change:** On launcher start, hit GitHub API for latest release. If newer than current, show a one-click "Update + Restart" button in the launcher control panel. Don't auto-apply (audit said branch lock / dirty-tree lock — those are correct). Surface it.
88+
- The auto-update endpoint already exists. Just need to fire the check on launch.
89+
90+
### Tier 3 — Polish that compounds
91+
92+
#### R8. Single-instance lock
93+
**Change:** Before resolve-ports.cjs runs, take a file lock (`data/.adforge.lock`). If lock is held, just open the browser to the running sidecar and exit. Skips the entire spawn-twice-in-2-seconds race.
94+
95+
#### R9. Health check + status icon
96+
**Change:** Sidecar exposes `/health` already. Tauri tray icon could be:
97+
- Green dot — sidecar healthy
98+
- Yellow — starting up
99+
- Red — error (click to see logs)
100+
101+
#### R10. First-run wizard inside the app, not in the terminal
102+
**Change:** Instead of `npm install` running visibly during first launch (~30s of scrolling logs), show a splash screen ("Setting up — first launch only…") while the install runs in the background.
103+
104+
#### R11. Uninstaller
105+
**Change:** Native installers come with one. For the manual route, add an `AdForge-uninstall.bat` / `.command` that:
106+
- Kills the sidecar
107+
- Removes the Desktop shortcut
108+
- Optionally wipes `%APPDATA%\AdForge\` (with confirm)
109+
- Tells user to drag the install folder to trash
110+
111+
#### R12. "Open Web App" button → direct deep link to brand list, not launcher
112+
**Change:** Skip the launcher HTML on launch; go straight to `http://127.0.0.1:<port>/brand`. User who already onboarded doesn't need to see the launcher every time. Add a tray-menu / hotkey "Open AdForge launcher" for the sidecar controls.
113+
114+
---
115+
116+
## Recommended implementation order (next 4 commits, today-shippable)
117+
118+
### Commit A — Defaults (R1 + R2, ~20 lines)
119+
1. Default port range bumped from `3010-5010``41573-49999`.
120+
2. On first `.env.local` creation, ask the OS for free ports.
121+
122+
### Commit B — Single-instance + browser refresh (R3 + R8, ~30 lines)
123+
1. File-lock on launch.
124+
2. Bumping the version stamp triggers existing tab reload.
125+
126+
### Commit C — Per-user data dir (R6, ~20 lines + migration)
127+
1. Read DATA_DIR from OS conventions, write a one-time migration of existing `./data/` contents.
128+
129+
### Commit D — Tauri wrapper (R5, half-day project)
130+
1. `npx create-tauri-app` in a subfolder.
131+
2. Configure Tauri to spawn `scripts/local-sync.cjs` as a child process.
132+
3. Build per-OS installers + add a GitHub Actions release job.
133+
134+
After Commit D: the README install instruction becomes literally "Download AdForge.dmg, drag to Applications. Done."
135+
136+
---
137+
138+
## My actual recommendation right now
139+
140+
**Do A + B + C today (~70 lines total).** That gets you 80% of the polish with zero new dependencies. The user-facing improvement is:
141+
- New users → never hit port conflict (R1 + R2)
142+
- Returning users → existing tabs auto-refresh on relaunch (R3)
143+
- Multi-install scenarios → can't race themselves (R8)
144+
- Updates / reinstalls → data persists across folder changes (R6)
145+
146+
**Tauri (D) is a separate decision** — it's the right long-term answer but it changes the project from "BYOK browser-only web app" to "downloadable desktop app." That's a positioning decision, not a technical one. If you say yes, I can wire it. If you'd rather keep the "browser-only, self-hosted" identity, A + B + C is plenty.
147+
148+
What do you want to do?

0 commit comments

Comments
 (0)