Commit Graph

7 Commits

Author SHA1 Message Date
darroyo 84b185be39 Phase A-E: stability, security, observability, and test coverage
Phase A - Stability:
- Engine.Start(): recovers orphaned jobs (running/queued/waking_up) after crash
- Engine.Stop(): graceful shutdown - cancels all in-flight jobs and waits
- Queue keyed by jobID (not syncPairID): cancel now targets exact job
- Local rsync uses jobCtx (context.Background() replaced)
- Migrations wrapped in transactions; checksums stored

Phase B - Security:
- admin/admin default removed: SYNCSERVER_ADMIN_PASSWORD required on first run
- Path validation: rejects .., leading -, null bytes in sync pair paths
- Rsync flags allowlist: dangerous flags blocked (--rsync-path, -e, --files-from)
- Shell concat in RunRemote replaced with proper sh -c escaping
- knownhosts: replaced custom parser with golang.org/x/crypto/ssh/knownhosts
- RequireAdmin wired: machine CRUD, SSH key ops, settings require admin role
- deploy-keys: uses authorized_keys only (no private key upload)
- Hardcoded /var/lib/syncserver/ssh paths replaced with cfg.SSHDir()

Phase C - Operational:
- /readyz health check: DB query + SSH dir accessibility
- /metrics endpoint: Prometheus text format (jobs, queue, machines)
- Event struct JSON tags: job_id, machine_id, type (snake_case)
- EventBus broadcast: fanned out to all subscribers
- SQLite VACUUM INTO backup: scheduled before cleanup if BackupDir set
- Filesystem job log cleanup: removes .log files for purged jobs
- Backup retention: old backups auto-purged

Phase D - Frontend:
- Schedules page: REST API + full CRUD UI for cron schedules
- Dashboard: cancel button for running/queued jobs
- JobDetail: server-side log download via API
- Settings: displays data_dir from server
- 404 page: proper NotFound component

Phase E - Tests:
- auth_test.go: JWT, bcrypt, middleware, seed (18 tests)
- models_test.go: Job, Machine, SyncPair, Schedule repos (18 tests)
- go test -race: no data races found
2026-07-19 22:14:30 -04:00
darroyo 6b29a4b419 Bump version to 1.0.51 2026-07-19 19:49:00 -04:00
darroyo 69c4898a56 Add cancellation reason tracking with user/system codes and UI 2026-07-08 17:31:22 -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 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 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