Files
archive-clients/docs/telegram-ux.md
T

7.0 KiB

Telegram UX

Archive Control adds a separate handler/module to the existing bot. Existing commands and conversations retain their current behavior.

Authorization and shared state

The handler accepts private-chat users through the existing @username allowlist for compatibility. A configured numeric Telegram user ID may pin an entry; when pinned, both the ID and current allowlist rule must match. This mitigates username reassignment while permitting a staged migration.

Jobs, placements, events, queues, and routes are shared administrative state and store no initiating-user identity. UI session state records only what is needed to resume the conversation/view and expires after 24 hours by default.

Entry point and navigation

The existing “Archive/Unarchive Resources” entry opens one message:

What do you want to do?

[ Archive ] [ Unarchive ]
[ Evict Cache ] [ Job Status ]

All subsequent pages edit this message. Cancel closes the active selection flow. Back returns one level while retaining validated filters/selections. Callback payloads contain opaque session/action IDs, not resource names or paths, and are validated against persisted session revision and expiry.

Archive and unarchive flow

1. Select source resource

Control queries relevant online nodes on demand. It groups identical resource and selection replicas into one display choice while showing distinct selections separately. The list is stable-sorted and paged:

Which cached resource do you want to archive? (page 1/3)
filters: `documentary`, `2025`

1. `10.0 GB` Resource A — cache-1
2. `840 MB` Resource B — cache-2

[ 1 ] [ 2 ]
[ Prev ] [ Next ]
[ Remove filters ] [ Cancel ]

Size is selected-complete logical content, not total torrent size. New messages add literal, case-insensitive filters and narrow the current results; Remove filters resets the chain. If no item remains, the message explains whether no source is online, no selected-complete data exists, or filters eliminated all results.

2. Select source replica and target

If multiple identical-selection replicas exist, control may choose a healthy source automatically using deterministic availability/route/free-space rules; otherwise it lists the source replicas. One eligible target is selected automatically; multiple targets are paged. Offline targets are not offered.

A resource already on a target is still eligible when the requested selection has an unverified delta. The UI says that it will extend an existing placement.

3. Confirm or choose one entry

Before showing confirmation, control obtains fresh full trees from source and target and calculates the transfer delta.

Archive Resource A from cache-1 to archive-2?
Requested: 7 files, 10.0 GB
Already verified there: 2 files, 3.1 GB
Will transfer: 5 files, 6.9 GB

[ Confirm ]
[ Choose one entry… ] [ Cancel ]

Choose one entry opens a paged/filterable tree. Only source-selected-complete files/directories are enabled. Selecting a directory expands it to descendant file indices, returns to a freshly recomputed confirmation, and clearly states the chosen subtree. The protocol supports multiple entries from v1, but the initial UI exposes one.

Confirmation uses a persisted, single-use nonce bound to session revision, operation, resource, source, target, selection, fingerprints, and placement generation. Double taps or stale callbacks cannot create a second job.

Evict Cache flow

The first page lists current cache placements. Selecting one triggers fresh queries to the cache and relevant online archive nodes. Each row/confirmation shows coverage:

  • enabled when the union of verified archives covers every selected cache file;
  • disabled with missing file count/size and unavailable archive explanation otherwise.

There is no override button. Confirmation creates a durable three-step eviction job; it never clears an archive placement or a transfer history row.

Job Status

Status pages show live and retained jobs with operation, resource, endpoints, state, current-step and overall percentages, bytes/s where meaningful, and failure reason. Routine edits are coalesced to one per five seconds by default. Step changes, stall transitions, failures, commit, cleanup-required, and terminal states edit immediately subject to Telegram rate-limit backoff.

State symbols:

Symbol Meaning
🟡 queued/not started
🔵 active, waiting, or stalled
🟠 committed but cleanup required
🟢 succeeded
🔴 failed or cancelled

Transfer jobs display five numbered steps: Source Stage/HardLink, Syncthing, Target Merge/Copy, QB Verification, and Staging Cleanup. Route setup and preflight are named, unnumbered pre-steps. Eviction displays Verify Archive Coverage, QB Remove Entry, and Safe File Unlink.

A stalled job keeps its last overall percentage:

🔵 Archive: Resource A — cache-1 → archive-2
[2/5 Syncthing: 63.42%, overall 32.68%, stalled, last progress 38m ago]
Waiting indefinitely; retry occurs when progress/service connectivity returns.

Failure messages include stable phase and clear reason, while hiding secrets and host-only paths.

Clear and remove behavior

Clear Finished hides only green successful jobs and leaves a 30-day default tombstone. Orange Cleanup Required is not clearable as finished.

Remove One first replaces buttons with current-page job numbers and Cancel. A successful green row hides immediately. A queued job confirmation deletes only its queue record/reservation. An active, failed-with-residue, or cancelling job requires a second confirmation and begins/continues compensation; its row remains until safe cleanup is known. A committed job can only retry staging cleanup. No history action deletes a cache placement; that is exclusively Evict Cache.

Restart and rate-limit behavior

Sessions, pages, filters, chosen entries, confirmation bindings, and live status views are persisted. On bot restart, active status messages resume updates when the stored chat/message remains editable; otherwise users can reopen Job Status without losing job state. “message is not modified” is treated as success. Telegram retry-after values pause/coalesce edits without affecting orchestration.

Interactive test entry

An opt-in Archive Control (Test) entry reuses this same handler with an independent callback namespace and SQLite database. Its scripted backend provides comprehensive, empty, and slow-route scenarios without contacting control/client daemons, qBittorrent, or Syncthing. The production entry, callback namespace, database, jobs, placements, and other bot features are unchanged.

The test entry exposes administrator-only /actest controls to reset a scenario, move a synthetic job through displayed states, fail the next selected backend call, complete a slow route, inspect recent trace events, or export the complete JSONL trace. The trace contains callback and filter inputs, session state transitions, exact message/keyboard renders, backend results/errors, and job transitions, so a UI report can be reproduced without live storage nodes.