Commit Graph

31 Commits

Author SHA1 Message Date
darroyo 5d5b6c99a7 Bump version to 1.0.9
Fix Wake-on-LAN: set SO_BROADCAST on UDP socket, send 3 magic packets,
expose broadcast_addr and wake timeout fields in UI, add Test Wake endpoint,
surface send errors in job status, bump default wake timeout to 180s.
2026-07-08 19:19:50 -04:00
darroyo 25a31af64c Make ExecStartPre chown non-fatal to prevent service start failures 2026-07-08 17:42:28 -04:00
darroyo 69c4898a56 Add cancellation reason tracking with user/system codes and UI 2026-07-08 17:31:22 -04:00
darroyo 3c1bbce9e7 Add .tmp/ to gitignore and remove tracked screenshots 2026-07-08 14:33:34 -04:00
darroyo 0c43372e3e Visual fixes: base href, dashboard pair names, edit button 2026-07-08 14:31:41 -04:00
darroyo 9d32ef7fd6 Add job error persistence and friendly error UI
Backend:
- Migration 0003_job_error: adds error_message and error_code columns to jobs table
- models/job.go: add ErrorMessage, ErrorCode fields to Job struct; SetError method; update all SELECT queries
- models/job_log.go: GetAllFiltered also reads error_message and error_code (via Job embed)
- syncengine/engine.go: setJobError() helper; capture errors at Wol timeout (wol_timeout), rsync error (rsync_error), and exit_code failure points
- api/dto.go: add ErrorMessage and ErrorCode to JobResponse
- api/handlers_jobs.go: jobToResp propagates error fields

Frontend:
- api/client.ts: add error_message? and error_code? to Job interface
- lib/status.ts: add ERROR_CODES map with friendly titles/hints; getErrorCodeInfo()
- components/ErrorDetailsModal.tsx: new modal showing error title, hint, full message, job metadata, and stderr log; copy-all and download-log buttons
- pages/JobDetail.tsx: error banner for failed jobs with title/hint; View error button opens ErrorDetailsModal; SSE updates error_message in real-time
2026-07-08 09:04:47 -04:00
darroyo e0e94bd518 Fix: defensive frontend + panic recovery logging middleware
Frontend:
- JobDetail loadLogs: fallback to [] when API returns null
- JobDetail loadJob: pairs ?? [] guard on /api/sync-pairs 500
- JobHistory: Array.isArray guard on job list response
- api client: return undefined for null body instead of throwing

Backend:
- handlers_jobs GetLog: return [] instead of null when no log rows
- router: custom recoverer middleware that logs panics to slog
  with full stack trace, method, and path
2026-07-08 01:28:12 -04:00
darroyo 6d16797c4f Fix known_hosts format: use ssh.MarshalAuthorizedKey
Bug: AddKnownHost wrote raw SSH wire-protocol bytes directly to
known_hosts instead of the OpenSSH authorized-key one-line format.
This produced garbage entries that would break SSH verification
for newly added machines.

Fix: ssh.ParsePublicKey(keyData) + ssh.MarshalAuthorizedKey() to
produce canonical hostkey lines: hostname ssh-ed25519 AAAAB3...xn3c=
2026-07-08 00:44:01 -04:00
darroyo 8d0117399c Fix SSH public key format: use ssh.MarshalAuthorizedKey
Bug: raw ed25519.PublicKey bytes were stored directly instead of
OpenSSH authorized-key format (ssh-ed25519 AAAA... label).

Fixes:
- internal/sshmanager/fingerprint.go: GenerateKeyPair now uses
  ssh.NewPublicKey + ssh.MarshalAuthorizedKey
- internal/sshmanager/keys.go: EnsureServerKey uses same fix; also
  regenerates .pub file from private key if stored value is corrupt
- internal/sshmanager/fingerprint.go: add MarshalED25519PublicKey,
  PublicKeyFromPrivateKeyFile, RegeneratePublicKeyFromPrivateKeyFile
