Database¶
YAAMon uses a single SQLite file (WAL mode, PRAGMA foreign_keys = ON). All schema changes are applied at startup through a versioned migration table. Each migration runs inside its own transaction together with the schema_version insert, so a failed migration is rolled back cleanly and retried on the next start. Complex migrations that cannot be expressed as a single SQL string use a Go migrationFn instead.
Tables¶
schema_version¶
Tracks applied migrations. migrate() in internal/db/db.go runs each migration whose version exceeds MAX(version).
| Column | Type | Notes |
|---|---|---|
version |
INTEGER PK | Migration number |
applied_at |
DATETIME | When it was applied |
nodes¶
One row per AllStar node managed by this instance.
| Column | Type | Notes |
|---|---|---|
id |
INTEGER PK AUTOINCREMENT | |
name |
TEXT NOT NULL | Display name |
node_number |
TEXT NOT NULL | AllStar node number |
ami_host |
TEXT | Default localhost |
ami_port |
INTEGER | Default 5038 |
ami_user |
TEXT | AMI username |
ami_pass |
TEXT | AMI password (plaintext — secured by AMI-level access control) |
enabled |
INTEGER | 1 = active, 0 = disabled |
description |
TEXT | Free-form |
location |
TEXT | Free-form |
created_at |
DATETIME |
favorites¶
Saved node numbers (quick-connect shortcuts) scoped to a parent node. position drives the user-visible sort order; sort_order is a secondary sort within groups.
| Column | Type | Notes |
|---|---|---|
id |
INTEGER PK AUTOINCREMENT | |
node_id |
INTEGER NOT NULL | FK → nodes(id) ON DELETE CASCADE |
node_number |
TEXT NOT NULL | AllStar target node |
callsign |
TEXT | |
description |
TEXT | |
location |
TEXT | |
cmd |
TEXT | AMI command to issue on connect |
sort_order |
INTEGER | Secondary sort within a group |
group_name |
TEXT | Default default |
position |
INTEGER | Primary display order |
created_at |
DATETIME |
users¶
Local user accounts. Password is a bcrypt hash; * means local login is disabled (OAuth2/proxy-created accounts).
| Column | Type | Notes |
|---|---|---|
id |
INTEGER PK AUTOINCREMENT | |
username |
TEXT UNIQUE NOT NULL | |
password |
TEXT NOT NULL | bcrypt hash or * |
permission |
TEXT NOT NULL | superuser, admin, readwrite, readonly, none |
full_name |
TEXT | Display name |
avatar_url |
TEXT | External URL or /api/users/{id}/avatar |
webauthn_id |
BLOB | 64-byte stable WebAuthn user handle |
created_at |
DATETIME |
tailscale_logins¶
Maps Tailscale user identities to local accounts. The PRIMARY KEY on login enforces that each Tailscale identity belongs to at most one account. ON DELETE CASCADE removes entries when the user is deleted.
| Column | Type | Notes |
|---|---|---|
login |
TEXT PRIMARY KEY | Full Tailscale identity (user@tailnet) |
user_id |
INTEGER NOT NULL | FK → users(id) ON DELETE CASCADE |
webauthn_credentials¶
FIDO2 passkey credentials for each user.
| Column | Type | Notes |
|---|---|---|
id |
INTEGER PK AUTOINCREMENT | |
user_id |
INTEGER NOT NULL | FK → users(id) ON DELETE CASCADE |
credential_id |
BLOB UNIQUE NOT NULL | WebAuthn credential ID |
name |
TEXT NOT NULL | User-assigned name (e.g. "MacBook Pro Touch ID") |
credential_json |
TEXT NOT NULL | Serialised webauthn.Credential |
created_at |
DATETIME | |
last_used_at |
DATETIME | Updated on each successful authentication |
webauthn_sessions¶
Single-use ceremony sessions for WebAuthn Begin/Finish flows (login and registration). Stored as Unix integer timestamps to avoid SQLite datetime string format ambiguity.
| Column | Type | Notes |
|---|---|---|
session_id |
TEXT PRIMARY KEY | Random session ID (stored in HttpOnly cookie) |
ceremony |
TEXT NOT NULL | login or registration |
user_id |
INTEGER | NULL for discoverable login |
session_json |
TEXT NOT NULL | Serialised webauthn.SessionData |
expires_at |
INTEGER NOT NULL | Unix timestamp (5-minute TTL) |
rpid |
TEXT NOT NULL | Relying Party ID at ceremony start |
origin |
TEXT NOT NULL | Origin at ceremony start |
configs¶
Key-value store for runtime settings.
| Column | Type | Notes |
|---|---|---|
key |
TEXT PRIMARY KEY | |
value |
TEXT | |
updated_at |
DATETIME |
Known config keys:
| Key | Contents |
|---|---|
session_secret |
Base64-encoded 32-byte HMAC key |
user_avatar_{id} |
Base64-encoded raw image bytes for uploaded avatars |
favicon / favicon-256.png |
Base64-encoded custom favicon images |
qrz_username |
QRZ.com account username |
qrz_password_enc |
AES-256-GCM encrypted QRZ password (key derived from session secret) |
stats_cache¶
Persists the last-known ASL stats for each node across server restarts. Rows are pruned at startup for node numbers not referenced by any node or favorite.
| Column | Type | Notes |
|---|---|---|
node_number |
TEXT PRIMARY KEY | AllStar node number |
stats_json |
TEXT NOT NULL | JSON-encoded NodeStats |
updated_at |
DATETIME | Last successful fetch time |
qrz_cache¶
Persists callsign records fetched from QRZ.com. Records are valid for 30 days.
| Column | Type | Notes |
|---|---|---|
callsign |
TEXT PRIMARY KEY | Amateur radio callsign (uppercase) |
record_json |
TEXT NOT NULL | JSON-encoded qrz.Record |
fetched_at |
DATETIME NOT NULL | When the QRZ API returned this record |
tls_certs¶
Stores a self-signed TLS certificate and private key generated at first start when tls.mode = self_signed.
| Column | Type | Notes |
|---|---|---|
id |
INTEGER PK | Always 1 |
cert_pem |
TEXT | PEM certificate |
key_pem |
TEXT | PEM private key |
generated_at |
DATETIME |
Relationships¶
nodes ──< favorites
users ──< tailscale_logins
users ──< webauthn_credentials
nodes, favorites ──> stats_cache (pruned by cross-reference)
Migration history¶
| Version | Change |
|---|---|
| 1 | Initial schema: nodes, favorites, users, configs, tls_certs |
| 2 | Add favorites.position; seed from id |
| 3 | Add nodes.description, nodes.location |
| 4 | Add users.full_name, users.avatar_url |
| 5 | Add users.tailscale_usernames (comma-separated — superseded by migration 6) |
| 6 | Create tailscale_logins join table; migrate comma-separated data; drop tailscale_usernames column |
| 7 | Add stats_cache table |
| 8 | Add qrz_cache table |
| 9 | Add users.qrz_username, users.qrz_password_enc, users.lookup_source |
| 10 | Add users.webauthn_id; create webauthn_credentials and webauthn_sessions |
| 11 | Add webauthn_sessions.rpid and webauthn_sessions.origin |