Rewrote ARCHITECTURE.md with a new package-map section and updated Mermaid diagram showing src/app Service, src/scheduler, src/runner, src/storage, src/platform/autostart, and src/ui replacing the old src/core + src/gui split. Main-flows section documents the event-driven model and ErrorOccurred surfacing. Rewrote TESTS.md to cover all nine current test files (domain, app ×4, storage, scheduler, runner ×2, platform/autostart ×2, ui); every test function is documented. Removed stale src/core references. Updated README Project Layout from the two-package summary to the full per-package description. Marked T5.5 complete in REFACTORING.md. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
4.4 KiB
GoSentry Architecture
This document shows the current component interaction model. GoSentry is a single desktop process: the GUI, application service, scheduler, storage, and command runner live in one application. They communicate through typed events and well-defined interfaces rather than shared mutable state.
Package Map
cmd/gosentry entry point — starts the UI
src/
domain/ pure value types: Job, Config, RunRecord, Schedule, JobRuntime
app/ Service — sole owner of job/runtime state; emits typed Events
scheduler/ pure timing loop; calls app.Service.RunDue on every tick
runner/ shell command execution + log file writing + cleanup
storage/ YAML persistence (gosentry.yaml, jobs.yaml)
platform/
autostart/ Manager interface + Windows (shortcut) and Linux (XDG) impls
desktop/ display-scale helper (Linux only)
winproc/ hidden-window startup flags (Windows only)
ui/ Fyne windows, tabs, and dialogs; reads service via Events
Component Diagram
flowchart LR
user["Desktop user"]
ui["src/ui\nFyne windows, tabs, dialogs"]
svc["src/app Service\nsole owner of job + runtime state"]
store["src/storage Store\nYAML config and jobs"]
sched["src/scheduler Scheduler\npure timing loop"]
runner["src/runner\nshell command execution"]
autostart["src/platform/autostart Manager\nWindows shortcut / Linux XDG"]
config["gosentry.yaml\napplication settings"]
jobs["jobs.yaml\njob definitions"]
logs["logs_dir\nper-run command output logs"]
shell["Platform shell\ncmd.exe /C or sh -c"]
user -->|"edits jobs, settings, runs commands"| ui
ui -->|"CreateJob, UpdateJob, DeleteJob, RunNow, UpdateSettings, …"| svc
svc -->|"SaveJobs, SaveConfig, LoadJobs, LoadConfig"| store
store -->|"read/write"| config
store -->|"read/write"| jobs
svc -->|"Start(RunDue)"| sched
sched -->|"RunDue(now)"| svc
svc -->|"RunJob"| runner
runner -->|"execute command"| shell
runner -->|"write stdout/stderr log"| logs
runner -->|"RunRecord"| svc
svc -->|"emit JobChanged / RunRecorded / ErrorOccurred"| ui
ui -->|"display jobs, history, status"| user
ui -->|"SetAutostart, AutostartStatus"| autostart
svc -->|"Set / Status via Manager"| autostart
Main Flows
-
Startup:
cmd/gosentrycallsui.Run, which creates anapp.Service, opens the store, loadsgosentry.yamlandjobs.yaml, subscribes the UI to service events, builds the main window, and callsService.Startto begin the scheduler loop. -
Editing settings or jobs: The UI calls mutating methods on
app.Service(e.g.CreateJob,UpdateJob,UpdateSettings). The Service validates the request, updates its in-memory state, persists throughstorage.Store, and emits a typedEvent. The UI's observer receives the event and refreshes the relevant widget on the main thread viafyne.Do. -
Scheduled run:
scheduler.Schedulerfires a tick every second. On each tick it callsService.RunDue(now). The Service checks which enabled, non-paused jobs are due, marks each as running, and launchesrunner.RunJobin a goroutine. -
Manual run:
Run nowin the UI callsService.RunNow. The Service checks that the job exists, is not already running, and that the scheduler is not paused, then executesrunner.RunJobwith theManualtrigger. -
Command execution:
runner.RunJobbuilds the platform-specific invocation, executes the command through the platform shell, captures stdout and stderr, writes one timestamped.logfile, and returns adomain.RunRecord. -
History update: When a run goroutine completes,
Serviceupdates the job's runtime, saves YAML, triggers log cleanup, and emitsRunRecorded. The UI observer appends the record to the History tab. -
Autostart:
UpdateSettingsin the Service callsautostart.Manager.Set. The Manager interface has two implementations: Windows writes a.lnkshortcut to the user Startup folder; Linux writes an XDG Autostart.desktopfile. Both entries pass--start-in-tray. -
Error surfacing: Background errors (failed YAML saves, cleanup errors) are emitted as
ErrorOccurredevents and displayed in the UI status area, rather than being silently discarded.