D1 — scaffold + sqlite schema #3

Open
opened 2026-05-20 21:42:06 +00:00 by mik-tf · 0 comments
Owner

D1 — scaffold + sqlite schema

Sub-issue of #? (v0.1 scope). First piece of code in the repo.

Tasks

1. Scaffold from hero_template

Clone hero_template → rename hero_agenthero_os_tfgrid_deployer throughout. End state — 4 crates:

  • crates/hero_os_tfgrid_deployer/ — lifecycle CLI
  • crates/hero_os_tfgrid_deployer_server/ — JSON-RPC backend
  • crates/hero_os_tfgrid_deployer_sdk/ — generated typed client
  • crates/hero_os_tfgrid_deployer_admin/ — admin dashboard (Axum + Askama + Bootstrap, per /hero_ui_dashboard_admin)

Workspace Cargo.toml updated. cargo build --release --workspace passes.

2. service.toml + health endpoints

Per /herolib_base + /hero_service:

  • crates/hero_os_tfgrid_deployer_server/service.toml with proper metadata, kind=server
  • crates/hero_os_tfgrid_deployer_admin/service.toml with kind=admin
  • Both bind their sockets via hero_admin_lib::socket::bind_admin_socket (admin) and the standard rpc_server pattern (server)
  • Both expose /health and /.well-known/heroservice.json

3. sqlite schema

Initial tables (server crate src/db/schema.sql, using rusqlite or sqlx — pick one consistent with the rest of the workspace):

CREATE TABLE users (
    id             INTEGER PRIMARY KEY,
    forge_username TEXT NOT NULL UNIQUE,
    forge_user_id  INTEGER,
    display_name   TEXT,
    forge_email    TEXT,
    created_at     TEXT NOT NULL,
    created_by     TEXT NOT NULL,           -- admin operator
    notes          TEXT,
    forge_token    TEXT                     -- encrypted (hero_proc secret reference, not raw)
);

CREATE TABLE ssh_keys (
    id          INTEGER PRIMARY KEY,
    user_id     INTEGER NOT NULL REFERENCES users(id),
    public_key  TEXT NOT NULL,
    private_key_secret_ref TEXT NOT NULL,    -- hero_proc secret store key
    created_at  TEXT NOT NULL
);

CREATE TABLE vms (
    id             INTEGER PRIMARY KEY,
    user_id        INTEGER NOT NULL REFERENCES users(id),
    compute_vm_id  TEXT NOT NULL,           -- ID returned by ComputeService.deploy_vm
    node_id        INTEGER NOT NULL,
    farm_name      TEXT NOT NULL,
    mycelium_ip    TEXT,
    public_ipv4    TEXT,
    spec_cpu       INTEGER NOT NULL,
    spec_memory_mb INTEGER NOT NULL,
    spec_disk_gb   INTEGER NOT NULL,
    profile        TEXT NOT NULL,           -- 'demo' | 'lightweight' | 'books-only' | 'custom'
    state          TEXT NOT NULL,           -- 'provisioning' | 'ready' | 'failed' | 'decommissioned'
    provisioned_at TEXT NOT NULL,
    decommissioned_at TEXT
);

CREATE TABLE gateway_mappings (
    id            INTEGER PRIMARY KEY,
    vm_id         INTEGER NOT NULL REFERENCES vms(id),
    gateway_fqdn  TEXT NOT NULL,
    gateway_id    TEXT NOT NULL,            -- ID returned by ComputeService.deploy_webgateway
    target_port   INTEGER NOT NULL,         -- 9988 for hero_router default
    created_at    TEXT NOT NULL
);

CREATE TABLE events (
    id        INTEGER PRIMARY KEY,
    vm_id     INTEGER REFERENCES vms(id),
    user_id   INTEGER REFERENCES users(id),
    kind      TEXT NOT NULL,                 -- 'create_user' | 'deploy_vm' | 'bootstrap_run' | etc.
    summary   TEXT NOT NULL,
    detail    TEXT,                          -- JSON blob
    created_at TEXT NOT NULL
);

Secrets (Forge token, SSH private key) NEVER stored in plaintext in sqlite — only references to hero_proc secret entries. The deployer reads them via hero_proc secret get at use-time.

4. CLI shape

hero_os_tfgrid_deployer --info --json returns the canonical service info.
hero_os_tfgrid_deployer --start starts the server (which starts admin via service.toml).

hero_os_tfgrid_deployer system ping is a sanity smoke check.

OpenRPC methods (initial — additional in subsequent sub-issues):

  • deployer.system_ping
  • deployer.list_users (empty for now — fills as we add users)
  • deployer.list_vms (empty for now)

Acceptance criteria

  • cargo fmt --check && cargo clippy --workspace --all-targets -- -D warnings && cargo build --workspace --release passes
  • lab build hero_os_tfgrid_deployer --download --install works (after the first CI release)
  • hero_proc service hero_os_tfgrid_deployer --start brings the server + admin up cleanly
  • curl --unix-socket ~/hero/var/sockets/hero_os_tfgrid_deployer/rpc.sock http://localhost/health → HTTP 200
  • Admin dashboard reachable via hero_proc and shows the empty user / VM tables

References

  • Umbrella: #? (v0.1 scope)
  • Template: hero_template
  • Skills: /hero_service_check_fix · /hero_ui_dashboard_admin · /herolib_base · /hero_service
