mcp: project-plan — WiFi Join Web App (Travel Pi)

This commit is contained in:
Lovebug MCP 2026-06-28 10:15:13 +00:00
parent 5dcd2baba3
commit 7923d07c20

View File

@ -0,0 +1,76 @@
---
created: '2026-06-28'
path: Sources/Homelab
project: wifi-join-webapp
tags:
- dns
type: project-plan
---
## Goal
Replace the ten-click LuCI ceremony for joining a new WiFi network on the road with a one-screen, browser-based scan-and-join page. Universal access (phone/tablet/laptop, no SSH, no app), served off the all-in-one travel Pi. Tap a network, enter the password, done — the page writes the travelmate uplink and reconnects behind the scenes.
Secondary: it's a genuine portfolio piece — a custom web tool talking to OpenWRT's `ubus`/UCI API.
## Problem
Current join flow is all manual LuCI: type router IP (browser never remembers it) → log in → open travelmate → navigate to its page → scan radio0 → find network → add → apply → wait. Interface is fine; the ceremony is the problem. Most of the pain is front-half (reach + login + navigation depth) plus a scan/add/apply tail.
Deep-link bookmark + password-manager autofill would kill the front half cheaply (considered as Option A), but the decision was to build the real thing — a custom page that collapses the entire flow.
## Locked Decisions
- **Architecture: thin backend shim (not pure-frontend-against-ubus).** Privileged work (write config + reconnect travelmate) stays server-side in one place; avoids wrestling rpcd/ubus ACLs from browser JS. Frontend just hits two simple endpoints.
- **Runs on the all-in-one travel Pi.** OpenWRT + travelmate + Pi-hole are all on the one Raspberry Pi, so the shim talks to ubus/UCI locally — same-origin, no CORS, no cross-box auth.
- **Backend language: lua** (native to OpenWRT, uhttpd speaks it, zero extra packages). Python kept in reach as fallback if travelmate config-writing gets gnarly in lua. Travis is new to lua — pace accordingly.
- **Rides existing uhttpd** (already running for LuCI). No new web server.
- **Backup before any router change** (Phase 0, same rule as the captive-portal plan — same router).
- **Build + curl-test the shim before any frontend.** Prove backend, then UI is trivial.
## Open Items
- [ ] Verify exact `config wifi-config` field shape against live `/etc/config/travelmate` before trusting the join write (don't write from memory).
- [ ] Decide whether a `/status` endpoint is worth it for "waiting to connect" feedback, or poll something simpler.
- [ ] ubus ACL: confirm the shim can call iwinfo scan + uci commit + travelmate restart under whatever user uhttpd/rpcd runs it as.
- [ ] Decide auth on the page itself (LAN-only? any gate?) — currently assumed trusted-LAN, no extra auth.
## Phases
### Phase 0 — Backup (non-negotiable, first)
- [ ] `sysupgrade -b /tmp/backup-$(date +%Y%m%d).tar.gz`
- [ ] `scp` tarball off the Pi to laptop; confirm present before any change
### Phase 1 — Scan endpoint
- [ ] lua shim: `GET /cgi-bin/wifi-join/scan` → triggers radio0 scan, returns JSON `[{ssid, signal, encryption}]`
- [ ] curl-test from laptop; prove ubus scan works before any UI
### Phase 2 — Join endpoint
- [ ] Reference live `cat /etc/config/travelmate` for exact uplink shape
- [ ] lua shim: `POST /cgi-bin/wifi-join/join` body `{ssid, key}` → writes travelmate `wifi-config` uplink, commits, reconnects
- [ ] curl-test headless; prove travelmate write + reconnect works
### Phase 3 — Frontend (one page)
- [ ] Vanilla HTML/JS single file served by uhttpd: Scan button → network list w/ signal → tap → password field → Join → status
- [ ] Wire to the two proven endpoints
### Phase 4 — Polish
- [ ] Signal bars, connect-status feedback
- [ ] Bookmark target; effectively replaces LuCI for the common case
- [ ] Optional `/status` endpoint if feedback needs it
## Notes
- Architecture:
```
Browser ──HTTP same-origin──► uhttpd ──► static frontend (one HTML/JS page)
└──/cgi-bin/wifi-join──► lua shim
├─ ubus call iwinfo scan
├─ uci set wireless / travelmate wifi-config
├─ uci commit
└─ /etc/init.d/travelmate restart
```
- travelmate wrinkle: 2.1.3 stores uplinks as `config wifi-config` sections in `/etc/config/travelmate`, NOT raw `wireless.@wifi-iface`. "Join" = add a travelmate uplink entry and let its interface handler pick it up. Version-specific; verify against live config.
- Environment (confirmed this session): all-in-one Pi. travelmate `2.1.3-r3`, luci-app-travelmate `25.157.41932~3b521ef`, OpenWRT `24.10.1` r28597.
- Build discipline: backend proven by curl before a line of frontend. Same one-step-at-a-time interactive mode for the shim work.
- Related plan: `travel-pi-router` (captive-portal fix) — same Pi, shares the Phase 0 backup rule. This webapp is a separate deliverable from the captive-portal hook but lives on the same box.