Separate participant and blacklist display toggles
Nine7 Deploy
9203c79
Separate blacklist display setting
Nine7 Deploy
608883b
Align directory participant list with blacklist
Nine7 Deploy
7080954
10 days ago
Hide successful spoiler progress while retaining errors
Nine7 Deploy
f23003d
Move administrator controls into avatar menu
Nine7 Deploy
1e81421
Hide successful backup progress after completion
Nine7 Deploy
08ccb89
Unify task progress bars and separate polling rate limits
Nine7 Deploy
9e52e10
Normalize backup starting IDs and isolate progress rate limits
Nine7 Deploy
833da43
Match spoiler controls to backup UI styling
Nine7 Deploy
a8b01d4
Add live progress, backup ranges and album spoiler options
Nine7 Deploy
8f21cfa
Revert "Handle protected channels in channel spoiler task"
Nine7 Deploy
974a76c
This reverts commit 3ff27df5b0aeb9fbb9389ad17f01a2a7ff36dcb8.
Handle protected channels in channel spoiler task
Nine7 Deploy
3ff27df
Add channel history spoiler controls
Nine7 Deploy
7d1f491
13 days ago
Promote Userbot after bot joins chats
Nine7 Deploy
a344353
Reduce synchronization debounce latency
Nine7 Deploy
19df1d7
Preserve video dimensions during Userbot edits
Nine7 Deploy
2a210c3
Preserve media types during Userbot edits
Nine7 Deploy
098e70f
Route bot edit events through Userbot media sync
Nine7 Deploy
0809c17
Refresh source media before Userbot edits
Nine7 Deploy
320603f
Use Userbot to edit synced media in place
Nine7 Deploy
557e4ca
Edit synced messages in place
Nine7 Deploy
2ce465a
14 days ago
Prioritize completed leaderboard entries
Nine7 Deploy
064fc00
15 days ago
Preserve source order across synchronized targets
Nine7 Deploy
7394c9c
Debounce album updates before syncing
Nine7 Deploy
03c2551
Handle Telethon MessageEdited message callbacks
Nine7 Deploy
4cad976
Survive Neon dropping idle connections without losing writes
Nine7 Deploy
c8943aa
Neon closes idle connections, which surfaced as "SSL connection has been
closed unexpectedly" and silently discarded that save. A worse variant
existed: if an update committed but the response was lost, the next
compare-and-swap saw a revision mismatch and permanently paused all writes
as a bogus conflict.
- Retry a failed save once on a fresh connection when the failure is at the
connection layer; the transaction has rolled back so replay is safe
- When the revision does not match, compare the stored payload with what we
tried to write and treat identical content as success instead of a
conflict, so a lost response cannot lock writing
- Keep genuine conflicts blocked and log when one is detected
- Enable TCP keepalives so idle connections are less likely to be reaped
Default legacy merge to data only, without importing old automation
Nine7 Deploy
585988b
Merging everything brought old sync groups, stats tasks, directory tasks,
member monitors and migration rules back to life the moment the previous
data became reachable, which is not always wanted.
- `merge` (default) now combines data only: users, address books, member
ledgers, message maps, admin list and caches. Old automation is skipped
- Add `merge-all` for the previous behaviour when old tasks should resume
- Strip task fields from users that exist only in the old payload, so an
old-only account cannot reintroduce automation
- Normalise the merged user shape so merging twice is fully idempotent and
adds no stray keys
Merge legacy data instead of skipping or overwriting it
Nine7 Deploy
9882d42
Previously the only outcomes were skip (new data kept, old data stranded)
or a full replace (new data destroyed). Neither gives back the previous
configuration while keeping work done in the meantime.
- Add LEGACY_MIGRATION_MODE with merge (default), replace and skip; the
existing LEGACY_MIGRATION_FORCE now means replace
- Merge is a union: new values win on the same key, old data fills gaps,
and merging twice does not duplicate entries. Fields absent from the old
payload no longer wipe newer keys, which the replace path did
- Cover users, groups, stats and dir tasks, member monitors, address book,
msg_map, ch_members, admin_ids, events, backup_log and migration data
- Snapshot the pre-merge state to R2 (backups/nine7/premerge_*.json) so a
bad merge can be rolled back
- Track migration completion in a legacy_done column so the background
retry stops after success and survives restarts
- Throttle retry failure logging and attempt once immediately at startup
Add LEGACY_MIGRATION_FORCE to make old-data recovery deterministic
Nine7 Deploy
f0d8241
If business data is created before the old storage becomes reachable the
automatic migration is skipped to protect newer work, which would leave the
previous data stranded. Allow an explicit opt-in override so recovery does
not depend on the operator remembering not to touch the bot.
Make legacy data recovery survive restarts and stub users
Nine7 Deploy
ee6778a
The previous retry gate treated any entry in DATA["users"] as real data,
but /start and the Mini App auth path create an empty user stub, so simply
opening the console permanently disabled the background migration of old
WebDAV data. The retry was also started from a source flag that a normal
save would eventually rewrite.
- Judge emptiness by substantive business data (tasks, groups, address
book, monitors, msg_map, admin_ids, members, migration data), ignoring
auto-generated stubs such as users, profile, events and avatar caches
- Start the retry thread whenever no substantive data exists, independent
of the source column, so it survives restarts
- Stop the retry once a migration succeeds and log the skip only once
- Record the state origin on every save so it stays accurate
- Document LEGACY_RETRY_INTERVAL and the R2 upload recovery path
Fix Neon bootstrap being skipped when legacy storage is unreachable
Nine7 Deploy
12f5b7b
The legacy JSON read (WebDAV/R2) ran inside the same try block as Neon
initialisation, so a connection error from an unreachable WebDAV host was
caught by the outer handler and Neon was never bootstrapped. The app then
ran with empty state, and saving failed because the row did not exist.
- Isolate legacy reads so a failure can never abort Neon initialisation
- Bootstrap an empty Neon state when no legacy data is reachable
- Make saves upsert: insert when the row is missing, CAS on revision when
it exists, so a missing row is no longer misreported as a conflict
- Record the row origin in a new `source` column
- Retry legacy migration in the background while the state is still empty,
so data is recovered once WebDAV becomes reachable again
- Only let the retry overwrite a state that has no real business data yet
Add Neon PostgreSQL + R2 storage with data-loss safeguards
Nine7 Deploy
20d4d7e
- Store app state in Neon PostgreSQL jsonb row, keeping R2/WebDAV JSON as legacy fallback and one-time migration source
- Guard writes with revision check; pause writes on conflict instead of overwriting newer data
- Write timestamped disaster-recovery snapshots to R2 on an interval
- Sort address book and channel pickers by name in webapp and Telegram UI
- Make stats blacklist matching case-insensitive and NFKC-normalized
- Sync media edits via Telethon MessageEdited: recopy source message and replace target when media or type changes
28 days ago
Revert stats lists to one name per line and tighten separator spacing
lin7zhi
8ce753c
Secure event stream, batch stats saves, align list columns
lin7zhi
00a8827
Add message list display switch with 20 names per message
lin7zhi
4fe097b
Return blacklist extraction results directly to console
lin7zhi
84f067b
Parse ranked rows when extracting names and harden console requests
lin7zhi
9631153
Add clickable stats toggle and fix extract from other channels
lin7zhi
49c5e02
Add customizable participant list title
lin7zhi
1bb0121
Cap stats message lists by top_n and show real totals
lin7zhi
3b08f4b
Show directory participants in stats message and list app
lin7zhi
1b56ca2
Rework console navigation and match directory names without hash
lin7zhi
cfdcb5c
Normalize whitespace in member ledger search
lin7zhi
64e82f3
Return member list from ledger API and add list view tabs
lin7zhi
b2e184e
Fix home invite retries, show full blacklist in list app, stabilize ledger search