Commit Graph

180 Commits

Author SHA1 Message Date
7a9dd057a5 Merge pull request 'feat(storage): FileStore interface abstraction + filesystem backend' (#134) from feat-storage-interface-filesystem into main
Reviewed-on: #134
2026-02-17 17:55:09 +00:00
9f347e7898 feat(storage): implement filesystem backend
Implement FilesystemStore satisfying the FileStore interface for local
filesystem storage, replacing MinIO for simpler deployments.

- Atomic writes via temp file + os.Rename (no partial files)
- SHA-256 checksum computed on Put via io.MultiWriter
- Get/GetVersion return os.File (GetVersion ignores versionID)
- Delete is idempotent (no error if file missing)
- Copy uses same atomic write pattern
- PresignPut returns ErrPresignNotSupported
- Ping verifies root directory is writable
- Wire NewFilesystemStore in main.go backend switch
- 14 unit tests covering all methods including atomicity

Closes #127
2026-02-17 11:49:42 -06:00
b531617e39 feat(storage): define FileStore interface and refactor to use it
Extract a FileStore interface from the concrete *storage.Storage MinIO
wrapper so the API layer is storage-backend agnostic.

- Define FileStore interface in internal/storage/interface.go
- Add Exists method to MinIO Storage (via StatObject)
- Add compile-time interface satisfaction check
- Change Server.storage and ServerState.storage to FileStore interface
- Update NewServer and NewServerState signatures
- Add Backend and FilesystemConfig fields to StorageConfig
- Add backend selection switch in main.go (minio/filesystem/unknown)
- Update config.example.yaml with backend field

The nil-interface pattern is preserved: when storage is unconfigured,
store remains a true nil FileStore (not a typed nil pointer), so all
existing if s.storage == nil checks continue to work correctly.

Closes #126
2026-02-17 11:49:35 -06:00
906277149e Merge pull request 'feat(web): read-write configuration from admin UI' (#124) from feat-admin-config-ui into main
Reviewed-on: #124
2026-02-15 23:12:04 +00:00
Forbes
fc4826f576 feat(web): read-write configuration from admin UI
Convert all module settings from read-only to editable fields in the
admin settings page:

- Core: host, port, base_url (read-only stays read-only)
- Schemas: directory, default (count stays read-only)
- Database: host, port, name, user, password, sslmode (dropdown),
  max_connections
- Storage: endpoint, bucket, use_ssl (checkbox), region
- Auth: local/ldap/oidc sub-sections with enabled checkboxes,
  connection fields, and secret fields (password input for redacted)

New field components: SelectField (dropdown), CheckboxField (toggle).
Redacted fields now render as password inputs with placeholder.
Auth uses nested key handling to send sub-section objects.

Backend already persists overrides and flags restart-required changes.

Closes #117
2026-02-15 13:33:48 -06:00
fbfc955ccc Merge pull request 'feat(modules): SSE settings.changed event broadcast' (#123) from feat-sse-settings-changed into main
Reviewed-on: #123
2026-02-15 19:14:36 +00:00
e0295e7180 Merge branch 'main' into feat-sse-settings-changed 2026-02-15 19:14:26 +00:00
Forbes
7fec219152 feat(modules): SSE settings.changed event broadcast and UI reactions
Add useSSE hook that connects to /api/events with automatic reconnect
and exponential backoff. On settings.changed events:

- Refresh module state so sidebar nav items show/hide immediately
- Show dismissable toast when another admin updates settings

The backend already publishes settings.changed in HandleUpdateModuleSettings.

Closes #101
2026-02-15 13:11:04 -06:00
fa069eb05c Merge pull request 'feat(web): move edit/delete buttons into tab bar on item detail' (#122) from feat-move-edit-delete-buttons into main
Reviewed-on: #122
2026-02-15 19:03:59 +00:00
Forbes
8735c8341b feat(web): move edit/delete buttons into tab bar on item detail
Relocate Edit and Delete buttons from the header row into the tab bar,
grouping them with tab navigation to reduce mouse travel. Adds Pencil
and Trash2 icons for quick visual recognition.

Header now only shows part number, type badge, and close button.

Closes #119
2026-02-15 12:59:40 -06:00
7a172ce34c Merge pull request 'feat(web): favicon, narrow settings, scrollable token list' (#121) from feat-ui-tweaks into main
Reviewed-on: #121
2026-02-15 18:47:03 +00:00
Forbes
da65d4bc1a feat(web): favicon, narrow settings, scrollable token list
- Add kindred-logo.svg as site favicon (#115)
- Narrow settings page to 66% max-width, centered (#116)
- Add max-height and scroll to API token table (#118)

Closes #115, closes #116, closes #118
2026-02-15 12:38:20 -06:00
57d5a786d0 Merge pull request 'feat(web): collapsible left sidebar, remove top nav bar' (#120) from feat-sidebar-nav into main
Reviewed-on: #120
2026-02-15 18:33:09 +00:00
Forbes
42a901f39c feat(web): collapsible left sidebar, remove top nav bar
- Replace top header with left sidebar navigation
- Sidebar shows module-aware nav items filtered by /api/modules
- Collapsible: expanded shows icon+label, collapsed shows icon only
- Toggle with Ctrl+J or collapse button, state persisted in localStorage
- Keyboard navigable: Arrow Up/Down, Enter to navigate, Escape to collapse
- Bottom section: density toggle, user info with role badge, logout
- Add useModules hook for fetching module state
- Add sidebar density variables to theme.css

Closes #113, closes #114
2026-02-15 12:32:52 -06:00
666cc2b23b Merge pull request 'feat(jobs): wire auto-triggering on bom_changed events' (#112) from feat-job-auto-trigger into main
Reviewed-on: #112
2026-02-15 15:44:42 +00:00
Forbes
747bae8354 feat(jobs): wire auto-triggering on bom_changed events, add module guard
- Add IsEnabled("jobs") guard to triggerJobs() to skip when module disabled
- Fire bom_changed trigger from HandleAddBOMEntry, HandleUpdateBOMEntry,
  HandleDeleteBOMEntry (matching existing HandleMergeBOM pattern)
- Add 4 integration tests: revision trigger, BOM trigger, filter mismatch,
  module disabled
- Fix AppShell overflow: hidden -> auto so Settings page scrolls
- Clean old frontend assets in deploy script before extracting

Closes #107
2026-02-15 09:43:05 -06:00
71603bb6d7 Merge pull request 'feat: location hierarchy CRUD API' (#106) from feat-location-crud into main
Reviewed-on: #106
2026-02-15 09:16:52 +00:00
Forbes
4ef912cf4b feat: location hierarchy CRUD API
Add LocationRepository with CRUD operations, hierarchy traversal
(children, subtree by path prefix), and inventory-safe deletion.

Endpoints:
  GET    /api/locations          — list all or ?tree={path} for subtree
  POST   /api/locations          — create (auto-resolves parent_id, depth)
  GET    /api/locations/{path..} — get by hierarchical path
  PUT    /api/locations/{path..} — update name, type, metadata
  DELETE /api/locations/{path..} — delete (rejects if inventory exists)

Uses chi wildcard routes to support multi-segment paths like
/api/locations/lab/shelf-a/bin-3.

Includes 10 handler integration tests covering CRUD, nesting,
validation, duplicates, tree queries, and delete-not-found.

Closes #81
2026-02-15 03:15:54 -06:00
decb32c3e7 Merge pull request 'feat(web): admin settings page — module cards, toggles, config forms' (#105) from feat-admin-settings-api into main
Reviewed-on: #105
2026-02-15 09:09:17 +00:00
Forbes
0be39065ac feat(web): admin settings page with module cards, toggles, config forms
Add admin-only Module Configuration section to the Settings page.
Each module gets a collapsible card with enable/disable toggle,
status badge, module-specific config fields, save and test
connectivity buttons.

- AdminModules: fetches GET /api/modules + GET /api/admin/settings,
  renders Infrastructure and Features groups, restart banner
- ModuleCard: collapsible card with toggle, status badge, field
  layouts per module, save (PUT) and test (POST) actions
- TypeScript types for ModuleInfo, ModulesResponse, admin settings
  API response shapes

Ref: #100
2026-02-15 03:01:33 -06:00
Forbes
101d04ab6f test(api): admin settings handler tests
- TestGetAllSettings — all module keys present, secrets redacted
- TestGetModuleSettings — single module response
- TestGetModuleSettings_Unknown — 404 for unknown module
- TestToggleModule — disable projects, verify registry state
- TestToggleModule_DependencyError — enable dag without jobs, expect 400
- TestToggleRequiredModule — disable core, expect 400
- TestTestConnectivity_Database — ping database, expect success
- TestTestConnectivity_NotTestable — core module, expect 400
2026-02-15 02:51:00 -06:00
Forbes
8167d9c216 feat(api): admin settings API endpoints
Add four admin-only endpoints under /api/admin/settings:

- GET  /                — full config (secrets redacted)
- GET  /{module}        — single module config
- PUT  /{module}        — toggle modules + persist config overrides
- POST /{module}/test   — test external connectivity (database, storage)

PUT publishes a settings.changed SSE event. Config overrides are
persisted for future hot-reload support; changes to database/storage/
server/schemas namespaces return restart_required: true.

Wires SettingsRepository into Server struct.

Closes #99
2026-02-15 02:51:00 -06:00
Forbes
319a739adb feat(db): add SettingsRepository for module state and config overrides
Provides CRUD operations on the module_state and settings_overrides
tables (created in migration 016).

- GetModuleStates / SetModuleState — upsert module enabled/disabled
- GetOverrides / SetOverride / DeleteOverride — JSONB config overrides

Part of #99
2026-02-15 02:51:00 -06:00
e20252a993 Merge pull request 'feat: module system — registry, middleware, and discovery endpoint' (#102) from feat-module-system into main
Reviewed-on: #102
2026-02-14 20:05:42 +00:00
Forbes
138ce16010 fix: remove unreachable code in testutil.findProjectRoot 2026-02-14 14:02:48 -06:00
Forbes
690ad73161 feat(modules): public GET /api/modules discovery endpoint
Add HandleGetModules returning module state, metadata, and
public config (auth providers, Create URI scheme). No auth
required — clients call this pre-login.

Register at /api/modules before the auth middleware.

Ref #97
2026-02-14 14:02:11 -06:00
Forbes
b8abd8859d feat(modules): RequireModule middleware to gate route groups
Add RequireModule middleware that returns 404 with
{"error":"module '<id>' is not enabled"} when a module is disabled.

Wrap route groups:
- projects → RequireModule("projects")
- audit → RequireModule("audit")
- integrations/odoo → RequireModule("odoo")
- jobs, job-definitions, runners → RequireModule("jobs")
- /api/runner (runner-facing) → RequireModule("jobs")
- dag → RequireModule("dag") (extracted into sub-route)

Ref #98
2026-02-14 14:01:32 -06:00
Forbes
4fd4013360 feat(modules): wire registry into server startup
Add modules.Registry and config.Config fields to Server struct.
Create registry in main.go, load state from YAML+DB, log all
module states at startup.

Conditionally start job/runner sweeper goroutines only when the
jobs module is enabled.

Update all 5 test files to pass registry to NewServer.

Ref #95, #96
2026-02-14 14:00:24 -06:00
Forbes
3adc155b14 feat(modules): config loader refactor — YAML → DB → env pipeline
Add ModulesConfig and ModuleToggle types to config.go for explicit
module enable/disable in YAML.

Add LoadState() that merges state from three sources:
1. Backward-compat YAML fields (auth.enabled, odoo.enabled)
2. Explicit modules.* YAML toggles (override compat)
3. Database module_state table (highest precedence)

Validates dependency chain after loading. 5 loader tests.

Ref #95
2026-02-14 13:58:26 -06:00
Forbes
9d8afa5981 feat(modules): module registry with metadata, dependencies, and defaults
In-memory registry for 10 modules (3 required, 7 optional).
SetEnabled validates dependency chains: cannot enable a module
whose dependencies are disabled, cannot disable a module that
others depend on.

9 unit tests covering default state, toggling, dependency
validation, and error cases.

Ref #96
2026-02-14 13:57:32 -06:00
Forbes
f91cf2bc6f feat(modules): settings_overrides and module_state migration
Add migration 016 with two tables for the module system:
- settings_overrides: dotted-path config overrides set via admin UI
- module_state: per-module enabled/disabled state

Update testutil.TruncateAll to include new tables.

Ref #94
2026-02-14 13:56:26 -06:00
ef44523ae8 Merge pull request 'fix(web): standardize typography and spacing to style guide' (#93) from fix-web-style-guide into main
Reviewed-on: #93
2026-02-14 19:37:04 +00:00
Forbes
ba92dd363c fix(web): align all spacing values to 4px grid
Standardize all spacing to multiples of 4px (0.25rem):
- 0.15rem (2.4px) → 0.25rem (4px)
- 0.35rem (5.6px) → 0.25rem (4px)
- 0.375rem (6px) → 0.25rem (4px) for borderRadius
- 0.4rem (6.4px) → 0.5rem (8px)
- 0.6rem (9.6px) → 0.5rem (8px)

Updated theme.css density variables, silo-base.css focus ring,
and all TSX component inline styles.

Closes #71
2026-02-14 13:36:22 -06:00
Forbes
c7857fdfc9 fix(web): standardize font sizes to style guide scale
Map fontWeight: 700 → 600 in non-title contexts (LoginPage, FileDropZone).
Align FileDropZone badge padding to 4px grid.

Closes #70
2026-02-14 13:36:07 -06:00
defb3af56f Merge pull request 'feat: dependency DAG and YAML-defined compute jobs' (#92) from feat-dag-workers into main
Reviewed-on: #92
2026-02-14 19:27:18 +00:00
Forbes
6d7a85cfac docs: add DAG client integration contract for silo-mod and runners 2026-02-14 13:24:36 -06:00
Forbes
22c778f8b0 test: add DAG handler, job handler, and runner token tests 2026-02-14 13:23:21 -06:00
Forbes
ad4224aa8f feat: add silorunner binary with job poll/claim/execute lifecycle 2026-02-14 13:21:21 -06:00
Forbes
b6ac5133c3 feat: add auto-trigger hooks for revision and BOM changes 2026-02-14 13:20:15 -06:00
Forbes
2732554cd2 feat: add job, runner, and DAG API handlers with routes 2026-02-14 13:19:02 -06:00
Forbes
df073709ce feat: add DAG API handlers for graph queries and sync 2026-02-14 13:16:19 -06:00
Forbes
0eb891667b feat: add runner authentication middleware and identity context 2026-02-14 13:14:36 -06:00
Forbes
1952dea00c feat: wire job definitions, DAG/job repos, and background sweepers 2026-02-14 13:13:54 -06:00
Forbes
6becfd82d4 feat: add job and runner repository with atomic claim 2026-02-14 13:11:41 -06:00
Forbes
671a0aeefe feat: add DAG repository with graph queries and dirty propagation 2026-02-14 13:09:41 -06:00
Forbes
f60c25983b feat: add YAML job definition parser and example definitions
New package internal/jobdef mirrors the schema package pattern:
- Load/LoadAll/Validate for YAML job definitions
- Supports trigger types: revision_created, bom_changed, manual, schedule
- Supports scope types: item, assembly, project
- Supports compute types: validate, rebuild, diff, export, custom
- Defaults: timeout=600s, max_retries=1, priority=100

Example definitions in jobdefs/:
- assembly-validate.yaml: incremental validation on revision_created
- part-export-step.yaml: STEP export on manual trigger

11 unit tests, all passing.
2026-02-14 13:06:24 -06:00
Forbes
83e0d6821c feat: add database migrations for DAG and worker system
Migration 014: dag_nodes, dag_edges, dag_cross_edges tables for the
feature-level dependency graph with validation state tracking.

Migration 015: runners, job_definitions, jobs, job_log tables for the
async compute job system with PostgreSQL-backed work queue.

Update TruncateAll in testutil to include new tables.
2026-02-14 13:04:41 -06:00
Forbes
9a8b3150ff docs: add DAG and worker system specifications
DAG.md describes the two-tier dependency graph (BOM DAG + feature DAG),
node/edge data model, validation states, dirty propagation, forward/backward
cone queries, DAG sync payload format, and REST API.

WORKERS.md describes the general-purpose async compute job system: YAML job
definitions, job lifecycle (pending→claimed→running→completed/failed),
runner registration and authentication, claim semantics (SELECT FOR UPDATE
SKIP LOCKED), timeout enforcement, SSE events, and REST API.
2026-02-14 13:03:48 -06:00
376fa3db31 Merge pull request 'test: add test coverage for DB, file handlers, CSV/ODS, and API endpoints' (#86) from test-coverage-batch into main
Reviewed-on: #86
2026-02-14 14:50:38 +00:00
Forbes
257e3d99ac test(api): add revision, schema, audit, and auth handler tests (#78)
Revision tests (8):
- List, get, create, update status/labels, compare, rollback
- Not-found paths for missing items and revisions

Schema tests (4):
- List schemas, get by name, form descriptor, not-found

Audit tests (4):
- Completeness summary (empty + with items), item detail, not-found

Auth tests (4):
- Get current user (authenticated + unauthenticated)
- Auth config response
- Token lifecycle: create, list, revoke
2026-02-13 15:22:28 -06:00