Files
move-data-nas/AGENTS.md
T

5.1 KiB

SyncServer — Agent Guidance

Project Type

Go monolith (single binary) with embedded React SPA frontend. Targets Linux amd64 LXC containers on Proxmox.

Dev Commands

# Clean build and package (Linux amd64)
make clean && VERSION=X.Y.Z make package

# Build only (no package), Linux amd64
make build-all

# Run
./syncserver --data-dir ./data --addr :8080 \
  SYNCSERVER_ADMIN_USER=admin SYNCSERVER_ADMIN_PASSWORD=secret

# Tests
go test ./...

# Deploy (full build + bump + push + LXC deploy + verify)
./scripts/deploy.sh

Version Bumping

Before each push that contains user-facing changes, run the version bump script:

./scripts/bump-version.sh

This reads the current version from cmd/server/main.go, increments the patch number (semver), and updates both cmd/server/main.go and Makefile. Then commit and push:

git add cmd/server/main.go Makefile
git commit -m 'Bump version to X.Y.Z'
git push

The DEBIAN/control uses @@VERSION@@ placeholder and is substituted at make package time — no manual edit needed.

To verify the LXC is running the expected version:

ssh root@10.5.1.30 '/usr/bin/syncserver --version'
ssh root@10.5.1.30 'journalctl -u syncserver -n 3 --no-pager'

Deploy Flow

The make deploy target (or ./scripts/deploy.sh) automates the full deployment pipeline:

  1. Pre-flight — checks git clean, on main branch, LXC reachable, disk space
  2. Version bump — runs bump-version.sh, commits and pushes automatically
  3. Buildmake clean && make package (Linux amd64 .deb)
  4. Backup — copies current /usr/bin/syncserver to /var/backups/syncserver.previous.<version>
  5. Deploy — scp .deb to LXC, run dpkg -i
  6. Verify — service active, version matches, Cache-Control headers correct, HTTP 200

Deploy Options

./scripts/deploy.sh                    # Full deploy
./scripts/deploy.sh --dry-run          # Simulate without making changes
SKIP_BUILD=1 ./scripts/deploy.sh       # Use existing .deb
SKIP_VERIFY=1 ./scripts/deploy.sh     # Skip post-deploy checks
LXC_HOST=root@10.5.1.30 ./scripts/deploy.sh  # Custom target

Rollback

If verification fails after deploy, the script automatically rolls back to the backup binary. Manual rollback:

ssh root@10.5.1.30 "cp /var/backups/syncserver.previous.<version> /usr/bin/syncserver && systemctl restart syncserver"

LXC Host

  • Host: root@10.5.1.30
  • Remote dir: ~/move-data-nas
  • Service: syncserver (systemd)

Critical Build Order

  1. Frontend must be built FIRST: cd web && npm run build
  2. Output copied to internal/webui/dist/ (must exist before Go build)
  3. Then: go build ./cmd/server

scripts/build.sh does this automatically. Running go build without the frontend dist will produce a binary without the web UI.

Architecture Notes

  • Entry point: cmd/server/main.go
  • DB: modernc.org/sqlite — pure Go, CGO_ENABLED=0. Driver name is "sqlite" (not "sqlite3").
  • Migrations: embedded via //go:embed migrations in internal/db/migrations.go. Must use migrationsFS variable, path "migrations" (not "internal/db/migrations").
  • SSH keys: generated at startup if missing; stored in $DATA_DIR/ssh/id_ed25519. Only the public key is stored in DB.
  • Sync engine: uses os/exec.CommandContext to run rsync -e ssh .... SSH key is passed via -i flag, not via SSH config file.
  • Scheduler: homebrew cron parser (m h dom mon dow format, no seconds). Library github.com/robfig/cron is NOT used.
  • SSE: GET /api/jobs/stream streams text/event-stream. Clients must handle event: field.

Frontend Stack

  • TypeScript + React 18 + Vite + Tailwind CSS
  • Source: web/src/, built output: web/dist/
  • API client: web/src/api/client.ts
  • No React Router 6 data loaders; fetch hooks are manual in each page component
  • Tests: no frontend test suite yet

Key Package Boundaries

Package Responsibility
internal/api/ HTTP handlers, chi router, DTOs
internal/auth/ JWT (HS256), bcrypt, middleware
internal/db/ SQLite connection, migrations runner
internal/models/ Data access (raw sql)
internal/syncengine/ Job queue, rsync subprocess, event bus
internal/scheduler/ Cron parsing, tick loop
internal/sshmanager/ Ed25519 key generation, known_hosts
internal/wol/ Magic packet, TCP/ping waiter
internal/webui/ embed.FS for React dist

DB Schema

Managed via ordered SQL migrations in internal/db/migrations/. Apply on startup via db.RunMigrations(). Table schema_migrations tracks applied versions.

Package Script Quirks

  • scripts/build.sh: cross-compiles to Linux amd64 via GOOS=linux GOARCH=amd64. Version injected via -ldflags="-X main.version=$VERSION".
  • scripts/package-deb.sh: calls dpkg-deb --build. Version must be substituted into DEBIAN/control before build (@@VERSION@@ placeholder).

WoL Constraints

Magic packet uses SO_BROADCAST on a plain UDP socket. No raw sockets, no privileged container needed. Requires L2 reachability (same broadcast domain) from the server to the target machine's NIC.