## D1 — scaffold + sqlite schema Sub-issue of [`#?` (v0.1 scope)](https://forge.ourworld.tf/lhumina_code/hero_os_tfgrid_deployer/issues/2). First piece of code in the repo. ## Tasks ### 1. Scaffold from `hero_template` Clone [`hero_template`](https://forge.ourworld.tf/lhumina_code/hero_template) → rename `hero_agent` → `hero_os_tfgrid_deployer` throughout. End state — 4 crates: - `crates/hero_os_tfgrid_deployer/` — lifecycle CLI - `crates/hero_os_tfgrid_deployer_server/` — JSON-RPC backend - `crates/hero_os_tfgrid_deployer_sdk/` — generated typed client - `crates/hero_os_tfgrid_deployer_admin/` — admin dashboard (Axum + Askama + Bootstrap, per `/hero_ui_dashboard_admin`) Workspace `Cargo.toml` updated. `cargo build --release --workspace` passes. ### 2. service.toml + health endpoints Per `/herolib_base` + `/hero_service`: - `crates/hero_os_tfgrid_deployer_server/service.toml` with proper metadata, kind=server - `crates/hero_os_tfgrid_deployer_admin/service.toml` with kind=admin - Both bind their sockets via `hero_admin_lib::socket::bind_admin_socket` (admin) and the standard rpc_server pattern (server) - Both expose `/health` and `/.well-known/heroservice.json` ### 3. sqlite schema Initial tables (server crate `src/db/schema.sql`, using rusqlite or sqlx — pick one consistent with the rest of the workspace): ```sql CREATE TABLE users ( id INTEGER PRIMARY KEY, forge_username TEXT NOT NULL UNIQUE, forge_user_id INTEGER, display_name TEXT, forge_email TEXT, created_at TEXT NOT NULL, created_by TEXT NOT NULL, -- admin operator notes TEXT, forge_token TEXT -- encrypted (hero_proc secret reference, not raw) ); CREATE TABLE ssh_keys ( id INTEGER PRIMARY KEY, user_id INTEGER NOT NULL REFERENCES users(id), public_key TEXT NOT NULL, private_key_secret_ref TEXT NOT NULL, -- hero_proc secret store key created_at TEXT NOT NULL ); CREATE TABLE vms ( id INTEGER PRIMARY KEY, user_id INTEGER NOT NULL REFERENCES users(id), compute_vm_id TEXT NOT NULL, -- ID returned by ComputeService.deploy_vm node_id INTEGER NOT NULL, farm_name TEXT NOT NULL, mycelium_ip TEXT, public_ipv4 TEXT, spec_cpu INTEGER NOT NULL, spec_memory_mb INTEGER NOT NULL, spec_disk_gb INTEGER NOT NULL, profile TEXT NOT NULL, -- 'demo' | 'lightweight' | 'books-only' | 'custom' state TEXT NOT NULL, -- 'provisioning' | 'ready' | 'failed' | 'decommissioned' provisioned_at TEXT NOT NULL, decommissioned_at TEXT ); CREATE TABLE gateway_mappings ( id INTEGER PRIMARY KEY, vm_id INTEGER NOT NULL REFERENCES vms(id), gateway_fqdn TEXT NOT NULL, gateway_id TEXT NOT NULL, -- ID returned by ComputeService.deploy_webgateway target_port INTEGER NOT NULL, -- 9988 for hero_router default created_at TEXT NOT NULL ); CREATE TABLE events ( id INTEGER PRIMARY KEY, vm_id INTEGER REFERENCES vms(id), user_id INTEGER REFERENCES users(id), kind TEXT NOT NULL, -- 'create_user' | 'deploy_vm' | 'bootstrap_run' | etc. summary TEXT NOT NULL, detail TEXT, -- JSON blob created_at TEXT NOT NULL ); ``` Secrets (Forge token, SSH private key) NEVER stored in plaintext in sqlite — only references to `hero_proc secret` entries. The deployer reads them via `hero_proc secret get` at use-time. ### 4. CLI shape `hero_os_tfgrid_deployer --info --json` returns the canonical service info. `hero_os_tfgrid_deployer --start` starts the server (which starts admin via service.toml). `hero_os_tfgrid_deployer system ping` is a sanity smoke check. OpenRPC methods (initial — additional in subsequent sub-issues): - `deployer.system_ping` - `deployer.list_users` (empty for now — fills as we add users) - `deployer.list_vms` (empty for now) ### Acceptance criteria - `cargo fmt --check && cargo clippy --workspace --all-targets -- -D warnings && cargo build --workspace --release` passes - `lab build hero_os_tfgrid_deployer --download --install` works (after the first CI release) - `hero_proc service hero_os_tfgrid_deployer --start` brings the server + admin up cleanly - `curl --unix-socket ~/hero/var/sockets/hero_os_tfgrid_deployer/rpc.sock http://localhost/health` → HTTP 200 - Admin dashboard reachable via hero_proc and shows the empty user / VM tables ## References - Umbrella: [`#?` (v0.1 scope)](https://forge.ourworld.tf/lhumina_code/hero_os_tfgrid_deployer/issues/2) - Template: [`hero_template`](https://forge.ourworld.tf/lhumina_code/hero_template) - Skills: `/hero_service_check_fix` · `/hero_ui_dashboard_admin` · `/herolib_base` · `/hero_service`
Sign in to join this conversation.
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
lhumina_code/hero_os_tfgrid_deployer#3
No description provided.