- internal/models/sshkey.go: add UpdatePublicKey
- internal/api/handlers_sshkeys.go: List+Get recover existing DB
  records with corrupt public keys by regenerating from private key
  file and updating the DB

Also adds golang.org/x/crypto/ssh dependency via go mod tidy.
2026-07-08 00:30:57 -04:00
darroyo e322299dc3 Add deploy script with dry-run, retry, rollback and health checks 2026-07-08 00:21:17 -04:00
darroyo b185686d2b Bump version to 1.0.7 2026-07-08 00:05:37 -04:00
darroyo acdb1e3303 fix(Select): remove Icon asChild from Trigger to avoid Slot error
- Radix SelectTrigger composes its children via Slot internally
- Having both {children} and <Icon asChild> caused "Slot failed to slot onto its children"
- Use Radix default Icon instead (rendered automatically)
2026-07-08 00:03:44 -04:00
darroyo 3812b831c9 fix(Button): asChild slot children error
- Separate render paths: asChild uses Slot directly, normal uses button
- Fixes "Slot failed to slot onto its children" runtime error
- Slot now always receives exactly one child (the Link element)
2026-07-08 00:00:01 -04:00
darroyo f5f3b2263e fix(postinst): robust service restart on upgrade
- Always enable service (not conditional on is-enabled)
- try-restart: reinicia si ya estaba corriendo
- start fallback: arranca si quedó inactive después del try-restart
- Covers: fresh install, running disabled, stopped manual, failed
- Like baby-nas but handles the "running-but-not-enabled" edge case
2026-07-07 23:54:08 -04:00
darroyo 1e516cb746 simplify postinst: use try-restart like baby-nas
- Replace if/restart/else/enable with is-enabled && enable; try-restart
- Consistent with baby-nas approach
- Handles failed services gracefully (no auto-recover)
2026-07-07 23:49:52 -04:00
darroyo a79bb29699 fix: service restart on upgrade and no-cache headers for SPA assets
- postinst: restart instead of start if service already enabled (upgrade case)
- embed.go: no-cache/no-store on index.html, immutable cache on hashed assets
- Fixes web not refreshing after dpkg upgrade
2026-07-07 23:41:16 -04:00
darroyo 9cef7173cb Visual redesign: design system, refined ops console aesthetic
- Full component library (Button, Input, Label, Select, Modal, Table, Badge, Card, etc.)
- Tailwind design tokens: IBM Plex Sans + JetBrains Mono, teal accent, semantic status colors
- NavBar with logo, responsive hamburger menu, real logout
- All pages redesigned: Login, Dashboard (KPI cards), Machines, SyncPairs, JobHistory, JobDetail, SSHKeys, Settings
- Fixed: hover:bg-gray-750 dead class, window.location.href navigation bug
- Replaced alert()/confirm() with sonner toasts and accessible modals
- Added ErrorBoundary, skip link, accessible modal dialogs (Radix)
- Icons: lucide-react throughout, copy/download buttons
- 1.0.5 → 1.0.6
2026-07-07 23:12:34 -04:00
darroyo 93c22e844e Add persistent navbar with SSH Keys link
Refactor App.tsx to use Layout + Outlet pattern with sticky navbar
containing: Dashboard | Machines | Sync Pairs | Jobs | SSH Keys | Settings.
Clean up redundant button row from Dashboard and inline SSH Keys links.
2026-07-07 20:40:24 -04:00
darroyo bfa006f4ab Add SSH key management, job history persistence, and live streaming
- SSH key management: generate ed25519 keypairs or import public keys
  from UI (/ssh-keys), per-machine key selection in Machines form,
  one-time private key download with hash verification
- Fix engine to use machine-specific SSH key (was hardcoded to server key)
- Job log persistence: write to job_logs table (DB) with batched inserts,
  buffer of 50 lines; GetAllFiltered with status/pair/date range filters
- EventBus refactor: per-job subscriber channels, global channel, non-blocking
- SSE endpoints: /jobs/stream (all), /jobs/:id/log/stream (per-job live)
- JobDetail page: live log streaming, auto-scroll, cancel, duration
- JobHistory: filters (pair, status, date range), pagination, link to detail
- Cleanup scheduler: daily purge of job_logs and finished jobs older than
  SYNCSERVER_RETENTION_DAYS (default 30)
