# Sawa Control Panel — Issues & Decisions *Track open questions, known problems, and architectural decisions here.* --- ## Open Issues ### ISSUE-001 — sudo whitelist scope **Status:** Open **Priority:** Must resolve before Phase 1 complete The backend needs to run `rc-service` commands without being root. A sudoers whitelist is required. The exact scope needs to be defined. **Options:** - Whitelist per service per action — most secure, most verbose sudoers file - Whitelist `rc-service` for a named panel user with NOPASSWD — simpler, still scoped to that user **Suggested resolution:** Create a dedicated `panel` system user. Grant NOPASSWD sudo access to `rc-service` only, for the specific whitelisted service names. Example: ``` panel ALL=(ALL) NOPASSWD: /sbin/rc-service nginx *, /sbin/rc-service mariadb *, ... ``` --- ### ISSUE-002 — Client cert distribution to mobile **Status:** Open **Priority:** Must resolve before Phase 1 complete Installing a client certificate on Android/iOS for nginx mTLS requires PKCS12 (.p12) format. The cert generation script must output `.p12` alongside `.pem`. Safe transfer options to phone: - Generate a one-time HTTPS download URL on the server (temporary endpoint, auto-deletes after download) - AirDrop (iOS only) - Manual transfer via USB cable **Decision needed:** Which transfer method to implement in the cert script. --- ### ISSUE-003 — Service status parsing reliability **Status:** Open **Priority:** Should resolve before Phase 1 complete `rc-service status` returns inconsistent output formats across different services. Need to normalize into a consistent `started | stopped | crashed | unknown` enum. **Suggested resolution:** Parse `rc-status` output instead of per-service status calls — it returns a structured view of all services in the current runlevel. More reliable and one call instead of N calls. --- ### ISSUE-004 — Build and deploy workflow **Status:** Open **Priority:** Needed for Phase 1 React app needs to be built locally then deployed to `/var/www/panel/` on the server. Need a repeatable deploy process. **Options:** - `npm run deploy` script — builds then SCPs to server using stored SSH key - rsync watch mode for development iteration - GitHub Actions CI/CD (Phase 3+) **Suggested resolution for now:** Simple deploy script using scp. Keep it manual until the project stabilizes. --- ### ISSUE-005 — wlan0 fails on boot (server-side) **Status:** Open — pre-existing server issue, not a panel issue **Priority:** Low (eth0 works fine when server is docked at router) wlan0 interface fails to come up during boot with `ifup: failed to change interface wlan0 state to up`. wpa_supplicant appears to start before the Intel WiFi 5100 hardware is fully initialized. **Attempted fix:** Add `sleep 3` to pre-up in `/etc/network/interfaces` — not yet tested after reboot. **Workaround:** Manual bring-up after boot: ```sh wpa_supplicant -B -i wlan0 -c /etc/wpa_supplicant/wpa_supplicant.conf ip route add default via 10.0.0.1 dev wlan0 metric 200 ``` --- ### ISSUE-006 — Diskless/RAM mode not yet configured **Status:** Open — planned experiment **Priority:** Medium (USB write wear reduction) Currently running in `sys` mode — OS reads/writes directly to USB. Should convert to diskless mode to reduce USB wear. However the partition layout (separate ext4 boot partition sdb1, not vfat) is non-standard and the conversion is risky. **Plan:** Test diskless conversion on a cloned spare USB first. Never attempt on the master image. --- ## Resolved Decisions ### DECISION-001 — Authentication mechanism **Status:** Decided ✅ Use nginx mutual TLS (mTLS) with client certificates. No login page. Unauthorized devices get a TLS handshake failure — no HTTP response at all. **Rationale:** Minimizes attack surface. No password to brute-force. No session management. Works seamlessly on authorized devices after one-time cert install. Accessible from outside LAN without VPN. --- ### DECISION-002 — Frontend framework **Status:** Decided ✅ React with Vite and Tailwind CSS. **Rationale:** Fast dev experience, small production build. Tailwind avoids CSS file management overhead. No SSR needed — the panel is not public-facing or SEO-sensitive. --- ### DECISION-003 — Backend language **Status:** Decided ✅ Node.js with Express. **Rationale:** Node.js is already installed on the server as part of the Sawa stack. No additional runtime needed. Express is minimal and well understood. --- ### DECISION-004 — Database stack convention **Status:** Decided ✅ | Use case | Database | |----------|----------| | WordPress, Laravel | MariaDB | | Node.js apps | PostgreSQL | | Sessions, queues, app state | Redis (persistent, RDB+AOF) | | Pure caching | Memcached | --- ### DECISION-005 — Panel not served on public internet directly **Status:** Decided ✅ The control panel is accessible on LAN via its local IP and optionally via dynamic DNS from outside. It is not served on a named public domain. It runs on port 443 alongside other nginx virtual hosts, differentiated by the client certificate requirement. --- ## Technical Debt These are known issues on the server that should be addressed before or alongside panel development: - [ ] `noatime` not yet set on fstab — USB write reduction pending - [ ] Diskless/RAM mode not yet configured — see ISSUE-006 - [ ] MariaDB still using deprecated binary names (`mysql` vs `mariadb`) — harmless but noisy in logs - [ ] `resolv.conf` not protected from being overwritten by `networking restart` - [ ] `firstboot.sh` lbu overlay rename logic not yet tested on a real clone - [ ] Redis password currently passed on command line in some test calls — should use AUTH in config only - [ ] SSH on port 22 — consider moving to non-standard port to reduce scan noise - [ ] No log rotation configured — logs will grow unbounded on long-running servers