Skip to content

User Management

Identify User

Decode the JWT stored by the frontend to retrieve the user UUID:

const token = localStorage.getItem('secure_token');
const payload = JSON.parse(atob(token.split('.')[1]));
console.log(payload.user_id);

Alternatively read current_user_id from Local Storage.

Allowlist UUID

Provide the UUID via environment variable and restart the backend:

ADMIN_USER_IDS=1c0fe4f0-9d41-41cc-8806-b5e8f6a2ad71

Comma-separate multiple bootstrap admins.

Persist Role

Promote permanently with SQL or the admin API:

UPDATE users
SET is_admin = true
WHERE id = '1c0fe4f0-9d41-41cc-8806-b5e8f6a2ad71';
  • Enable UI: set VITE_ENABLE_ADMIN_PANEL=true before building the frontend.
  • Actions map directly to backend handlers (handlers/account.go, handlers/settings.go):
    • Toggle is_admin, assign RBAC roles (moderator, auditor).
    • Unlock accounts (failed_attempts, locked_until).
    • Adjust registration (app_settings.registration_enabled).
    • Inspect login telemetry and MFA adoption.

JWT + is_admin column gate every request—front-end toggles do not bypass auth.

Account Inventory

SELECT
id,
email,
COALESCE(is_admin, false) AS is_admin,
mfa_enabled,
failed_attempts,
locked_until,
created_at,
last_login
FROM users
ORDER BY created_at DESC;

Admin Audit

SELECT id, email, created_at, last_login
FROM users
WHERE is_admin = true;

Lockout Detection

SELECT id, email, failed_attempts, locked_until
FROM users
WHERE failed_attempts > 5;

Reset failed attempts:

UPDATE users
SET failed_attempts = 0,
locked_until = NULL
WHERE id = 'user-uuid';

MFA maintenance:

UPDATE users
SET mfa_enabled = true
WHERE id = 'user-uuid';
UPDATE users
SET mfa_enabled = false,
mfa_secret_encrypted = NULL
WHERE id = 'user-uuid';

Storage telemetry:

SELECT
id,
storage_used,
storage_limit,
ROUND(storage_used::numeric / storage_limit * 100, 1) AS usage_percent
FROM users
WHERE storage_limit > 0
ORDER BY usage_percent DESC;

Public registration is disabled by default. Enable it deliberately:

ENABLE_REGISTRATION=true

The admin panel writes the same value into app_settings.registration_enabled. Bootstrapping reads from the environment only when the setting is missing.

Encrypted Payloads

Admins never view decrypted note content—only metadata and audit logs.

Reset Workflow

Use the standard password reset flow to preserve encryption keys; avoid editing hashed columns manually.

Backups

Snapshot before destructive updates:

pg_dump -h localhost -U postgres -d notes -t users > users_backup.sql
  • Demote admin: UPDATE users SET is_admin = false WHERE id = 'user-uuid';
  • Purge trashed notes after retention: DELETE FROM notes WHERE deleted_at IS NOT NULL AND deleted_at < NOW() - INTERVAL '30 days';
  • Audit MFA adoption: SELECT COUNT(*) FILTER (WHERE mfa_enabled) * 100.0 / COUNT(*) FROM users WHERE deleted_at IS NULL;