- Migration 0002: indexes on job_logs(job_id), jobs(status,created_at),
  jobs(sync_pair_id)
2026-07-07 20:36:11 -04:00
darroyo 5374ab81cc auth: default admin/admin credentials on first install + bump 1.0.4
SeedAdmin now uses 'admin'/'admin' as defaults when environment
variables are not set, so the service works out-of-the-box after
first install.
2026-07-07 20:00:42 -04:00
darroyo 596981b63b Bump version to 1.0.3
webui: use fs.Sub to fix embed FS root so static assets are found

Previously http.FileServer searched for assets/foo.css in the embed FS
rooted at dist/, but only paths starting with dist/ resolve. fs.Sub
strips the dist/ prefix so FileServer finds the actual files.
2026-07-07 19:46:03 -04:00
darroyo 79b6c958fd Bump version to 1.0.2
- Add scripts/bump-version.sh for semver patch increments
- Update AGENTS.md Dev Commands section and add Version Bumping docs
- Makefile default VERSION bumped to 1.0.2
2026-07-07 19:18:52 -04:00
darroyo 3b5d20c05d webui: fix ServeSPA to use StripPrefix so FileServer finds assets 2026-07-07 19:12:40 -04:00
darroyo 38a89328a9 api: use webui.ServeSPA in NotFound handler instead of buggy inline logic 2026-07-07 15:58:18 -04:00
darroyo 68592bd119 Fix version in DEBIAN/control and Makefile default to 1.0.1 2026-07-07 15:52:33 -04:00
darroyo 7c5a091f7c Bump version to 1.0.1 2026-07-07 15:49:07 -04:00
darroyo 4cc93c7747 fix: self-healing permissions on /var/lib/syncserver
- systemd: add ExecStartPre to chown -R the data dir before every start
- postinst: add chown -R after creating dirs to fix ownership on upgrades

This prevents the service from failing if dirs were created by root or
drifted ownership after a manual run.
2026-07-07 15:41:10 -04:00
darroyo 9038e3a000 fix(make): copy web/dist into internal/webui/dist before build-all 2026-07-07 15:24:55 -04:00
darroyo 221aea8b4c refactor: adopt baby-nas Makefile style with inline packaging targets
- Simplify build targets: frontend, build, build-go, build-all, run, package
- Remove scripts/ for packaging (inline in Makefile)
- Add etc/syncserver/config.yaml and lib/systemd/system/ at project root
- build-all produces both amd64 and arm64 binaries
- package target builds .deb inline without external scripts
- VERSION from git tags, commit hash injected via ldflags
2026-07-07 15:18:01 -04:00
darroyo 8e08c73f60 feat: complete SyncServer implementation
Full-stack Go monolith with embedded React frontend for orchestrating
rsync-over-SSH file synchronization with Wake-on-LAN support.

Features:
- JWT auth (HS256) with bcrypt password hashing
- CRUD for machines (with WoL config) and sync_pairs
- Ed25519 SSH key generation and known_hosts management
- WoL magic packet sender + TCP-connect waiter with backoff
- Sync engine: rsync subprocess, per-pair job queue, progress parsing
- Homebrew cron parser for scheduled syncs
- SSE stream for live job status (queued/waking_up/running/success/failed)
- React+TS+Vite+Tailwind SPA embedded via embed.FS
- Debian packaging with systemd unit, postinst/prerm/postrm

Tech stack:
- Go 1.22+ (CGO_ENABLED=0, pure SQLite via modernc.org/sqlite)
- chi router for HTTP API
- TypeScript + React 18 + Tailwind CSS frontend
- Cross-compiled to Linux amd64 for Proxmox LXC deployment

Tests: wol (MAC parsing, magic packet), syncengine/queue, scheduler/cron
2026-07-07 15:03:22 -04:00
darroyo 1a66ac58cd Initial commit 2026-07-07 17:18:46 +00:00