T5.5: Update docs to reflect Phase 5 package structure
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>
This commit is contained in:
+72
-41
@@ -1,73 +1,104 @@
|
||||
# GoSentry Architecture
|
||||
|
||||
This document shows the current component interaction model. GoSentry is still a
|
||||
single desktop process: the GUI, scheduler, storage, and command runner live in
|
||||
one application and communicate through Go function calls and shared in-memory
|
||||
job state.
|
||||
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
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
user["Desktop user"]
|
||||
gui["src/gui - Fyne windows, tabs, dialogs"]
|
||||
store["src/core Store - YAML config and jobs"]
|
||||
scheduler["src/core Scheduler - @every and cron timing"]
|
||||
runner["src/core Runner - shell command execution"]
|
||||
autostart["src/core Autostart - Windows Startup shortcut / Linux desktop startup"]
|
||||
config["gosentry.yaml - application settings"]
|
||||
jobs["jobs.yaml - job definitions"]
|
||||
logs["logs_dir - per-run command output logs"]
|
||||
shell["Platform shell - cmd.exe /C or sh -c"]
|
||||
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"| gui
|
||||
gui -->|"OpenStore, SaveConfig, SaveJobs"| store
|
||||
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
|
||||
|
||||
gui -->|"Start, Pause, RunNow, RefreshSchedule"| scheduler
|
||||
scheduler -->|"SaveJobs after state changes"| store
|
||||
scheduler -->|"RunJob(trigger)"| runner
|
||||
svc -->|"Start(RunDue)"| sched
|
||||
sched -->|"RunDue(now)"| svc
|
||||
svc -->|"RunJob"| runner
|
||||
runner -->|"execute command"| shell
|
||||
runner -->|"write stdout/stderr log"| logs
|
||||
runner -->|"RunRecord with status, duration, log path"| scheduler
|
||||
scheduler -->|"onChange RunRecord"| gui
|
||||
gui -->|"display History, command output, job state"| user
|
||||
runner -->|"RunRecord"| svc
|
||||
svc -->|"emit JobChanged / RunRecorded / ErrorOccurred"| ui
|
||||
ui -->|"display jobs, history, status"| user
|
||||
|
||||
gui -->|"SetAutostart, AutostartStatus"| autostart
|
||||
autostart -->|"use executable path from resolved Paths"| config
|
||||
ui -->|"SetAutostart, AutostartStatus"| autostart
|
||||
svc -->|"Set / Status via Manager"| autostart
|
||||
```
|
||||
|
||||
## Main Flows
|
||||
|
||||
1. Startup:
|
||||
The executable starts `cmd/gosentry`, which calls the GUI package. The GUI
|
||||
opens the store, loads `gosentry.yaml` and `jobs.yaml`, creates the main tabs,
|
||||
then starts the scheduler with the loaded job slice.
|
||||
`cmd/gosentry` calls `ui.Run`, which creates an `app.Service`, opens the
|
||||
store, loads `gosentry.yaml` and `jobs.yaml`, subscribes the UI to service
|
||||
events, builds the main window, and calls `Service.Start` to begin the
|
||||
scheduler loop.
|
||||
|
||||
2. Editing settings or jobs:
|
||||
The GUI updates the in-memory job/config state and asks `Store` to write YAML
|
||||
back to disk. Job definitions stay in one `jobs.yaml`; runtime command output
|
||||
is not stored there.
|
||||
The UI calls mutating methods on `app.Service` (e.g. `CreateJob`,
|
||||
`UpdateJob`, `UpdateSettings`). The Service validates the request, updates
|
||||
its in-memory state, persists through `storage.Store`, and emits a typed
|
||||
`Event`. The UI's observer receives the event and refreshes the relevant
|
||||
widget on the main thread via `fyne.Do`.
|
||||
|
||||
3. Scheduled run:
|
||||
`Scheduler` checks due jobs on a one-second ticker. When a job is due, it marks
|
||||
the job as running, saves state, and starts `Runner` asynchronously.
|
||||
`scheduler.Scheduler` fires a tick every second. On each tick it calls
|
||||
`Service.RunDue(now)`. The Service checks which enabled, non-paused jobs are
|
||||
due, marks each as running, and launches `runner.RunJob` in a goroutine.
|
||||
|
||||
4. Manual run:
|
||||
`Run now` calls the same scheduler path as scheduled execution, but the
|
||||
resulting history record uses the `Manual` trigger.
|
||||
`Run now` in the UI calls `Service.RunNow`. The Service checks that the job
|
||||
exists, is not already running, and that the scheduler is not paused, then
|
||||
executes `runner.RunJob` with the `Manual` trigger.
|
||||
|
||||
5. Command execution:
|
||||
`Runner` executes the command through the platform shell, captures stdout and
|
||||
stderr, writes one timestamped `.log` file, and returns a `RunRecord`.
|
||||
`runner.RunJob` builds the platform-specific invocation, executes the
|
||||
command through the platform shell, captures stdout and stderr, writes one
|
||||
timestamped `.log` file, and returns a `domain.RunRecord`.
|
||||
|
||||
6. History update:
|
||||
The scheduler receives the `RunRecord`, updates the matching job, saves YAML,
|
||||
runs log cleanup, and calls the GUI callback so the `History` tab refreshes.
|
||||
When a run goroutine completes, `Service` updates the job's runtime, saves
|
||||
YAML, triggers log cleanup, and emits `RunRecorded`. The UI observer appends
|
||||
the record to the History tab.
|
||||
|
||||
7. Autostart:
|
||||
The Settings tab calls the platform autostart implementation. Windows uses a
|
||||
shortcut in the current user's Startup folder. Linux uses a desktop-session
|
||||
startup entry. Both autostart mechanisms pass `--start-in-tray`, so the
|
||||
scheduler starts without opening the main window after sign-in.
|
||||
`UpdateSettings` in the Service calls `autostart.Manager.Set`. The Manager
|
||||
interface has two implementations: Windows writes a `.lnk` shortcut to the
|
||||
user Startup folder; Linux writes an XDG Autostart `.desktop` file. Both
|
||||
entries pass `--start-in-tray`.
|
||||
|
||||
8. Error surfacing:
|
||||
Background errors (failed YAML saves, cleanup errors) are emitted as
|
||||
`ErrorOccurred` events and displayed in the UI status area, rather than
|
||||
being silently discarded.
|
||||
|
||||
Reference in New Issue
Block a user