commit full of PRs

PRs full of commit

basically i used the ENTIRE mimo grant to convert a system to another. hope this one is good. may fail.
This commit is contained in:
lda committed 2026-05-03 00:48:11 +07:00 Verified
1 parent b5a28c801c
commit b850c218ec
112 files changed
+2407 -4237

No files matched your search

-100
View File
@@ -1,100 +0,0 @@
# Wakey Checkpoint (2026-04-11)
## Snapshot
This checkpoint captures the current state after control-plane migration, logging hardening, config ergonomics, and state storage upgrades.
## What Is Done
- Legacy router-hosted HTTP/static layer removed from `wakey` crate.
- New `wakey-control-plane` crate is active for:
- enroll-token issuance
- agent enrollment
- connected-agent websocket registry
- command relay to agent
- `wakey-agent` is active for outbound websocket execution and local command dispatch.
## Logging + Telemetry
- High-signal logs were added across:
- control-plane API relay path
- control-plane websocket lifecycle
- control-plane state lifecycle
- agent command lifecycle, session lifecycle, and enrollment
- Correlated relay spans include command context (`agent_id`, `request_id`, `command`).
- Control-plane telemetry is config-driven:
- optional OTLP endpoint
- optional JSON logs
- fallback local logs when OTLP endpoint is not set
## Config Ergonomics
### Control-plane
- Config file support is wired (`/etc/wakey-control-plane/config.toml` by default).
- `serve` can read defaults from config file and CLI can override.
- New `init-config` command scaffolds a control-plane config file.
### Agent
- Existing `init-config` command scaffolds agent config.
- Enrollment can optionally signal reload of running daemon.
## State Storage Upgrade
- Control-plane state backend moved from JSON snapshot to embedded `sled` DB.
- Default state path changed to `/var/lib/wakey-control-plane/state.db`.
- Legacy JSON migration support has been removed; sled is now the only supported
state format.
- Enroll tokens include persisted expiry timestamps and are validated on enroll.
- Periodic and explicit garbage collection remove expired tokens.
## Operator Commands
### Control-plane bootstrap
```sh
wakey-control-plane init-config
wakey-control-plane serve --config-file /etc/wakey-control-plane/config.toml
```
### Issue enroll token (live daemon path)
```sh
wakey-control-plane issue-enroll-token --public-url https://cp.example.com
```
### Agent bootstrap
```sh
wakey-agent enroll --server-url https://cp.example.com --enroll-token <token>
wakey-agent serve --config /etc/wakey-agent/config.toml
```
## Build Health
- Last verified passing:
- `cargo check --workspace`
- `cargo clippy --workspace`
## Test Coverage Added In This Pass
- Unit tests in `wakey-control-plane/src/state/store.rs` now cover:
- expired-token garbage collection removes persisted stale tokens
- enroll rejects expired tokens and consumes stale entries
- state stats counters for agents and expired token totals
## Known Tradeoffs / Follow-ups
- Reload semantics with `sled` are now mostly no-op for in-memory state (data is durable in DB).
- No dedicated state-inspection CLI command yet (suggestion: add `state-stats` command).
- OTLP configuration is currently control-plane focused; agent parity can be added if needed.
## Suggested Next Steps
1. Add a control-plane `state-stats` command to print DB path, agent count, token count.
2. Add symmetric telemetry config support in `wakey-agent` config file.
3. Add integration tests for:
- enroll + relay over websocket
- legacy JSON-to-sled migration path
- init-config command behavior and overrides
-82
View File
@@ -1,82 +0,0 @@
# Wakey Checkpoint (2026-04-12)
## Snapshot
This checkpoint captures progress after adding audit persistence, alert evaluation and transitions, control-plane alert APIs, and websocket timing diagnostics across agent and control-plane.
## Major Changes Landed
- Control-plane audit system implemented with persistent sled-backed events.
- Audit emission wired into:
- enroll accept/reject
- token issue/list/revoke
- command dispatch/result/error/timeout
- websocket auth accept/reject and disconnect
- Audit query API added:
- `GET /api/v1/control/audit/events`
- Active alert engine added with deterministic rules over audit + live session state.
- Alert APIs added:
- `GET /api/v1/control/alerts`
- `GET /api/v1/control/alerts/history`
- `GET /api/v1/control/alerts/ws`
- Alert transition persistence added (open/resolve transitions tracked across evaluations).
- Route classes split explicitly in runtime:
- public routes (enroll/ws/health)
- control routes (`/api/v1/control/*`)
- Caddy template added for edge policy and Cloudflare Access boundary:
- `deploy/Caddyfile.control-plane.example`
## Reliability and Diagnostics Improvements
- Agent websocket connect diagnostics now include:
- DNS resolution timing (`dns_resolve_ms`)
- websocket connect timing (`ws_connect_ms`)
- Control-plane websocket lifecycle logs include:
- connect-to-hello timing
- connect-to-auth timing
- hello-to-auth timing
- Slow connect warnings are now emitted when timing thresholds are exceeded.
## Root-Cause Findings Captured
- Long agent websocket connect delays were reproduced and traced to hostname resolution path.
- Switching agent `server_url` hostname to direct IP made connect immediate.
- This confirms app-level relay logic was not the source of the startup delay.
## Verification Status
- `cargo check --workspace` passing after all changes.
- Added and passing tests include:
- audit event append/filter in state store
- alert transition open/resolve persistence
- alert evaluator rule checks (offline + timeout, auth/enroll rejection spikes)
## Current API Surface for UI Start
- Agents and command execution:
- `GET /api/v1/control/agents`
- `POST /api/v1/control/agents/{agent_id}/command`
- Audits:
- `GET /api/v1/control/audit/events`
- Alerts:
- `GET /api/v1/control/alerts`
- `GET /api/v1/control/alerts/history`
- websocket subscribe: `GET /api/v1/control/alerts/ws`
## Remaining Plan Items (Most Significant)
1. UI implementation (`/ui` app shell and pages) is still open.
2. Alert dedupe/cooldown persistence and tuning are still basic and need hardening.
3. Audit retention pruning policy and long-run storage controls are not finalized.
4. Edge auth enforcement tests and deployment rehearsals remain to be added.
5. Multi-day soak drills and failure-injection validation remain open.
## Suggested Next Actions
1. Build minimal UI shell with three views:
- agents/commands
- audit timeline
- alerts panel (active + history + websocket stream)
2. Add periodic retention task for audit and alert transition trees.
3. Add proxy-level integration tests that assert private endpoints are blocked without Access headers.
4. Run a 48-72h soak with hostname vs IP connect-path metrics collected.
@@ -1,14 +0,0 @@
# Control Plane Review
## Findings
1. High: the admin/control API is effectively unauthenticated, so anyone who can reach the server can issue enroll tokens, list/revoke tokens, inspect audit/alerts, and send live commands to agents. In [`wakey-control-plane/src/runtime/mod.rs:61`](c:/Users/Admin/Documents/realshit/wakey/wakey-control-plane/src/runtime/mod.rs#L61) through [`wakey-control-plane/src/runtime/mod.rs:109`](c:/Users/Admin/Documents/realshit/wakey/wakey-control-plane/src/runtime/mod.rs#L109), `control_api_routes()` is merged straight into the app with no auth middleware despite the comment saying these routes are “admin-only.” The UI also calls those endpoints directly with plain `fetch` and no auth material in [`ui/src/api.ts:60`](c:/Users/Admin/Documents/realshit/wakey/ui/src/api.ts#L60) through [`ui/src/api.ts:123`](c:/Users/Admin/Documents/realshit/wakey/ui/src/api.ts#L123). This is a full remote-takeover issue for the control plane, not just a missing polish item.
2. High: a second websocket connection for the same `agent_id` silently replaces the current session, but the old authenticated socket is left alive and can still submit `result`/`error` frames against pending requests. In [`wakey-control-plane/src/ws.rs:195`](c:/Users/Admin/Documents/realshit/wakey/wakey-control-plane/src/ws.rs#L195) through [`wakey-control-plane/src/ws.rs:200`](c:/Users/Admin/Documents/realshit/wakey/wakey-control-plane/src/ws.rs#L200), a successful auth simply overwrites `sessions[agent_id] = tx.clone()`. The previous socket is not closed or demoted. Later, any authenticated socket can satisfy pending requests in [`wakey-control-plane/src/ws.rs:229`](c:/Users/Admin/Documents/realshit/wakey/wakey-control-plane/src/ws.rs#L229) through [`wakey-control-plane/src/ws.rs:247`](c:/Users/Admin/Documents/realshit/wakey/wakey-control-plane/src/ws.rs#L247), while requests are correlated only by `request_id` created in [`wakey-control-plane/src/api/commands.rs:91`](c:/Users/Admin/Documents/realshit/wakey/wakey-control-plane/src/api/commands.rs#L91) through [`wakey-control-plane/src/api/commands.rs:97`](c:/Users/Admin/Documents/realshit/wakey/wakey-control-plane/src/api/commands.rs#L97). That creates a split-brain/race condition where a stale or malicious prior session for the same agent can inject or win replies.
3. Medium: configured seed enroll tokens are reinserted into the database on every startup, so “one-time” tokens become reusable after a restart if they remain in config. In [`wakey-control-plane/src/state/store.rs:52`](c:/Users/Admin/Documents/realshit/wakey/wakey-control-plane/src/state/store.rs#L52) through [`wakey-control-plane/src/state/store.rs:68`](c:/Users/Admin/Documents/realshit/wakey/wakey-control-plane/src/state/store.rs#L68), `load_or_init()` blindly seeds `daemon.enroll_tokens` into sled every time the process starts. Enrollment consumes tokens in [`wakey-control-plane/src/state/store.rs:91`](c:/Users/Admin/Documents/realshit/wakey/wakey-control-plane/src/state/store.rs#L91) through [`wakey-control-plane/src/state/store.rs:109`](c:/Users/Admin/Documents/realshit/wakey/wakey-control-plane/src/state/store.rs#L109), but that consumption is undone on the next boot if the token still exists in config. That breaks the “short-lived/one-time” assumption and makes operational mistakes much more likely.
## Residual Risks
- The control-plane/UI surface is growing quickly and currently assumes a trusted environment in multiple places. Even after adding admin auth, I would expect more authz/session-boundary issues to surface.
- The command relay path is conceptually good, but it needs stronger session ownership rules before it is trustworthy under reconnect races or duplicated agents.
@@ -1,57 +0,0 @@
## Plan: Audit, Alerts, UI, and Safe Edge Exposure
Recommended approach: ship in this order audit first, alerts second, UI third, then edge hardening and soak. This gives you observability truth before you build subscriptions and screens, and keeps risky control APIs private behind Cloudflare Access at Caddy.
**Steps**
1. Phase A: Lock trust boundaries and endpoint classes.
2. Public Agent API stays exposed: /api/v1/agents/enroll, /api/v1/agent/ws, /healthz.
3. Private Control API stays protected: /api/v1/control/* and /ui/*.
4. Phase A: Define AuditEvent schema and retention defaults.
5. Phase B: Add audit persistence in sled and emit at key points.
6. Emit audit on token issue/list/revoke, ws auth/disconnect, command dispatch/result/timeout/error, and reload/config operations.
7. Phase B: Add audit query API with filters and pagination.
8. Phase C: Implement deterministic alert rules and evaluator loop.
9. Start with offline agent threshold, timeout-rate threshold, auth-failure spike, token misuse attempts.
10. Add dedupe and cooldown so alerts do not flap.
11. Phase C: Add alert delivery APIs.
12. Poll-first endpoint for active alerts and recent transitions, websocket stream optional after rules stabilize.
13. Phase D: Build same-domain UI app shell at /ui with origin-relative API client.
14. Phase D: Build pages: Agent Health, Command Runner, Audit Timeline, Alerts Panel.
15. Phase E: Add Caddy deployment template with Cloudflare Access policy boundaries and websocket support.
16. Phase E: Run end-to-end drills and 48-72h soak.
**Relevant files**
- [wakey-control-plane/src/runtime/mod.rs](wakey-control-plane/src/runtime/mod.rs)
- [wakey-control-plane/src/api/commands.rs](wakey-control-plane/src/api/commands.rs)
- [wakey-control-plane/src/api/control.rs](wakey-control-plane/src/api/control.rs)
- [wakey-control-plane/src/ws.rs](wakey-control-plane/src/ws.rs)
- [wakey-control-plane/src/state/store.rs](wakey-control-plane/src/state/store.rs)
- [wakey-control-plane/src/state/types.rs](wakey-control-plane/src/state/types.rs)
- [wakey-control-plane/src/config/types.rs](wakey-control-plane/src/config/types.rs)
- [wakey-control-plane/src/config/resolve.rs](wakey-control-plane/src/config/resolve.rs)
- [wakey-control-plane/src/cli.rs](wakey-control-plane/src/cli.rs)
- [README.md](README.md)
- [scripts/init/openwrt/wakey](scripts/init/openwrt/wakey)
- [.github/plan-controlPlaneAppV1.prompt.md](.github/plan-controlPlaneAppV1.prompt.md)
**Verification**
1. Unit tests for audit append/query, pagination, retention pruning.
2. Unit tests for alert rule evaluation, dedupe, cooldown.
3. Contract tests for request_id correlation across command result and timeout/error audit records.
4. Integration tests for ws auth/disconnect audit events and command timeout event emission.
5. API tests for audit and alert endpoints.
6. Edge security tests that unauthenticated /api/v1/control/* and /ui/* are denied.
7. Soak tests for reconnect churn and audit growth stability.
**Decisions captured**
- Admin auth default: Cloudflare Access only, enforced at Caddy.
- UI host: same domain path deployment.
- Shell bridge: excluded from v1 due high risk and low break-glass value during hard router failures.
- Alert delivery: poll-first in v1, websocket stream optional.
**Caddy policy shape for this plan**
1. Route /api/v1/agents/enroll and /api/v1/agent/ws to control-plane upstream without Cloudflare Access gate.
2. Route /api/v1/control/* and /ui/* only when Cloudflare Access authentication is valid.
3. Preserve websocket upgrade headers on /api/v1/agent/ws.
4. Keep control-plane process bound to private interface or localhost behind Caddy.
5. Deny direct exposure of /api/v1/control/* from origin network paths.
-32
View File
@@ -1,32 +0,0 @@
## Plan: Control Plane App v1
Build an end-to-end, ops-ready v1 over 6+ weeks by reusing current wakey and wakey-core logic, keeping wakey-agent as outbound executor, and adding a dedicated control-plane server plus minimal operator UI.
**Steps**
1. Phase 1, contract baseline: finalize relay contract for command, result, error, request correlation, timeout, retry, and forward compatibility behavior.
2. Phase 1, boundary lock: keep execution in wakey service functions and keep domain DTOs in wakey-core while removing legacy HTTP/static compatibility code.
3. Phase 2, server skeleton: implement enrollment endpoint, agent registry, websocket acceptor, and request correlation map. Depends on step 1 and step 2.
4. Phase 2, relay core: implement command submission to connected agents, request_id correlation, timeout paths, and structured relay errors. Depends on step 3.
5. Phase 2, persistence and identity: durable agent records, enroll token lifecycle, and safe credential metadata. Parallel with step 4 after schema is stable.
6. Phase 3, operator surface: add API for agent inventory, health, command execution, and recent outcomes; add minimal UI for core operations. Depends on step 4 and step 5.
7. Phase 3, ops hardening: metrics, logs, audits, heartbeat liveness checks, and alert thresholds. Parallel with step 6.
8. Phase 4, deployment pipeline: add server build and deploy artifacts, environment templates, and rollback workflow. Depends on step 6 and step 7.
9. Phase 4, validation and soak: run enrollment-to-command end-to-end tests and disconnect/failure drills with multi-day soak. Depends on step 8.
**Relevant files to reuse**
- [wakey-agent/src/protocol.rs](wakey-agent/src/protocol.rs)
- [wakey-agent/src/session.rs](wakey-agent/src/session.rs)
- [wakey-agent/src/dispatch.rs](wakey-agent/src/dispatch.rs)
- [src/service/mod.rs](src/service/mod.rs)
- [wakey-core/src/model](wakey-core/src/model)
- [scripts/package_rootfs.ps1](scripts/package_rootfs.ps1)
- [.gitea/workflows/release.yml](.gitea/workflows/release.yml)
**Verification**
1. Contract tests for command and result serialization, request_id stability, and unknown frame tolerance.
2. Relay integration tests for enrollment, websocket auth flow, correlation, and timeout handling.
3. Security tests for token lifecycle and invalid credential rejection.
4. API tests for registry and command execution behavior.
5. Observability tests for heartbeat, reconnect counters, latency, and failure alerts.
6. Deployment tests for build, release, rollback rehearsal, and staging smoke checks.
7. On-device tests for enroll, procd lifecycle, reconnect, and remote command round trips.
@@ -1,184 +0,0 @@
# Plan: Observation Store And Sync V1
## Summary
Build device observation support in layers:
1. Local router observations are captured by `wakey observe ...` from OpenWrt hotplug.
2. `wakey-linux` stores current observed DHCP/neigh state locally.
3. `wakey-agent` forwards compact observations to the control plane.
4. The control plane stores observations per agent and later joins them to known devices through `device_identifiers`.
This is separate from durable identity. Observations are facts an agent saw at a time; known devices are manual/user-approved identity records.
## Network/API Boundary
The control plane has two route classes:
- Public agent routes: intended to be reachable by agents.
- Protected control routes: intended to sit behind Cloudflare Access/admin auth.
Observation upload belongs on the public agent route surface because routers/agents must call it:
```text
POST /api/v1/agents/observations
```
The endpoint must require normal agent authentication, using the same persistent `agent_id`/`agent_token` trust model as WebSocket auth. It must not be a Cloudflare Access-only admin endpoint.
Admin/UI read APIs belong under protected control routes:
```text
GET /api/v1/control/observations
GET /api/v1/control/devices
```
## Step 1: Local Observation Store
Replace the narrow `/tmp/wakey_mac_names.json` cache with a local observation store owned by `wakey-linux`.
Minimum local tables/state:
```text
observed_dhcp_clients:
mac
ip
hostname
first_seen_unix
last_seen_unix
last_action
observed_neighbors:
key
mac
ip
first_seen_unix
last_seen_unix
last_action
```
Behavior:
- Hotplug scripts stay minimal and call `wakey-agent observe ...`.
- `wakey-agent observe ...` delegates to `wakey observe ...`.
- `wakey observe dhcp ...` writes DHCP observations.
- `wakey observe neigh ...` writes neighbor observations.
- Existing `wakey leases` and `wakey inventory` still read live sources first, then enrich from the local observation store.
- Do not make local queries depend exclusively on hotplug events yet.
## Step 2: Control-Plane Observation Tables
Add observation tables early so future API/UI work does not need another major state refactor.
Control-plane schema:
```text
agent_device_observations:
observation_key TEXT PRIMARY KEY
agent_id TEXT NOT NULL
kind TEXT NOT NULL
mac TEXT
ip TEXT
hostname TEXT
first_seen_unix INTEGER NOT NULL
last_seen_unix INTEGER NOT NULL
last_action TEXT NOT NULL
agent_device_observation_events:
event_id TEXT PRIMARY KEY
agent_id TEXT NOT NULL
kind TEXT NOT NULL
action TEXT NOT NULL
mac TEXT
ip TEXT
hostname TEXT
ts_unix INTEGER NOT NULL
```
Keep `agent_device_observation_events` optional in behavior if needed, but create it in schema early. Current-state rows are the primary path; event history is for debugging/audit.
Indexes:
```text
agent_device_observations(agent_id)
agent_device_observations(mac)
agent_device_observations(ip)
agent_device_observations(hostname)
agent_device_observations(last_seen_unix)
agent_device_observation_events(agent_id, ts_unix)
agent_device_observation_events(mac)
```
## Step 3: Agent Upload
Add agent upload payload:
```json
{
"observations": [
{
"kind": "dhcp",
"action": "update",
"mac": "04:7c:16:79:6d:ee",
"ip": "192.168.100.94",
"hostname": "lda",
"first_seen_unix": 1770000000,
"last_seen_unix": 1770000123
}
]
}
```
Rules:
- Agent may send snapshots periodically and after local observe events.
- Control plane upserts current-state rows by stable observation key.
- Observation keys should be deterministic from `agent_id`, `kind`, and the best available identifier:
- DHCP with MAC: `agent:{agent_id}:dhcp:mac:{mac}`
- Neigh with MAC: `agent:{agent_id}:neigh:mac:{mac}`
- Neigh without MAC: `agent:{agent_id}:neigh:ip:{ip}`
- Uploads must not create known devices automatically.
## Step 4: Join Observations To Known Devices
Known devices already have durable IDs and manual identifiers:
```text
known_devices
device_identifiers
```
Join rule:
```text
agent_device_observations.mac
-> device_identifiers(kind = 'mac', value = mac)
-> known_devices.device_id
```
Unknown observations are rows that do not match any manual `device_identifiers` row.
This enables:
- same known device observed by multiple agents;
- same known device with multiple MACs;
- UI flow to attach an unknown observed MAC to an existing known device;
- wake flows that choose agent-local observed IP/MAC context for a known device.
## Step 5: UI/API Later
After storage and upload exist:
- show known devices with all matching observations grouped by agent;
- show unknown observations;
- add action: attach observation identifier to known device;
- add action: create known device from observation;
- add wake action from known device using a selected agent/observation.
## Defaults
- `wakey` remains the local router/debugging CLI.
- `wakey-agent` is the sync bridge to the control plane.
- `wakey-control-plane` is durable identity and multi-agent view.
- Local observation store is not authoritative; live sources still matter.
- Control-plane observations are not durable identity; only manual known-device identifiers are.
-149
View File
@@ -1,149 +0,0 @@
## Plan: wakey UI v1 (Device-First)
The Operator UI is not the end goal by itself.
The goal is to make wakey excellent at its original purpose: quickly finding devices and waking them reliably.
Agent, audit, and token features remain important, but they should support the device workflow rather than dominate the navigation and development effort.
## Product North Star
An operator should be able to do this in under 10 seconds:
1. Open the UI.
2. Search for a device by name, IP, or MAC.
3. See whether it looks online/reachable.
4. Trigger wake.
5. See immediate command result and short follow-up status.
## Scope Priorities
1. P0: Device discovery and wake UX.
2. P1: Fast troubleshooting context around wake results.
3. P2: Fleet/agent/admin operations.
This explicitly means pages and components for Agent, Audit, Alerts, and Tokens should be present but secondary in visual hierarchy and effort until P0 is complete.
## IA Direction (v1)
Primary top-level focus:
1. Devices
2. Wake Queue (or Recent Actions)
Secondary top-level focus:
1. Fleet Health
2. Audit
3. Alerts
4. Access/Tokens
If needed, keep current routes during transition, but adjust default landing and navigation emphasis so Devices is the home workflow.
## Phase Plan
### Phase 1: Device-Centric Foundation
1. Add a dedicated Devices page that merges existing status/leases/inventory signal into one operator list.
2. Include searchable columns for name, IP, MAC, interface/dev, and recency indicators.
3. Provide row-level wake action and bulk-safe interaction model (single-click row action, confirm for bulk).
4. Define a compact "device confidence" heuristic from available data (for example: recent lease + reachable neighbor).
5. Set the default route to Devices, with prominent search and wake controls above the fold.
Acceptance criteria:
1. Search by hostname, IP, and MAC all work from one input.
2. Wake action reachable in one click from list row.
3. Response feedback shown immediately with clear success/error text.
### Phase 2: Wake Execution UX
1. Build a focused wake panel with explicit target preview before send.
2. Provide quick presets: "wake by selected device", "wake by MAC", "wake by query".
3. Persist recent wake targets locally for operator speed.
4. Add post-wake verification loop (short timed refresh of status indicators).
5. Surface request correlation id and a copy action for incident sharing.
Acceptance criteria:
1. Operator can retry wake with one click.
2. Operator can see last 20 wake attempts with outcome and timestamp.
3. Error states differentiate validation, timeout, and execution failure.
### Phase 3: Context Without Workflow Drift
1. Keep Alerts and Audit accessible from device rows and wake outcomes.
2. Add contextual deep links: device -> related alerts, device -> recent audit events.
3. Improve filtering for alerts/audit with saved local filter presets.
4. Add gentle live updates, keeping websocket optional with polling fallback.
Acceptance criteria:
1. From any failed wake, operator can jump to relevant audit entries in one step.
2. Alerts page can be filtered by kind/severity/agent and linked back to impacted devices.
### Phase 4: Fleet/Admin Hardening
1. Keep Agents page for connectivity and control routing visibility.
2. Keep Tokens page for enrollment lifecycle operations.
3. Keep Dashboard but reframe metrics around "device availability" and "wake success" first.
4. Add audit-friendly confirmation flows for destructive actions.
Acceptance criteria:
1. Admin flows do not block or slow P0 device workflows.
2. All admin actions produce clear audit-visible outcomes.
### Phase 5: Validation and Production Readiness
1. Add smoke tests for P0 flow: find device -> wake -> observe result.
2. Add contract checks for command payload/response shapes used by device and wake screens.
3. Add scenario drills (offline agent, delayed command, websocket drop, expired token).
4. Verify edge policy still protects control routes while preserving required public endpoints.
Acceptance criteria:
1. P0 flow remains usable during partial degradation.
2. Build/typecheck/test gates stay green in CI.
## Concrete UI Backlog (Ordered)
1. Create DevicesPage with unified searchable table.
2. Wire wake action directly from device row.
3. Add Recent Wake Actions panel with outcomes.
4. Add post-wake short verification refresh.
5. Rework Dashboard cards to device-first metrics.
6. Add deep links from wake result to audit and alerts context.
7. Add empty/loading/error skeleton patterns tuned for device list scale.
## Metrics of Success
1. Time-to-wake median under 10 seconds for known target.
2. Wake success rate visible per time window.
3. Fewer operator clicks for common tasks (device lookup + wake).
4. Reduced navigation to agent-centric pages for everyday usage.
## Design and Interaction Principles
1. Device-first information density over generic admin dashboards.
2. Search and action bar always visible on desktop and mobile.
3. Action feedback must be immediate and explicit.
4. Keep advanced infrastructure details available but visually de-emphasized.
## Architecture Decisions
1. Keep same-domain /ui serving and origin-relative API requests.
2. Keep route and API contracts stable while iterating UX aggressively.
3. Treat websocket as progressive enhancement; polling fallback required.
4. Preserve Cloudflare Access boundary for all control endpoints.
## Relevant Files
1. [ui/src/App.tsx](ui/src/App.tsx)
2. [ui/src/pages/CommandsPage.tsx](ui/src/pages/CommandsPage.tsx)
3. [ui/src/pages/DashboardPage.tsx](ui/src/pages/DashboardPage.tsx)
4. [ui/src/api.ts](ui/src/api.ts)
5. [wakey-control-plane/src/api/commands.rs](wakey-control-plane/src/api/commands.rs)
6. [wakey-control-plane/src/api/audit.rs](wakey-control-plane/src/api/audit.rs)
7. [wakey-control-plane/src/api/alerts.rs](wakey-control-plane/src/api/alerts.rs)
8. [wakey-control-plane/src/api/control.rs](wakey-control-plane/src/api/control.rs)
9. [wakey-control-plane/src/runtime/mod.rs](wakey-control-plane/src/runtime/mod.rs)
10. [README.md](README.md)
## Immediate Next Build Slice
1. Implement DevicesPage and make it default route.
2. Add row-level wake action with in-place result feedback.
3. Add Recent Wake Actions section backed by local state first, then audit correlation.
4. Rebalance navigation labels/order to make device workflows primary.
-69
View File
@@ -1,69 +0,0 @@
# Plan: SQLx Query Macro Adoption
## Summary
Move control-plane SQL from unchecked `sqlx::query(...)` calls toward `sqlx::query!` / `query_as!` where the SQL shape is static.
This gives compile-time checking for table/column names and Rust value types. Dynamic filter builders can stay on `QueryBuilder`.
## Offline Setup
Normal builds should not need a live database:
```text
SQLX_OFFLINE=true
```
`.env` is ignored, so copy:
```sh
cp .env.example .env
```
SQLx query metadata should be generated into `.sqlx/` and committed.
Prepare metadata with:
```sh
cargo install sqlx-cli --no-default-features --features sqlite
./scripts/prepare_sqlx_sqlite.sh
```
The script:
- creates a temporary SQLite database;
- runs `wakey-control-plane/migrations`;
- runs `cargo sqlx prepare --workspace -- -p wakey-control-plane --all-targets --all-features`;
- writes `.sqlx/`.
## Conversion Rules
Use `query!` / `query_as!` for static SQL:
- inserts;
- deletes;
- simple selects by primary key;
- fixed update statements;
- count queries.
Keep non-macro SQL for genuinely dynamic SQL:
- audit event filters built with `QueryBuilder`;
- observation listing with optional filters, unless split into fixed branches;
- any SQL where table/column names are intentionally generated.
## Test/CI
After query macros are introduced, CI should add:
```sh
cargo install sqlx-cli --no-default-features --features sqlite
./scripts/prepare_sqlx_sqlite.sh
cargo sqlx prepare --check --workspace -- --all-targets --all-features
```
Do not add the CI check until the first `.sqlx/` metadata is committed, otherwise it adds dependency install cost without catching anything.
## Notes
The SQLx docs say offline mode needs `cargo sqlx prepare` output checked into version control, and that `DATABASE_URL` takes precedence unless `SQLX_OFFLINE=true` is set. Keep `.env` local; commit `.env.example` and `.sqlx/`.