246 lines
11 KiB
Markdown
246 lines
11 KiB
Markdown
# morphit-ops
|
|
|
|
Operator command-line tool for a Morphit instance. Read-mostly
|
|
view into the indexer + relay shared database: status snapshot,
|
|
drain queue depth, recent signups, abuse signals, moderation
|
|
flags. Designed to be run on the same VPS that hosts the
|
|
indexer and relay, over SSH.
|
|
|
|
The CLI does NOT mutate state. Everything it shows is sourced
|
|
from queries against the same Postgres the indexer and relay
|
|
write to; no admin endpoints are involved. This keeps the
|
|
attack surface small (read-only Postgres connection is the only
|
|
auth the CLI needs).
|
|
|
|
The `init` subcommand is the exception — it's a first-time
|
|
setup wizard that writes `morphit.config.env` and a posting-key
|
|
keystore to disk. See "First-time setup" below.
|
|
|
|
## First-time setup
|
|
|
|
Run on a fresh checkout to generate your `morphit.config.env`
|
|
and active-key keystore:
|
|
|
|
```sh
|
|
cd apps/ops-cli
|
|
npx tsx src/main.ts init
|
|
```
|
|
|
|
The wizard:
|
|
|
|
1. Runs a system check (CPU, RAM, disk, OS version, Postgres
|
|
reachability, outbound HTTPS). Catches issues before you
|
|
commit time to interactive prompts.
|
|
2. Walks you through 18 setup steps with ELI5 explanations.
|
|
3. Validates each input (Blurt account names checked against
|
|
the chain, database URL parsed, etc.).
|
|
4. Shows a review and asks for confirmation.
|
|
5. Writes `morphit.config.env` and `apps/relay/keystore.{wif,json}`
|
|
with `0600` permissions.
|
|
|
|
If you only want to verify your hardware/OS meets the bar
|
|
before committing time to setup:
|
|
|
|
```sh
|
|
npx tsx src/main.ts init --check-only
|
|
```
|
|
|
|
`init` works on a fresh checkout where `npm install` hasn't
|
|
been run yet — it has no third-party dependencies beyond what
|
|
ships in Node.js.
|
|
|
|
## Publish your instance to the federation
|
|
|
|
After your indexer + relay + frontend are up and serving
|
|
correctly at your public origin, run:
|
|
|
|
```sh
|
|
# Source your wizard-generated env files so register can
|
|
# read them:
|
|
set -a; . ./morphit.env; . ./morphit.config.env; set +a
|
|
|
|
npx tsx apps/ops-cli/src/main.ts register
|
|
```
|
|
|
|
This posts a `morphit_operator_register_v1` op on the Blurt
|
|
chain. Within ~10 minutes every Morphit indexer (including
|
|
morphit.io and your own) will see it via chain replay,
|
|
probe your origin to verify it's serving correctly, and add
|
|
your instance to their `/instances` directory.
|
|
|
|
You can verify your registration landed by visiting your
|
|
own `/instances` page — you should appear with status
|
|
`good` and a "You are here" badge.
|
|
|
|
The `register` subcommand requires `npm install` to have run
|
|
(it dynamically loads `@beblurt/dblurt` for chain
|
|
broadcasting).
|
|
|
|
## Quick start (after init)
|
|
|
|
```sh
|
|
cd apps/ops-cli
|
|
npm install
|
|
export MORPHIT_OPS_DATABASE_URL=postgres://morphit:secret@localhost:5432/morphit
|
|
npx tsx src/main.ts status
|
|
```
|
|
|
|
You should see a multi-section dashboard summarizing indexer
|
|
health, drain queue, today's signups, and 24h moderation flags.
|
|
|
|
## Configuration
|
|
|
|
The CLI reads its database connection from environment variables.
|
|
Only the database URL is required; everything else has a
|
|
sensible default.
|
|
|
|
| Variable | Required | Default | Notes |
|
|
| ------------------------------------ | ------------------ | --------------- | --------------------------------------------------------------------- |
|
|
| `MORPHIT_OPS_DATABASE_URL` | Yes (or alt below) | — | Postgres connection string |
|
|
| `MORPHIT_INDEXER_DATABASE_URL` | Alt | — | Falls back to this if MORPHIT_OPS_DATABASE_URL is unset |
|
|
| `DATABASE_URL` | Alt | — | Final fallback |
|
|
| `MORPHIT_OPS_RELAY_ACCOUNT` | No | `morphit-relay` | Matched against accounts.creator for signup queries |
|
|
| `MORPHIT_OPS_FEES_ACCOUNT` | No | `morphit-fees` | Currently informational; used in future subcommands |
|
|
| `MORPHIT_RELAY_SIGNUP_DAILY_CEILING` | No | `50` | Snapshot of relay's ceiling, used to compute "X / Y" on dashboard |
|
|
| `MORPHIT_OPS_COLOR` | No | `auto` | `auto` (TTY-aware), `always`, or `never`. `NO_COLOR` env also honored |
|
|
|
|
### Threshold tunables
|
|
|
|
Each metric on the status dashboard maps to a status glyph
|
|
(`✓` / `⚠` / `✗`) by comparing its value to a warn/error
|
|
threshold pair. Defaults follow the audit-recommended values.
|
|
Override any of them via env:
|
|
|
|
| Env variable | Default | Maps to |
|
|
| ------------------------------------------------ | ----------- | -------------------------------------- |
|
|
| `MORPHIT_OPS_THRESHOLD_RELAY_BALANCE_WARN` | `100` | Warn below this many BLURT |
|
|
| `MORPHIT_OPS_THRESHOLD_RELAY_BALANCE_ERROR` | `30` | Error below this many BLURT |
|
|
| `MORPHIT_OPS_THRESHOLD_DRAIN_AGE_WARN_SEC` | `300` (5m) | Warn when oldest pending exceeds this |
|
|
| `MORPHIT_OPS_THRESHOLD_DRAIN_AGE_ERROR_SEC` | `3600` (1h) | Error when oldest pending exceeds this |
|
|
| `MORPHIT_OPS_THRESHOLD_INDEXER_LAG_WARN_BLOCKS` | `5` | Warn when indexer is N+ blocks behind |
|
|
| `MORPHIT_OPS_THRESHOLD_INDEXER_LAG_ERROR_BLOCKS` | `30` | Error when indexer is N+ blocks behind |
|
|
| `MORPHIT_OPS_THRESHOLD_SIGNUPS_PCT_WARN` | `80` | Warn at this % of daily ceiling |
|
|
| `MORPHIT_OPS_THRESHOLD_SIGNUPS_PCT_ERROR` | `100` | Error at this % of daily ceiling |
|
|
| `MORPHIT_OPS_THRESHOLD_ABUSE_WARN` | `10` | Warn at this many flags in 24h |
|
|
| `MORPHIT_OPS_THRESHOLD_ABUSE_ERROR` | `50` | Error at this many flags in 24h |
|
|
|
|
## Subcommands
|
|
|
|
| Subcommand | What it shows |
|
|
| --------------------------------------------------- | ------------------------------------------------------------------------------------- |
|
|
| `init` | First-time setup wizard (run on a fresh install) |
|
|
| `register` | Publish operator registration on-chain (Phase D.5) |
|
|
| `status` | One-screen dashboard: indexer state, drain queue, signups today, moderation flags 24h |
|
|
| `drain-queue [--age=DUR]` | Pending relay transfers, oldest first. `--age=1h` shows entries waiting >1h |
|
|
| `signups [--since=DUR]` | Accounts created via this relay. Default window: 24h |
|
|
| `abuse [--since=DUR]` | Combined view: persistent broadcast failures + new reciprocity/related-account flags |
|
|
| `failed-broadcasts [--since=DUR]` | Relay broadcasts that errored, with error messages |
|
|
| `loyalty [--since=DUR]` | Loyalty milestone delegations triggered. Default window: 7d |
|
|
| `attestations` | Orders awaiting fee-attestation verification (BTC/XMR fee path) |
|
|
| `flags [--type=reciprocity\|related] [--since=DUR]` | Moderation flags drill-down |
|
|
|
|
### Global flags
|
|
|
|
- `--json` — emit JSON instead of human-formatted output, suitable for piping to `jq`
|
|
- `--no-color` — disable ANSI color (also honored: `NO_COLOR` env var)
|
|
- `--help`, `-h` — show usage
|
|
- `--version`, `-v` — show version
|
|
|
|
### `init`-specific flags
|
|
|
|
- `--check-only` — run the system check, print results, and exit (no prompts)
|
|
- `--out=PATH` — write `morphit.config.env` to PATH instead of the repo root
|
|
|
|
### Duration spec (`DUR`)
|
|
|
|
Number followed by unit: `s` (seconds), `m` (minutes), `h` (hours), `d` (days).
|
|
Examples: `30s`, `5m`, `24h`, `7d`. Case-insensitive on the unit;
|
|
whitespace between number and unit is tolerated (`5 m` works).
|
|
|
|
## JSON output
|
|
|
|
Every subcommand accepts `--json`. Output is a single document
|
|
to stdout, suitable for piping. Examples:
|
|
|
|
```sh
|
|
# How many failed broadcasts had errors > 5 minutes ago?
|
|
morphit-ops failed-broadcasts --json | jq '.entries | map(select(.error_count >= 5)) | length'
|
|
|
|
# Recent signups as a CSV-like list
|
|
morphit-ops signups --json | jq -r '.entries[] | [.name, .created_block_time] | @tsv'
|
|
|
|
# Alert if drain queue oldest age > 1 hour
|
|
oldest=$(morphit-ops status --json | jq '.drain_queue.oldest_age_sec // 0')
|
|
[ "$oldest" -gt 3600 ] && echo "ALERT: drain queue stuck"
|
|
```
|
|
|
|
## Troubleshooting
|
|
|
|
**"No database URL configured."**
|
|
Set `MORPHIT_OPS_DATABASE_URL` to the same connection string the
|
|
indexer uses. See your operator config or systemd unit.
|
|
|
|
**Status shows 0 signups but you know there were some.**
|
|
The CLI matches `accounts.creator = MORPHIT_OPS_RELAY_ACCOUNT`.
|
|
If your relay's account name isn't `morphit-relay`, set
|
|
`MORPHIT_OPS_RELAY_ACCOUNT` to the actual name.
|
|
|
|
**Failed-broadcasts list is empty but the relay's logs show errors.**
|
|
The CLI sees only persisted DB state. In-flight or never-queued
|
|
errors (e.g., the relay's active-key unlock failed at startup)
|
|
don't appear here. Check the relay's structured logs for those.
|
|
|
|
**Color is wrong / glyphs are blank.**
|
|
Some basic SSH sessions have spotty UTF-8 support. Pass
|
|
`--no-color` for ASCII-only output (`[OK]`, `[WARN]`, `[ERR]`).
|
|
|
|
## What's NOT in v1
|
|
|
|
The following are deliberately deferred until a follow-up phase:
|
|
|
|
- **Operations subcommands** (`drain-now`, `pause-signups`,
|
|
`set-ceiling`, `top-up-balance`). These would mutate live
|
|
state and require either a relay HTTP admin endpoint with
|
|
signed-challenge auth, or a coordination mechanism through
|
|
Postgres. v1 is read-only by intent.
|
|
- **Operator monitoring web UI.** We deliberately ship a CLI
|
|
instead — fewer attack surfaces, scriptable, fits the
|
|
operator's SSH-into-the-VPS workflow.
|
|
- **Multi-relay views.** The CLI assumes one relay account
|
|
per instance. Operators running multiple relays would
|
|
invoke the CLI multiple times with different
|
|
`MORPHIT_OPS_RELAY_ACCOUNT` values.
|
|
|
|
## Source map
|
|
|
|
```
|
|
src/
|
|
├── main.ts Entry point + tiny arg parser
|
|
├── config.ts Env vars + threshold tunables
|
|
├── db.ts pg.Pool wrapper
|
|
├── render/
|
|
│ ├── term.ts ANSI colors, glyphs, sections
|
|
│ └── json.ts --json emitter
|
|
├── lib/
|
|
│ ├── ctx.ts Shared CommandCtx type
|
|
│ └── time.ts Duration/time formatting helpers
|
|
└── commands/
|
|
├── status.ts Dashboard
|
|
├── drainQueue.ts Pending transfers
|
|
├── signups.ts Recent signups
|
|
├── abuse.ts Combined abuse signals
|
|
├── failedBroadcasts.ts Errored broadcasts
|
|
├── loyalty.ts Milestones
|
|
├── attestations.ts Pending fee attestations
|
|
└── flags.ts Moderation flags
|
|
|
|
scripts/
|
|
└── ops-cli-smoke.ts 35-scenario smoke runner
|
|
|
|
test/
|
|
└── time.test.ts Vitest mirror of the smoke (for when vitest is installed)
|
|
```
|
|
|
|
## License
|
|
|
|
AGPL-3.0-only — same as the rest of Morphit.
|