45 Commits
Author SHA1 Message Date
kazeyukiro a690ecd3f4 fix(auth,ui): reduce SQLite busy 503; TCP/UDP dual connection chart
Auth user lookup retries briefly on DB lock; SQLite opens with
busy_timeout and a single connection. Dashboard tracks TCP/UDP series
and draws them as solid/dashed lines like traffic rates.
2026-10-02 04:52:22 +00:00
kazeyukiro fec9733baa docs: remove third-party panel name references from copy
Drop  and external m-ui product names from docs, UI strings,
and code comments. Keep functional descriptions of server egress and WARP.
docs: remove third-party panel name references from copy
Drop  and external m-ui product names from docs, UI strings,
and code comments. Keep functional descriptions of server egress and WARP.
docs: remove third-party panel name references from copy
Drop  and external m-ui product names from docs, UI strings,
and code comments. Keep functional descriptions of server egress and WARP.
docs: remove third-party panel name references from copy
Drop  and external m-ui product names from docs, UI strings,
and code comments. Keep functional descriptions of server egress and WARP.
docs: remove third-party panel name references from copy
Drop  and external m-ui product names from docs, UI strings,
and code comments. Keep functional descriptions of server egress and WARP.
docs: remove third-party panel name references from copy
Drop  and external m-ui product names from docs, UI strings,
and code comments. Keep functional descriptions of server egress and WARP.
docs: remove third-party panel name references from copy
Drop  and external m-ui product names from docs, UI strings,
and code comments. Keep functional descriptions of server egress and WARP.
docs: remove third-party panel name references from copy
Drop  and external m-ui product names from docs, UI strings,
and code comments. Keep functional descriptions of server egress and WARP.
docs: remove third-party panel name references from copy
Drop  and external m-ui product names from docs, UI strings,
and code comments. Keep functional descriptions of server egress and WARP.
docs: remove third-party panel name references from copy
Drop  and external m-ui product names from docs, UI strings,
and code comments. Keep functional descriptions of server egress and WARP.
docs: remove third-party panel name references from copy
Drop  and external m-ui product names from docs, UI strings,
and code comments. Keep functional descriptions of server egress and WARP.
docs: remove third-party panel name references from copy
Drop  and external m-ui product names from docs, UI strings,
and code comments. Keep functional descriptions of server egress and WARP.
2026-09-29 15:51:57 +00:00
kazeyukiro c79e0b7a17 feat(auth): optional GitHub OAuth for panel login
Store client id/secret and allowed GitHub usernames in settings.
OAuth start/callback issues the same session JWT as password login;
first allowed login can bind to matching or sole admin account.
Login page shows Continue with GitHub when enabled.
feat(auth): optional GitHub OAuth for panel login
Store client id/secret and allowed GitHub usernames in settings.
OAuth start/callback issues the same session JWT as password login;
first allowed login can bind to matching or sole admin account.
Login page shows Continue with GitHub when enabled.
feat(auth): optional GitHub OAuth for panel login
Store client id/secret and allowed GitHub usernames in settings.
OAuth start/callback issues the same session JWT as password login;
first allowed login can bind to matching or sole admin account.
Login page shows Continue with GitHub when enabled.
feat(auth): optional GitHub OAuth for panel login
Store client id/secret and allowed GitHub usernames in settings.
OAuth start/callback issues the same session JWT as password login;
first allowed login can bind to matching or sole admin account.
Login page shows Continue with GitHub when enabled.
feat(auth): optional GitHub OAuth for panel login
Store client id/secret and allowed GitHub usernames in settings.
OAuth start/callback issues the same session JWT as password login;
first allowed login can bind to matching or sole admin account.
Login page shows Continue with GitHub when enabled.
feat(auth): optional GitHub OAuth for panel login
Store client id/secret and allowed GitHub usernames in settings.
OAuth start/callback issues the same session JWT as password login;
first allowed login can bind to matching or sole admin account.
Login page shows Continue with GitHub when enabled.
feat(auth): optional GitHub OAuth for panel login
Store client id/secret and allowed GitHub usernames in settings.
OAuth start/callback issues the same session JWT as password login;
first allowed login can bind to matching or sole admin account.
Login page shows Continue with GitHub when enabled.
feat(auth): optional GitHub OAuth for panel login
Store client id/secret and allowed GitHub usernames in settings.
OAuth start/callback issues the same session JWT as password login;
first allowed login can bind to matching or sole admin account.
Login page shows Continue with GitHub when enabled.
feat(auth): optional GitHub OAuth for panel login
Store client id/secret and allowed GitHub usernames in settings.
OAuth start/callback issues the same session JWT as password login;
first allowed login can bind to matching or sole admin account.
Login page shows Continue with GitHub when enabled.
feat(auth): optional GitHub OAuth for panel login
Store client id/secret and allowed GitHub usernames in settings.
OAuth start/callback issues the same session JWT as password login;
first allowed login can bind to matching or sole admin account.
Login page shows Continue with GitHub when enabled.
feat(auth): optional GitHub OAuth for panel login
Store client id/secret and allowed GitHub usernames in settings.
OAuth start/callback issues the same session JWT as password login;
first allowed login can bind to matching or sole admin account.
Login page shows Continue with GitHub when enabled.
feat(auth): optional GitHub OAuth for panel login
Store client id/secret and allowed GitHub usernames in settings.
OAuth start/callback issues the same session JWT as password login;
first allowed login can bind to matching or sole admin account.
Login page shows Continue with GitHub when enabled.
2026-09-26 01:05:10 +00:00
kazeyukiro 7e8094938c fix(ci): remove unused log import in database.go 2026-09-21 00:18:00 +08:00
kazeyukiro fee8f6535d fix(ci): gofmt database.go and user/api.go 2026-09-21 00:10:00 +08:00
kazeyukiro 64609d43d1 chore: delete HWID package and model 2026-09-20 23:50:21 +08:00
kazeyukiro 79e6c778a1 chore: remove HWID feature (subscription device binding) 2026-09-21 00:00:00 +08:00
kazeyukiro 37a5fa0284 feat(traffic): per-node usage + traffic multiplier billing
- Listener.traffic_multiplier (default 1): billable = raw × multiplier
- user_node_traffics: raw per user per node; user quota uses billable totals
- Collector attributes deltas by inbound name; resets clear node rows
- API GET /users/:id/node-traffic
- UI: node multiplier on Listeners; Users node-traffic modal (desktop+mobile)
feat(traffic): per-node usage + traffic multiplier billing
- Listener.traffic_multiplier (default 1): billable = raw × multiplier
- user_node_traffics: raw per user per node; user quota uses billable totals
- Collector attributes deltas by inbound name; resets clear node rows
- API GET /users/:id/node-traffic
- UI: node multiplier on Listeners; Users node-traffic modal (desktop+mobile)
feat(traffic): per-node usage + traffic multiplier billing
- Listener.traffic_multiplier (default 1): billable = raw × multiplier
- user_node_traffics: raw per user per node; user quota uses billable totals
- Collector attributes deltas by inbound name; resets clear node rows
- API GET /users/:id/node-traffic
- UI: node multiplier on Listeners; Users node-traffic modal (desktop+mobile)
feat(traffic): per-node usage + traffic multiplier billing
- Listener.traffic_multiplier (default 1): billable = raw × multiplier
- user_node_traffics: raw per user per node; user quota uses billable totals
- Collector attributes deltas by inbound name; resets clear node rows
- API GET /users/:id/node-traffic
- UI: node multiplier on Listeners; Users node-traffic modal (desktop+mobile)
feat(traffic): per-node usage + traffic multiplier billing
- Listener.traffic_multiplier (default 1): billable = raw × multiplier
- user_node_traffics: raw per user per node; user quota uses billable totals
- Collector attributes deltas by inbound name; resets clear node rows
- API GET /users/:id/node-traffic
- UI: node multiplier on Listeners; Users node-traffic modal (desktop+mobile)
feat(traffic): per-node usage + traffic multiplier billing
- Listener.traffic_multiplier (default 1): billable = raw × multiplier
- user_node_traffics: raw per user per node; user quota uses billable totals
- Collector attributes deltas by inbound name; resets clear node rows
- API GET /users/:id/node-traffic
- UI: node multiplier on Listeners; Users node-traffic modal (desktop+mobile)
feat(traffic): per-node usage + traffic multiplier billing
- Listener.traffic_multiplier (default 1): billable = raw × multiplier
- user_node_traffics: raw per user per node; user quota uses billable totals
- Collector attributes deltas by inbound name; resets clear node rows
- API GET /users/:id/node-traffic
- UI: node multiplier on Listeners; Users node-traffic modal (desktop+mobile)
feat(traffic): per-node usage + traffic multiplier billing
- Listener.traffic_multiplier (default 1): billable = raw × multiplier
- user_node_traffics: raw per user per node; user quota uses billable totals
- Collector attributes deltas by inbound name; resets clear node rows
- API GET /users/:id/node-traffic
- UI: node multiplier on Listeners; Users node-traffic modal (desktop+mobile)
feat(traffic): per-node usage + traffic multiplier billing
- Listener.traffic_multiplier (default 1): billable = raw × multiplier
- user_node_traffics: raw per user per node; user quota uses billable totals
- Collector attributes deltas by inbound name; resets clear node rows
- API GET /users/:id/node-traffic
- UI: node multiplier on Listeners; Users node-traffic modal (desktop+mobile)
feat(traffic): per-node usage + traffic multiplier billing
- Listener.traffic_multiplier (default 1): billable = raw × multiplier
- user_node_traffics: raw per user per node; user quota uses billable totals
- Collector attributes deltas by inbound name; resets clear node rows
- API GET /users/:id/node-traffic
- UI: node multiplier on Listeners; Users node-traffic modal (desktop+mobile)
feat(traffic): per-node usage + traffic multiplier billing
- Listener.traffic_multiplier (default 1): billable = raw × multiplier
- user_node_traffics: raw per user per node; user quota uses billable totals
- Collector attributes deltas by inbound name; resets clear node rows
- API GET /users/:id/node-traffic
- UI: node multiplier on Listeners; Users node-traffic modal (desktop+mobile)
feat(traffic): per-node usage + traffic multiplier billing
- Listener.traffic_multiplier (default 1): billable = raw × multiplier
- user_node_traffics: raw per user per node; user quota uses billable totals
- Collector attributes deltas by inbound name; resets clear node rows
- API GET /users/:id/node-traffic
- UI: node multiplier on Listeners; Users node-traffic modal (desktop+mobile)
2026-09-20 23:50:00 +08:00
kazeyukiro 277e65c09a fix(db): drop legacy HWID index before AutoMigrate
SQLite index names are global; uidx_user_hwid left by hw_id_devices
blocked creating hwid_devices and rolled back panel updates.
prepareHWIDDeviceSchema now runs before AutoMigrate and drops the
conflicting index plus legacy/broken HWID tables.
fix(db): drop legacy HWID index before AutoMigrate
SQLite index names are global; uidx_user_hwid left by hw_id_devices
blocked creating hwid_devices and rolled back panel updates.
prepareHWIDDeviceSchema now runs before AutoMigrate and drops the
conflicting index plus legacy/broken HWID tables.
fix(db): drop legacy HWID index before AutoMigrate
SQLite index names are global; uidx_user_hwid left by hw_id_devices
blocked creating hwid_devices and rolled back panel updates.
prepareHWIDDeviceSchema now runs before AutoMigrate and drops the
conflicting index plus legacy/broken HWID tables.
fix(db): drop legacy HWID index before AutoMigrate
SQLite index names are global; uidx_user_hwid left by hw_id_devices
blocked creating hwid_devices and rolled back panel updates.
prepareHWIDDeviceSchema now runs before AutoMigrate and drops the
conflicting index plus legacy/broken HWID tables.
fix(db): drop legacy HWID index before AutoMigrate
SQLite index names are global; uidx_user_hwid left by hw_id_devices
blocked creating hwid_devices and rolled back panel updates.
prepareHWIDDeviceSchema now runs before AutoMigrate and drops the
conflicting index plus legacy/broken HWID tables.
fix(db): drop legacy HWID index before AutoMigrate
SQLite index names are global; uidx_user_hwid left by hw_id_devices
blocked creating hwid_devices and rolled back panel updates.
prepareHWIDDeviceSchema now runs before AutoMigrate and drops the
conflicting index plus legacy/broken HWID tables.
fix(db): drop legacy HWID index before AutoMigrate
SQLite index names are global; uidx_user_hwid left by hw_id_devices
blocked creating hwid_devices and rolled back panel updates.
prepareHWIDDeviceSchema now runs before AutoMigrate and drops the
conflicting index plus legacy/broken HWID tables.
fix(db): drop legacy HWID index before AutoMigrate
SQLite index names are global; uidx_user_hwid left by hw_id_devices
blocked creating hwid_devices and rolled back panel updates.
prepareHWIDDeviceSchema now runs before AutoMigrate and drops the
conflicting index plus legacy/broken HWID tables.
fix(db): drop legacy HWID index before AutoMigrate
SQLite index names are global; uidx_user_hwid left by hw_id_devices
blocked creating hwid_devices and rolled back panel updates.
prepareHWIDDeviceSchema now runs before AutoMigrate and drops the
conflicting index plus legacy/broken HWID tables.
fix(db): drop legacy HWID index before AutoMigrate
SQLite index names are global; uidx_user_hwid left by hw_id_devices
blocked creating hwid_devices and rolled back panel updates.
prepareHWIDDeviceSchema now runs before AutoMigrate and drops the
conflicting index plus legacy/broken HWID tables.
fix(db): drop legacy HWID index before AutoMigrate
SQLite index names are global; uidx_user_hwid left by hw_id_devices
blocked creating hwid_devices and rolled back panel updates.
prepareHWIDDeviceSchema now runs before AutoMigrate and drops the
conflicting index plus legacy/broken HWID tables.
fix(db): drop legacy HWID index before AutoMigrate
SQLite index names are global; uidx_user_hwid left by hw_id_devices
blocked creating hwid_devices and rolled back panel updates.
prepareHWIDDeviceSchema now runs before AutoMigrate and drops the
conflicting index plus legacy/broken HWID tables.
2026-09-20 23:35:00 +08:00
kazeyukiro 00cc0b9f4b fix(db): HWID table column hwid (GORM acronym mapping)
GORM snake_case mapped HWID -> h_w_i_d and table -> hw_id_devices, so
SELECT ... hwid failed with "no such column: hwid". Explicit column tags,
table name hwid_devices, and startup repair that drops broken tables.
fix(db): HWID table column hwid (GORM acronym mapping)
GORM snake_case mapped HWID -> h_w_i_d and table -> hw_id_devices, so
SELECT ... hwid failed with "no such column: hwid". Explicit column tags,
table name hwid_devices, and startup repair that drops broken tables.
fix(db): HWID table column hwid (GORM acronym mapping)
GORM snake_case mapped HWID -> h_w_i_d and table -> hw_id_devices, so
SELECT ... hwid failed with "no such column: hwid". Explicit column tags,
table name hwid_devices, and startup repair that drops broken tables.
fix(db): HWID table column hwid (GORM acronym mapping)
GORM snake_case mapped HWID -> h_w_i_d and table -> hw_id_devices, so
SELECT ... hwid failed with "no such column: hwid". Explicit column tags,
table name hwid_devices, and startup repair that drops broken tables.
fix(db): HWID table column hwid (GORM acronym mapping)
GORM snake_case mapped HWID -> h_w_i_d and table -> hw_id_devices, so
SELECT ... hwid failed with "no such column: hwid". Explicit column tags,
table name hwid_devices, and startup repair that drops broken tables.
fix(db): HWID table column hwid (GORM acronym mapping)
GORM snake_case mapped HWID -> h_w_i_d and table -> hw_id_devices, so
SELECT ... hwid failed with "no such column: hwid". Explicit column tags,
table name hwid_devices, and startup repair that drops broken tables.
fix(db): HWID table column hwid (GORM acronym mapping)
GORM snake_case mapped HWID -> h_w_i_d and table -> hw_id_devices, so
SELECT ... hwid failed with "no such column: hwid". Explicit column tags,
table name hwid_devices, and startup repair that drops broken tables.
fix(db): HWID table column hwid (GORM acronym mapping)
GORM snake_case mapped HWID -> h_w_i_d and table -> hw_id_devices, so
SELECT ... hwid failed with "no such column: hwid". Explicit column tags,
table name hwid_devices, and startup repair that drops broken tables.
fix(db): HWID table column hwid (GORM acronym mapping)
GORM snake_case mapped HWID -> h_w_i_d and table -> hw_id_devices, so
SELECT ... hwid failed with "no such column: hwid". Explicit column tags,
table name hwid_devices, and startup repair that drops broken tables.
fix(db): HWID table column hwid (GORM acronym mapping)
GORM snake_case mapped HWID -> h_w_i_d and table -> hw_id_devices, so
SELECT ... hwid failed with "no such column: hwid". Explicit column tags,
table name hwid_devices, and startup repair that drops broken tables.
fix(db): HWID table column hwid (GORM acronym mapping)
GORM snake_case mapped HWID -> h_w_i_d and table -> hw_id_devices, so
SELECT ... hwid failed with "no such column: hwid". Explicit column tags,
table name hwid_devices, and startup repair that drops broken tables.
fix(db): HWID table column hwid (GORM acronym mapping)
GORM snake_case mapped HWID -> h_w_i_d and table -> hw_id_devices, so
SELECT ... hwid failed with "no such column: hwid". Explicit column tags,
table name hwid_devices, and startup repair that drops broken tables.
2026-09-20 23:15:00 +08:00
kazeyukiro 9cf0df62d3 feat: 5s IP-limit poll; per-user subscription pull limit (24h)
- traffic.DefaultInterval 10s → 5s for faster concurrent IP enforcement
- sub_pull_limit: max successful sub fetches per rolling 24h (0=unlimited)
- Users form + i18n; 429 when limit reached
feat: 5s IP-limit poll; per-user subscription pull limit (24h)
- traffic.DefaultInterval 10s → 5s for faster concurrent IP enforcement
- sub_pull_limit: max successful sub fetches per rolling 24h (0=unlimited)
- Users form + i18n; 429 when limit reached
feat: 5s IP-limit poll; per-user subscription pull limit (24h)
- traffic.DefaultInterval 10s → 5s for faster concurrent IP enforcement
- sub_pull_limit: max successful sub fetches per rolling 24h (0=unlimited)
- Users form + i18n; 429 when limit reached
feat: 5s IP-limit poll; per-user subscription pull limit (24h)
- traffic.DefaultInterval 10s → 5s for faster concurrent IP enforcement
- sub_pull_limit: max successful sub fetches per rolling 24h (0=unlimited)
- Users form + i18n; 429 when limit reached
feat: 5s IP-limit poll; per-user subscription pull limit (24h)
- traffic.DefaultInterval 10s → 5s for faster concurrent IP enforcement
- sub_pull_limit: max successful sub fetches per rolling 24h (0=unlimited)
- Users form + i18n; 429 when limit reached
feat: 5s IP-limit poll; per-user subscription pull limit (24h)
- traffic.DefaultInterval 10s → 5s for faster concurrent IP enforcement
- sub_pull_limit: max successful sub fetches per rolling 24h (0=unlimited)
- Users form + i18n; 429 when limit reached
feat: 5s IP-limit poll; per-user subscription pull limit (24h)
- traffic.DefaultInterval 10s → 5s for faster concurrent IP enforcement
- sub_pull_limit: max successful sub fetches per rolling 24h (0=unlimited)
- Users form + i18n; 429 when limit reached
feat: 5s IP-limit poll; per-user subscription pull limit (24h)
- traffic.DefaultInterval 10s → 5s for faster concurrent IP enforcement
- sub_pull_limit: max successful sub fetches per rolling 24h (0=unlimited)
- Users form + i18n; 429 when limit reached
feat: 5s IP-limit poll; per-user subscription pull limit (24h)
- traffic.DefaultInterval 10s → 5s for faster concurrent IP enforcement
- sub_pull_limit: max successful sub fetches per rolling 24h (0=unlimited)
- Users form + i18n; 429 when limit reached
feat: 5s IP-limit poll; per-user subscription pull limit (24h)
- traffic.DefaultInterval 10s → 5s for faster concurrent IP enforcement
- sub_pull_limit: max successful sub fetches per rolling 24h (0=unlimited)
- Users form + i18n; 429 when limit reached
feat: 5s IP-limit poll; per-user subscription pull limit (24h)
- traffic.DefaultInterval 10s → 5s for faster concurrent IP enforcement
- sub_pull_limit: max successful sub fetches per rolling 24h (0=unlimited)
- Users form + i18n; 429 when limit reached
feat: 5s IP-limit poll; per-user subscription pull limit (24h)
- traffic.DefaultInterval 10s → 5s for faster concurrent IP enforcement
- sub_pull_limit: max successful sub fetches per rolling 24h (0=unlimited)
- Users form + i18n; 429 when limit reached
2026-09-20 00:55:00 +08:00
kazeyukiro 23faed3ad9 fix(hwid): enforce limit properly; accept real client device ids
- When hwid_limit>0, require valid x-hwid (deny bare clients with 403)
- Relax pattern (UUID/base64/8-128 chars); expand column to 128
- Query ?hwid= fallback; unique-race refresh; surface enforce errors
fix(hwid): enforce limit properly; accept real client device ids
- When hwid_limit>0, require valid x-hwid (deny bare clients with 403)
- Relax pattern (UUID/base64/8-128 chars); expand column to 128
- Query ?hwid= fallback; unique-race refresh; surface enforce errors
fix(hwid): enforce limit properly; accept real client device ids
- When hwid_limit>0, require valid x-hwid (deny bare clients with 403)
- Relax pattern (UUID/base64/8-128 chars); expand column to 128
- Query ?hwid= fallback; unique-race refresh; surface enforce errors
fix(hwid): enforce limit properly; accept real client device ids
- When hwid_limit>0, require valid x-hwid (deny bare clients with 403)
- Relax pattern (UUID/base64/8-128 chars); expand column to 128
- Query ?hwid= fallback; unique-race refresh; surface enforce errors
fix(hwid): enforce limit properly; accept real client device ids
- When hwid_limit>0, require valid x-hwid (deny bare clients with 403)
- Relax pattern (UUID/base64/8-128 chars); expand column to 128
- Query ?hwid= fallback; unique-race refresh; surface enforce errors
fix(hwid): enforce limit properly; accept real client device ids
- When hwid_limit>0, require valid x-hwid (deny bare clients with 403)
- Relax pattern (UUID/base64/8-128 chars); expand column to 128
- Query ?hwid= fallback; unique-race refresh; surface enforce errors
fix(hwid): enforce limit properly; accept real client device ids
- When hwid_limit>0, require valid x-hwid (deny bare clients with 403)
- Relax pattern (UUID/base64/8-128 chars); expand column to 128
- Query ?hwid= fallback; unique-race refresh; surface enforce errors
fix(hwid): enforce limit properly; accept real client device ids
- When hwid_limit>0, require valid x-hwid (deny bare clients with 403)
- Relax pattern (UUID/base64/8-128 chars); expand column to 128
- Query ?hwid= fallback; unique-race refresh; surface enforce errors
fix(hwid): enforce limit properly; accept real client device ids
- When hwid_limit>0, require valid x-hwid (deny bare clients with 403)
- Relax pattern (UUID/base64/8-128 chars); expand column to 128
- Query ?hwid= fallback; unique-race refresh; surface enforce errors
fix(hwid): enforce limit properly; accept real client device ids
- When hwid_limit>0, require valid x-hwid (deny bare clients with 403)
- Relax pattern (UUID/base64/8-128 chars); expand column to 128
- Query ?hwid= fallback; unique-race refresh; surface enforce errors
fix(hwid): enforce limit properly; accept real client device ids
- When hwid_limit>0, require valid x-hwid (deny bare clients with 403)
- Relax pattern (UUID/base64/8-128 chars); expand column to 128
- Query ?hwid= fallback; unique-race refresh; surface enforce errors
fix(hwid): enforce limit properly; accept real client device ids
- When hwid_limit>0, require valid x-hwid (deny bare clients with 403)
- Relax pattern (UUID/base64/8-128 chars); expand column to 128
- Query ?hwid= fallback; unique-race refresh; surface enforce errors
2026-09-20 00:50:00 +08:00
codebuddy 2c4ed3cb4a style: gofmt all backend Go files (CI gofmt check was failing)
style: gofmt all backend Go files (CI gofmt check was failing)
style: gofmt all backend Go files (CI gofmt check was failing)
style: gofmt all backend Go files (CI gofmt check was failing)
style: gofmt all backend Go files (CI gofmt check was failing)
style: gofmt all backend Go files (CI gofmt check was failing)
style: gofmt all backend Go files (CI gofmt check was failing)
style: gofmt all backend Go files (CI gofmt check was failing)
style: gofmt all backend Go files (CI gofmt check was failing)
style: gofmt all backend Go files (CI gofmt check was failing)
style: gofmt all backend Go files (CI gofmt check was failing)
style: gofmt all backend Go files (CI gofmt check was failing)
2026-09-14 14:04:29 +08:00
Z User 4778c43c79 feat: online ops parity — HWID devices UI, first-use expiry, external subs, TOTP, web_path
- Users: start_on_first_use + expire_days_after_first; TouchFirstUse on sub/traffic
- External subscription URLs merged into Clash/Mihomo client YAML
- HWID device list/kick/clear wired in Users (API already present)
- Admin TOTP 2FA (setup/enable/disable + login second step)
- Optional server.web_path panel prefix (config.yaml)
- subscription-userinfo already present; Traffic page shows live connections
feat: online ops parity — HWID devices UI, first-use expiry, external subs, TOTP, web_path
- Users: start_on_first_use + expire_days_after_first; TouchFirstUse on sub/traffic
- External subscription URLs merged into Clash/Mihomo client YAML
- HWID device list/kick/clear wired in Users (API already present)
- Admin TOTP 2FA (setup/enable/disable + login second step)
- Optional server.web_path panel prefix (config.yaml)
- subscription-userinfo already present; Traffic page shows live connections
feat: online ops parity — HWID devices UI, first-use expiry, external subs, TOTP, web_path
- Users: start_on_first_use + expire_days_after_first; TouchFirstUse on sub/traffic
- External subscription URLs merged into Clash/Mihomo client YAML
- HWID device list/kick/clear wired in Users (API already present)
- Admin TOTP 2FA (setup/enable/disable + login second step)
- Optional server.web_path panel prefix (config.yaml)
- subscription-userinfo already present; Traffic page shows live connections
feat: online ops parity — HWID devices UI, first-use expiry, external subs, TOTP, web_path
- Users: start_on_first_use + expire_days_after_first; TouchFirstUse on sub/traffic
- External subscription URLs merged into Clash/Mihomo client YAML
- HWID device list/kick/clear wired in Users (API already present)
- Admin TOTP 2FA (setup/enable/disable + login second step)
- Optional server.web_path panel prefix (config.yaml)
- subscription-userinfo already present; Traffic page shows live connections
feat: online ops parity — HWID devices UI, first-use expiry, external subs, TOTP, web_path
- Users: start_on_first_use + expire_days_after_first; TouchFirstUse on sub/traffic
- External subscription URLs merged into Clash/Mihomo client YAML
- HWID device list/kick/clear wired in Users (API already present)
- Admin TOTP 2FA (setup/enable/disable + login second step)
- Optional server.web_path panel prefix (config.yaml)
- subscription-userinfo already present; Traffic page shows live connections
feat: online ops parity — HWID devices UI, first-use expiry, external subs, TOTP, web_path
- Users: start_on_first_use + expire_days_after_first; TouchFirstUse on sub/traffic
- External subscription URLs merged into Clash/Mihomo client YAML
- HWID device list/kick/clear wired in Users (API already present)
- Admin TOTP 2FA (setup/enable/disable + login second step)
- Optional server.web_path panel prefix (config.yaml)
- subscription-userinfo already present; Traffic page shows live connections
feat: online ops parity — HWID devices UI, first-use expiry, external subs, TOTP, web_path
- Users: start_on_first_use + expire_days_after_first; TouchFirstUse on sub/traffic
- External subscription URLs merged into Clash/Mihomo client YAML
- HWID device list/kick/clear wired in Users (API already present)
- Admin TOTP 2FA (setup/enable/disable + login second step)
- Optional server.web_path panel prefix (config.yaml)
- subscription-userinfo already present; Traffic page shows live connections
feat: online ops parity — HWID devices UI, first-use expiry, external subs, TOTP, web_path
- Users: start_on_first_use + expire_days_after_first; TouchFirstUse on sub/traffic
- External subscription URLs merged into Clash/Mihomo client YAML
- HWID device list/kick/clear wired in Users (API already present)
- Admin TOTP 2FA (setup/enable/disable + login second step)
- Optional server.web_path panel prefix (config.yaml)
- subscription-userinfo already present; Traffic page shows live connections
feat: online ops parity — HWID devices UI, first-use expiry, external subs, TOTP, web_path
- Users: start_on_first_use + expire_days_after_first; TouchFirstUse on sub/traffic
- External subscription URLs merged into Clash/Mihomo client YAML
- HWID device list/kick/clear wired in Users (API already present)
- Admin TOTP 2FA (setup/enable/disable + login second step)
- Optional server.web_path panel prefix (config.yaml)
- subscription-userinfo already present; Traffic page shows live connections
feat: online ops parity — HWID devices UI, first-use expiry, external subs, TOTP, web_path
- Users: start_on_first_use + expire_days_after_first; TouchFirstUse on sub/traffic
- External subscription URLs merged into Clash/Mihomo client YAML
- HWID device list/kick/clear wired in Users (API already present)
- Admin TOTP 2FA (setup/enable/disable + login second step)
- Optional server.web_path panel prefix (config.yaml)
- subscription-userinfo already present; Traffic page shows live connections
feat: online ops parity — HWID devices UI, first-use expiry, external subs, TOTP, web_path
- Users: start_on_first_use + expire_days_after_first; TouchFirstUse on sub/traffic
- External subscription URLs merged into Clash/Mihomo client YAML
- HWID device list/kick/clear wired in Users (API already present)
- Admin TOTP 2FA (setup/enable/disable + login second step)
- Optional server.web_path panel prefix (config.yaml)
- subscription-userinfo already present; Traffic page shows live connections
feat: online ops parity — HWID devices UI, first-use expiry, external subs, TOTP, web_path
- Users: start_on_first_use + expire_days_after_first; TouchFirstUse on sub/traffic
- External subscription URLs merged into Clash/Mihomo client YAML
- HWID device list/kick/clear wired in Users (API already present)
- Admin TOTP 2FA (setup/enable/disable + login second step)
- Optional server.web_path panel prefix (config.yaml)
- subscription-userinfo already present; Traffic page shows live connections
2026-09-12 15:31:24 +00:00
Z User 3a5b0d7e66 feat: sub path/port, user groups/tags/cycle renew, export links, WARP register
- server.sub_path / sub_port / env overrides; custom /sub/:token + optional second listener
- subscription URLs use configured path; legacy API path kept
- proxy users: group, tags, traffic_reset_days, expire_renew_days + background cycle job
- GET /users/export-links for one-click subscription link export
- POST /system/templates/warp/register (Cloudflare WARP one-click) + Settings UI
- Share page export-all; Users form fields for group/tags/cycles
feat: sub path/port, user groups/tags/cycle renew, export links, WARP register
- server.sub_path / sub_port / env overrides; custom /sub/:token + optional second listener
- subscription URLs use configured path; legacy API path kept
- proxy users: group, tags, traffic_reset_days, expire_renew_days + background cycle job
- GET /users/export-links for one-click subscription link export
- POST /system/templates/warp/register (Cloudflare WARP one-click) + Settings UI
- Share page export-all; Users form fields for group/tags/cycles
feat: sub path/port, user groups/tags/cycle renew, export links, WARP register
- server.sub_path / sub_port / env overrides; custom /sub/:token + optional second listener
- subscription URLs use configured path; legacy API path kept
- proxy users: group, tags, traffic_reset_days, expire_renew_days + background cycle job
- GET /users/export-links for one-click subscription link export
- POST /system/templates/warp/register (Cloudflare WARP one-click) + Settings UI
- Share page export-all; Users form fields for group/tags/cycles
feat: sub path/port, user groups/tags/cycle renew, export links, WARP register
- server.sub_path / sub_port / env overrides; custom /sub/:token + optional second listener
- subscription URLs use configured path; legacy API path kept
- proxy users: group, tags, traffic_reset_days, expire_renew_days + background cycle job
- GET /users/export-links for one-click subscription link export
- POST /system/templates/warp/register (Cloudflare WARP one-click) + Settings UI
- Share page export-all; Users form fields for group/tags/cycles
feat: sub path/port, user groups/tags/cycle renew, export links, WARP register
- server.sub_path / sub_port / env overrides; custom /sub/:token + optional second listener
- subscription URLs use configured path; legacy API path kept
- proxy users: group, tags, traffic_reset_days, expire_renew_days + background cycle job
- GET /users/export-links for one-click subscription link export
- POST /system/templates/warp/register (Cloudflare WARP one-click) + Settings UI
- Share page export-all; Users form fields for group/tags/cycles
feat: sub path/port, user groups/tags/cycle renew, export links, WARP register
- server.sub_path / sub_port / env overrides; custom /sub/:token + optional second listener
- subscription URLs use configured path; legacy API path kept
- proxy users: group, tags, traffic_reset_days, expire_renew_days + background cycle job
- GET /users/export-links for one-click subscription link export
- POST /system/templates/warp/register (Cloudflare WARP one-click) + Settings UI
- Share page export-all; Users form fields for group/tags/cycles
feat: sub path/port, user groups/tags/cycle renew, export links, WARP register
- server.sub_path / sub_port / env overrides; custom /sub/:token + optional second listener
- subscription URLs use configured path; legacy API path kept
- proxy users: group, tags, traffic_reset_days, expire_renew_days + background cycle job
- GET /users/export-links for one-click subscription link export
- POST /system/templates/warp/register (Cloudflare WARP one-click) + Settings UI
- Share page export-all; Users form fields for group/tags/cycles
feat: sub path/port, user groups/tags/cycle renew, export links, WARP register
- server.sub_path / sub_port / env overrides; custom /sub/:token + optional second listener
- subscription URLs use configured path; legacy API path kept
- proxy users: group, tags, traffic_reset_days, expire_renew_days + background cycle job
- GET /users/export-links for one-click subscription link export
- POST /system/templates/warp/register (Cloudflare WARP one-click) + Settings UI
- Share page export-all; Users form fields for group/tags/cycles
feat: sub path/port, user groups/tags/cycle renew, export links, WARP register
- server.sub_path / sub_port / env overrides; custom /sub/:token + optional second listener
- subscription URLs use configured path; legacy API path kept
- proxy users: group, tags, traffic_reset_days, expire_renew_days + background cycle job
- GET /users/export-links for one-click subscription link export
- POST /system/templates/warp/register (Cloudflare WARP one-click) + Settings UI
- Share page export-all; Users form fields for group/tags/cycles
feat: sub path/port, user groups/tags/cycle renew, export links, WARP register
- server.sub_path / sub_port / env overrides; custom /sub/:token + optional second listener
- subscription URLs use configured path; legacy API path kept
- proxy users: group, tags, traffic_reset_days, expire_renew_days + background cycle job
- GET /users/export-links for one-click subscription link export
- POST /system/templates/warp/register (Cloudflare WARP one-click) + Settings UI
- Share page export-all; Users form fields for group/tags/cycles
feat: sub path/port, user groups/tags/cycle renew, export links, WARP register
- server.sub_path / sub_port / env overrides; custom /sub/:token + optional second listener
- subscription URLs use configured path; legacy API path kept
- proxy users: group, tags, traffic_reset_days, expire_renew_days + background cycle job
- GET /users/export-links for one-click subscription link export
- POST /system/templates/warp/register (Cloudflare WARP one-click) + Settings UI
- Share page export-all; Users form fields for group/tags/cycles
feat: sub path/port, user groups/tags/cycle renew, export links, WARP register
- server.sub_path / sub_port / env overrides; custom /sub/:token + optional second listener
- subscription URLs use configured path; legacy API path kept
- proxy users: group, tags, traffic_reset_days, expire_renew_days + background cycle job
- GET /users/export-links for one-click subscription link export
- POST /system/templates/warp/register (Cloudflare WARP one-click) + Settings UI
- Share page export-all; Users form fields for group/tags/cycles
2026-09-10 16:45:18 +00:00
Z User 2c625c8790 fix(db): silence GORM record-not-found noise for optional settings
Telegram and traffic_reset_day lookups are expected to miss until configured;
default Info logger flooded journal every scheduler tick and looked like errors.
fix(db): silence GORM record-not-found noise for optional settings
Telegram and traffic_reset_day lookups are expected to miss until configured;
default Info logger flooded journal every scheduler tick and looked like errors.
fix(db): silence GORM record-not-found noise for optional settings
Telegram and traffic_reset_day lookups are expected to miss until configured;
default Info logger flooded journal every scheduler tick and looked like errors.
fix(db): silence GORM record-not-found noise for optional settings
Telegram and traffic_reset_day lookups are expected to miss until configured;
default Info logger flooded journal every scheduler tick and looked like errors.
fix(db): silence GORM record-not-found noise for optional settings
Telegram and traffic_reset_day lookups are expected to miss until configured;
default Info logger flooded journal every scheduler tick and looked like errors.
fix(db): silence GORM record-not-found noise for optional settings
Telegram and traffic_reset_day lookups are expected to miss until configured;
default Info logger flooded journal every scheduler tick and looked like errors.
fix(db): silence GORM record-not-found noise for optional settings
Telegram and traffic_reset_day lookups are expected to miss until configured;
default Info logger flooded journal every scheduler tick and looked like errors.
fix(db): silence GORM record-not-found noise for optional settings
Telegram and traffic_reset_day lookups are expected to miss until configured;
default Info logger flooded journal every scheduler tick and looked like errors.
fix(db): silence GORM record-not-found noise for optional settings
Telegram and traffic_reset_day lookups are expected to miss until configured;
default Info logger flooded journal every scheduler tick and looked like errors.
fix(db): silence GORM record-not-found noise for optional settings
Telegram and traffic_reset_day lookups are expected to miss until configured;
default Info logger flooded journal every scheduler tick and looked like errors.
fix(db): silence GORM record-not-found noise for optional settings
Telegram and traffic_reset_day lookups are expected to miss until configured;
default Info logger flooded journal every scheduler tick and looked like errors.
fix(db): silence GORM record-not-found noise for optional settings
Telegram and traffic_reset_day lookups are expected to miss until configured;
default Info logger flooded journal every scheduler tick and looked like errors.
2026-09-10 14:23:21 +00:00
freephilx 2e6256fb6a feat(distribution): add complete installation and recovery workflows
Ship stable-only Linux bundles and multiarch Docker images with a pinned Mihomo core. Share secure first-run initialization across native and container installs.
Validate downloads before downtime, snapshot persistent state before updates, and restore the previous installation after a failed upgrade. Add backup, restore, healthcheck, and randomized administrator reset commands.
Add release verification, lifecycle regression tests, and installation documentation.
feat(distribution): add complete installation and recovery workflows
Ship stable-only Linux bundles and multiarch Docker images with a pinned Mihomo core. Share secure first-run initialization across native and container installs.
Validate downloads before downtime, snapshot persistent state before updates, and restore the previous installation after a failed upgrade. Add backup, restore, healthcheck, and randomized administrator reset commands.
Add release verification, lifecycle regression tests, and installation documentation.
feat(distribution): add complete installation and recovery workflows
Ship stable-only Linux bundles and multiarch Docker images with a pinned Mihomo core. Share secure first-run initialization across native and container installs.
Validate downloads before downtime, snapshot persistent state before updates, and restore the previous installation after a failed upgrade. Add backup, restore, healthcheck, and randomized administrator reset commands.
Add release verification, lifecycle regression tests, and installation documentation.
feat(distribution): add complete installation and recovery workflows
Ship stable-only Linux bundles and multiarch Docker images with a pinned Mihomo core. Share secure first-run initialization across native and container installs.
Validate downloads before downtime, snapshot persistent state before updates, and restore the previous installation after a failed upgrade. Add backup, restore, healthcheck, and randomized administrator reset commands.
Add release verification, lifecycle regression tests, and installation documentation.
feat(distribution): add complete installation and recovery workflows
Ship stable-only Linux bundles and multiarch Docker images with a pinned Mihomo core. Share secure first-run initialization across native and container installs.
Validate downloads before downtime, snapshot persistent state before updates, and restore the previous installation after a failed upgrade. Add backup, restore, healthcheck, and randomized administrator reset commands.
Add release verification, lifecycle regression tests, and installation documentation.
feat(distribution): add complete installation and recovery workflows
Ship stable-only Linux bundles and multiarch Docker images with a pinned Mihomo core. Share secure first-run initialization across native and container installs.
Validate downloads before downtime, snapshot persistent state before updates, and restore the previous installation after a failed upgrade. Add backup, restore, healthcheck, and randomized administrator reset commands.
Add release verification, lifecycle regression tests, and installation documentation.
feat(distribution): add complete installation and recovery workflows
Ship stable-only Linux bundles and multiarch Docker images with a pinned Mihomo core. Share secure first-run initialization across native and container installs.
Validate downloads before downtime, snapshot persistent state before updates, and restore the previous installation after a failed upgrade. Add backup, restore, healthcheck, and randomized administrator reset commands.
Add release verification, lifecycle regression tests, and installation documentation.
feat(distribution): add complete installation and recovery workflows
Ship stable-only Linux bundles and multiarch Docker images with a pinned Mihomo core. Share secure first-run initialization across native and container installs.
Validate downloads before downtime, snapshot persistent state before updates, and restore the previous installation after a failed upgrade. Add backup, restore, healthcheck, and randomized administrator reset commands.
Add release verification, lifecycle regression tests, and installation documentation.
feat(distribution): add complete installation and recovery workflows
Ship stable-only Linux bundles and multiarch Docker images with a pinned Mihomo core. Share secure first-run initialization across native and container installs.
Validate downloads before downtime, snapshot persistent state before updates, and restore the previous installation after a failed upgrade. Add backup, restore, healthcheck, and randomized administrator reset commands.
Add release verification, lifecycle regression tests, and installation documentation.
feat(distribution): add complete installation and recovery workflows
Ship stable-only Linux bundles and multiarch Docker images with a pinned Mihomo core. Share secure first-run initialization across native and container installs.
Validate downloads before downtime, snapshot persistent state before updates, and restore the previous installation after a failed upgrade. Add backup, restore, healthcheck, and randomized administrator reset commands.
Add release verification, lifecycle regression tests, and installation documentation.
feat(distribution): add complete installation and recovery workflows
Ship stable-only Linux bundles and multiarch Docker images with a pinned Mihomo core. Share secure first-run initialization across native and container installs.
Validate downloads before downtime, snapshot persistent state before updates, and restore the previous installation after a failed upgrade. Add backup, restore, healthcheck, and randomized administrator reset commands.
Add release verification, lifecycle regression tests, and installation documentation.
feat(distribution): add complete installation and recovery workflows
Ship stable-only Linux bundles and multiarch Docker images with a pinned Mihomo core. Share secure first-run initialization across native and container installs.
Validate downloads before downtime, snapshot persistent state before updates, and restore the previous installation after a failed upgrade. Add backup, restore, healthcheck, and randomized administrator reset commands.
Add release verification, lifecycle regression tests, and installation documentation.
2026-09-08 22:47:35 +08:00
freephilx 0e5af8a096 feat(listeners)!: select REALITY targets with server-side checks
BREAKING CHANGE: REALITY create and update requests require an explicit reality-config.dest; implicit Microsoft and SNI-derived destinations are no longer supplied.
feat(listeners)!: select REALITY targets with server-side checks
BREAKING CHANGE: REALITY create and update requests require an explicit reality-config.dest; implicit Microsoft and SNI-derived destinations are no longer supplied.
feat(listeners)!: select REALITY targets with server-side checks
BREAKING CHANGE: REALITY create and update requests require an explicit reality-config.dest; implicit Microsoft and SNI-derived destinations are no longer supplied.
feat(listeners)!: select REALITY targets with server-side checks
BREAKING CHANGE: REALITY create and update requests require an explicit reality-config.dest; implicit Microsoft and SNI-derived destinations are no longer supplied.
feat(listeners)!: select REALITY targets with server-side checks
BREAKING CHANGE: REALITY create and update requests require an explicit reality-config.dest; implicit Microsoft and SNI-derived destinations are no longer supplied.
feat(listeners)!: select REALITY targets with server-side checks
BREAKING CHANGE: REALITY create and update requests require an explicit reality-config.dest; implicit Microsoft and SNI-derived destinations are no longer supplied.
feat(listeners)!: select REALITY targets with server-side checks
BREAKING CHANGE: REALITY create and update requests require an explicit reality-config.dest; implicit Microsoft and SNI-derived destinations are no longer supplied.
feat(listeners)!: select REALITY targets with server-side checks
BREAKING CHANGE: REALITY create and update requests require an explicit reality-config.dest; implicit Microsoft and SNI-derived destinations are no longer supplied.
feat(listeners)!: select REALITY targets with server-side checks
BREAKING CHANGE: REALITY create and update requests require an explicit reality-config.dest; implicit Microsoft and SNI-derived destinations are no longer supplied.
feat(listeners)!: select REALITY targets with server-side checks
BREAKING CHANGE: REALITY create and update requests require an explicit reality-config.dest; implicit Microsoft and SNI-derived destinations are no longer supplied.
feat(listeners)!: select REALITY targets with server-side checks
BREAKING CHANGE: REALITY create and update requests require an explicit reality-config.dest; implicit Microsoft and SNI-derived destinations are no longer supplied.
feat(listeners)!: select REALITY targets with server-side checks
BREAKING CHANGE: REALITY create and update requests require an explicit reality-config.dest; implicit Microsoft and SNI-derived destinations are no longer supplied.
2026-09-08 22:47:32 +08:00
Z User 7ce3796d9b feat(hwid): Happ/Remnawave-compatible subscription HWID device limit
- Track x-hwid / x-device-os / x-ver-os / x-device-model on sub fetch
- Per-user hwid_limit; response headers x-hwid-active|not-supported|max-devices-reached
- Admin API list/delete/clear devices; user form field
feat(hwid): Happ/Remnawave-compatible subscription HWID device limit
- Track x-hwid / x-device-os / x-ver-os / x-device-model on sub fetch
- Per-user hwid_limit; response headers x-hwid-active|not-supported|max-devices-reached
- Admin API list/delete/clear devices; user form field
feat(hwid): Happ/Remnawave-compatible subscription HWID device limit
- Track x-hwid / x-device-os / x-ver-os / x-device-model on sub fetch
- Per-user hwid_limit; response headers x-hwid-active|not-supported|max-devices-reached
- Admin API list/delete/clear devices; user form field
feat(hwid): Happ/Remnawave-compatible subscription HWID device limit
- Track x-hwid / x-device-os / x-ver-os / x-device-model on sub fetch
- Per-user hwid_limit; response headers x-hwid-active|not-supported|max-devices-reached
- Admin API list/delete/clear devices; user form field
feat(hwid): Happ/Remnawave-compatible subscription HWID device limit
- Track x-hwid / x-device-os / x-ver-os / x-device-model on sub fetch
- Per-user hwid_limit; response headers x-hwid-active|not-supported|max-devices-reached
- Admin API list/delete/clear devices; user form field
feat(hwid): Happ/Remnawave-compatible subscription HWID device limit
- Track x-hwid / x-device-os / x-ver-os / x-device-model on sub fetch
- Per-user hwid_limit; response headers x-hwid-active|not-supported|max-devices-reached
- Admin API list/delete/clear devices; user form field
feat(hwid): Happ/Remnawave-compatible subscription HWID device limit
- Track x-hwid / x-device-os / x-ver-os / x-device-model on sub fetch
- Per-user hwid_limit; response headers x-hwid-active|not-supported|max-devices-reached
- Admin API list/delete/clear devices; user form field
feat(hwid): Happ/Remnawave-compatible subscription HWID device limit
- Track x-hwid / x-device-os / x-ver-os / x-device-model on sub fetch
- Per-user hwid_limit; response headers x-hwid-active|not-supported|max-devices-reached
- Admin API list/delete/clear devices; user form field
feat(hwid): Happ/Remnawave-compatible subscription HWID device limit
- Track x-hwid / x-device-os / x-ver-os / x-device-model on sub fetch
- Per-user hwid_limit; response headers x-hwid-active|not-supported|max-devices-reached
- Admin API list/delete/clear devices; user form field
feat(hwid): Happ/Remnawave-compatible subscription HWID device limit
- Track x-hwid / x-device-os / x-ver-os / x-device-model on sub fetch
- Per-user hwid_limit; response headers x-hwid-active|not-supported|max-devices-reached
- Admin API list/delete/clear devices; user form field
feat(hwid): Happ/Remnawave-compatible subscription HWID device limit
- Track x-hwid / x-device-os / x-ver-os / x-device-model on sub fetch
- Per-user hwid_limit; response headers x-hwid-active|not-supported|max-devices-reached
- Admin API list/delete/clear devices; user form field
feat(hwid): Happ/Remnawave-compatible subscription HWID device limit
- Track x-hwid / x-device-os / x-ver-os / x-device-model on sub fetch
- Per-user hwid_limit; response headers x-hwid-active|not-supported|max-devices-reached
- Admin API list/delete/clear devices; user form field
2026-09-07 14:32:02 +00:00
Z User 812373aa27 fix(audit): cluster JWT storage size, Telegram chat_ids/events robustness
- Store remote panel JWT as text (HS256 tokens can exceed 256 chars)
- Accept chat_ids as JSON array or comma-separated string
- Default enabled_events when empty; EventEnabled falls back to login,cpu,crash
- Gate CPU Telegram alerts by EventEnabled("cpu")
fix(audit): cluster JWT storage size, Telegram chat_ids/events robustness
- Store remote panel JWT as text (HS256 tokens can exceed 256 chars)
- Accept chat_ids as JSON array or comma-separated string
- Default enabled_events when empty; EventEnabled falls back to login,cpu,crash
- Gate CPU Telegram alerts by EventEnabled("cpu")
fix(audit): cluster JWT storage size, Telegram chat_ids/events robustness
- Store remote panel JWT as text (HS256 tokens can exceed 256 chars)
- Accept chat_ids as JSON array or comma-separated string
- Default enabled_events when empty; EventEnabled falls back to login,cpu,crash
- Gate CPU Telegram alerts by EventEnabled("cpu")
fix(audit): cluster JWT storage size, Telegram chat_ids/events robustness
- Store remote panel JWT as text (HS256 tokens can exceed 256 chars)
- Accept chat_ids as JSON array or comma-separated string
- Default enabled_events when empty; EventEnabled falls back to login,cpu,crash
- Gate CPU Telegram alerts by EventEnabled("cpu")
fix(audit): cluster JWT storage size, Telegram chat_ids/events robustness
- Store remote panel JWT as text (HS256 tokens can exceed 256 chars)
- Accept chat_ids as JSON array or comma-separated string
- Default enabled_events when empty; EventEnabled falls back to login,cpu,crash
- Gate CPU Telegram alerts by EventEnabled("cpu")
fix(audit): cluster JWT storage size, Telegram chat_ids/events robustness
- Store remote panel JWT as text (HS256 tokens can exceed 256 chars)
- Accept chat_ids as JSON array or comma-separated string
- Default enabled_events when empty; EventEnabled falls back to login,cpu,crash
- Gate CPU Telegram alerts by EventEnabled("cpu")
fix(audit): cluster JWT storage size, Telegram chat_ids/events robustness
- Store remote panel JWT as text (HS256 tokens can exceed 256 chars)
- Accept chat_ids as JSON array or comma-separated string
- Default enabled_events when empty; EventEnabled falls back to login,cpu,crash
- Gate CPU Telegram alerts by EventEnabled("cpu")
fix(audit): cluster JWT storage size, Telegram chat_ids/events robustness
- Store remote panel JWT as text (HS256 tokens can exceed 256 chars)
- Accept chat_ids as JSON array or comma-separated string
- Default enabled_events when empty; EventEnabled falls back to login,cpu,crash
- Gate CPU Telegram alerts by EventEnabled("cpu")
fix(audit): cluster JWT storage size, Telegram chat_ids/events robustness
- Store remote panel JWT as text (HS256 tokens can exceed 256 chars)
- Accept chat_ids as JSON array or comma-separated string
- Default enabled_events when empty; EventEnabled falls back to login,cpu,crash
- Gate CPU Telegram alerts by EventEnabled("cpu")
fix(audit): cluster JWT storage size, Telegram chat_ids/events robustness
- Store remote panel JWT as text (HS256 tokens can exceed 256 chars)
- Accept chat_ids as JSON array or comma-separated string
- Default enabled_events when empty; EventEnabled falls back to login,cpu,crash
- Gate CPU Telegram alerts by EventEnabled("cpu")
fix(audit): cluster JWT storage size, Telegram chat_ids/events robustness
- Store remote panel JWT as text (HS256 tokens can exceed 256 chars)
- Accept chat_ids as JSON array or comma-separated string
- Default enabled_events when empty; EventEnabled falls back to login,cpu,crash
- Gate CPU Telegram alerts by EventEnabled("cpu")
fix(audit): cluster JWT storage size, Telegram chat_ids/events robustness
- Store remote panel JWT as text (HS256 tokens can exceed 256 chars)
- Accept chat_ids as JSON array or comma-separated string
- Default enabled_events when empty; EventEnabled falls back to login,cpu,crash
- Gate CPU Telegram alerts by EventEnabled("cpu")
2026-09-05 14:46:55 +00:00
Z User bcb1d50393 feat(cluster): sync remote node mirrors and merge into local user subscription
- Cache remote nodes + URI/client_yaml via POST /cluster/:id/sync-nodes
- Bind local users to mirrors; Clash YAML and v2ray base64 subs merge remote entries
- UI: Sync nodes on cluster page; remote multi-select in user bind dialog
feat(cluster): sync remote node mirrors and merge into local user subscription
- Cache remote nodes + URI/client_yaml via POST /cluster/:id/sync-nodes
- Bind local users to mirrors; Clash YAML and v2ray base64 subs merge remote entries
- UI: Sync nodes on cluster page; remote multi-select in user bind dialog
feat(cluster): sync remote node mirrors and merge into local user subscription
- Cache remote nodes + URI/client_yaml via POST /cluster/:id/sync-nodes
- Bind local users to mirrors; Clash YAML and v2ray base64 subs merge remote entries
- UI: Sync nodes on cluster page; remote multi-select in user bind dialog
feat(cluster): sync remote node mirrors and merge into local user subscription
- Cache remote nodes + URI/client_yaml via POST /cluster/:id/sync-nodes
- Bind local users to mirrors; Clash YAML and v2ray base64 subs merge remote entries
- UI: Sync nodes on cluster page; remote multi-select in user bind dialog
feat(cluster): sync remote node mirrors and merge into local user subscription
- Cache remote nodes + URI/client_yaml via POST /cluster/:id/sync-nodes
- Bind local users to mirrors; Clash YAML and v2ray base64 subs merge remote entries
- UI: Sync nodes on cluster page; remote multi-select in user bind dialog
feat(cluster): sync remote node mirrors and merge into local user subscription
- Cache remote nodes + URI/client_yaml via POST /cluster/:id/sync-nodes
- Bind local users to mirrors; Clash YAML and v2ray base64 subs merge remote entries
- UI: Sync nodes on cluster page; remote multi-select in user bind dialog
feat(cluster): sync remote node mirrors and merge into local user subscription
- Cache remote nodes + URI/client_yaml via POST /cluster/:id/sync-nodes
- Bind local users to mirrors; Clash YAML and v2ray base64 subs merge remote entries
- UI: Sync nodes on cluster page; remote multi-select in user bind dialog
feat(cluster): sync remote node mirrors and merge into local user subscription
- Cache remote nodes + URI/client_yaml via POST /cluster/:id/sync-nodes
- Bind local users to mirrors; Clash YAML and v2ray base64 subs merge remote entries
- UI: Sync nodes on cluster page; remote multi-select in user bind dialog
feat(cluster): sync remote node mirrors and merge into local user subscription
- Cache remote nodes + URI/client_yaml via POST /cluster/:id/sync-nodes
- Bind local users to mirrors; Clash YAML and v2ray base64 subs merge remote entries
- UI: Sync nodes on cluster page; remote multi-select in user bind dialog
feat(cluster): sync remote node mirrors and merge into local user subscription
- Cache remote nodes + URI/client_yaml via POST /cluster/:id/sync-nodes
- Bind local users to mirrors; Clash YAML and v2ray base64 subs merge remote entries
- UI: Sync nodes on cluster page; remote multi-select in user bind dialog
feat(cluster): sync remote node mirrors and merge into local user subscription
- Cache remote nodes + URI/client_yaml via POST /cluster/:id/sync-nodes
- Bind local users to mirrors; Clash YAML and v2ray base64 subs merge remote entries
- UI: Sync nodes on cluster page; remote multi-select in user bind dialog
feat(cluster): sync remote node mirrors and merge into local user subscription
- Cache remote nodes + URI/client_yaml via POST /cluster/:id/sync-nodes
- Bind local users to mirrors; Clash YAML and v2ray base64 subs merge remote entries
- UI: Sync nodes on cluster page; remote multi-select in user bind dialog
2026-09-04 15:41:26 +00:00
風雪 dc13e69951 feat(telegram): full bot enhancement with inline menus, cron reports, events
Reference: https://docs.sanaei.dev/zh/docs/operations/telegram-bot/
Field naming follows existing 3m-ui snake_case convention (not sanaei's
tg* prefix) per project maintainer's request.
== Data layer ==
- ProxyUser: add TelegramID (indexed) + TelegramName fields for linking
proxy users to their Telegram accounts (self-service queries).
- SafeUser + ToSafeUser: expose both new fields.
- user.Service: BindTelegram / UnbindTelegram / GetByTelegramID methods.
- user API: GET /by-telegram/:tgid, PUT /:id/telegram, DELETE /:id/telegram
(registered before /:id to avoid path capture).
- UpdateInput/CreateInput: accept TelegramID + TelegramName.
== Settings expansion (8 new fields, snake_case) ==
- schedule: cron expr or @daily/@every 6h for periodic reports (default @daily)
- attach_backup: include DB backup zip in periodic report
- language: bot message language zh/en (default zh)
- enabled_events: comma-sep event list (default 'login,cpu,crash')
Supports: login,cpu,memory,crash,node_down,node_up,block,unblock,expiry,traffic
- expiry_warn_days: remind N days before expiry (0=off)
- traffic_warn_gb: remind when remaining traffic < N GB (0=off)
- proxy_url: socks5:// or http:// proxy for Telegram API
- api_server: custom Bot API server (empty=official)
- EventEnabled(name) helper for per-event gating.
== Client enhancements ==
- Proxy support: http(s):// via http.Transport.Proxy; socks5:// via
golang.org/x/net/proxy SOCKS5 dialer. Parse failure → direct fallback.
- Custom API server (apiBase() replaces hardcoded URL).
- SendDocument: multipart sendDocument for backup file attachment.
- GetMe + SetMyCommands: for bot-info + set-my-commands endpoints.
- sendWithKeyboard: sendMessage with reply_markup (inline keyboards).
- answerCallbackQuery: clear callback loading spinner.
== Bot commands + inline menus ==
- /id: reply with sender's Telegram numeric ID.
- /usage: admin → search users; bound user → self-query traffic/expiry/sub URL.
- /start + /help: send inline keyboard menu (admin menu for admin chats,
user menu for bound users, plain text for unbound).
- Admin menu: 8 buttons (status/users/traffic/online/listeners/deldepleted/
backup/restart) in 4 rows.
- User menu: my_usage + my_sub buttons.
- callback_query handling: answerCallbackQuery + dispatch on callback_data.
- Access control: admin chats always pass; non-admin chats pass only when
FromID matches a ProxyUser.TelegramID.
- Bot struct: added userSvc field for GetByTelegramID lookups.
- NewBot signature: NewBot(db, mihomoSvc, userSvc).
== Cron scheduler (new telegram/scheduler.go) ==
- Periodic report goroutine driven by Settings.Schedule.
- Supports @hourly/@daily/@weekly/@monthly/@every <dur>/5-field cron.
- Report: host, version, uptime, CPU/mem/disk, user stats, expiring+depleted
counts.
- Optional backup: AttachBackup → system.WriteZip → SendDocument.
- Settings reload on every tick (no restart needed for schedule changes).
- NotifyEvent(event, details): generic event emitter for one-shot alerts.
== Events layer ==
- login.attempt: NotifyLogin (success) + NotifyLoginFailed (failure).
Failure path added to auth/api.go Login handler. Both gated by
EventEnabled('login') — admins can mute success spam yet keep failure alerts.
- memory.high: emitMemoryWarning via gopsutil/v4/mem. Reuses CPUWarnPct as
shared 'resource warn %' threshold. 1-hour cooldown dedup.
- crash: mihomo ProcessManager.SetCrashHandler → telegram.NotifyCrash.
Fires on non-zero exit while desired==true (unexpected crash, not admin stop).
Wired in app/container.go.
- Dual thresholds: expiry (hours + days), traffic (percent + GB) with
separate dedup keys so neither suppresses the other.
== API endpoints ==
- POST /telegram/set-my-commands: registers 12-command menu with Telegram.
- GET /telegram/bot-info: returns bot username/first_name/id.
== Frontend ==
- telegram.ts: 8 new fields in TelegramSettings interface + setTelegramCommands
+ fetchTelegramBotInfo API functions.
- Settings.tsx: 8 new form controls (schedule Input, language Select,
enabled_events multi-Select with 10 options, expiry_warn_days + traffic_warn_gb
InputNumber, attach_backup Switch, proxy_url Input, api_server Input).
Added 'Set bot commands' button calling setTelegramCommands.
- i18n: 11 new keys (zh + en) for the new settings labels.
== Verification ==
- go build ./... : PASS
- go vet ./... : PASS
- go test ./... : all 15 packages PASS
- npm run build (tsc + vite) : PASS, 3241 modules
- gofmt : clean
feat(telegram): full bot enhancement with inline menus, cron reports, events
Reference: https://docs.sanaei.dev/zh/docs/operations/telegram-bot/
Field naming follows existing 3m-ui snake_case convention (not sanaei's
tg* prefix) per project maintainer's request.
== Data layer ==
- ProxyUser: add TelegramID (indexed) + TelegramName fields for linking
proxy users to their Telegram accounts (self-service queries).
- SafeUser + ToSafeUser: expose both new fields.
- user.Service: BindTelegram / UnbindTelegram / GetByTelegramID methods.
- user API: GET /by-telegram/:tgid, PUT /:id/telegram, DELETE /:id/telegram
(registered before /:id to avoid path capture).
- UpdateInput/CreateInput: accept TelegramID + TelegramName.
== Settings expansion (8 new fields, snake_case) ==
- schedule: cron expr or @daily/@every 6h for periodic reports (default @daily)
- attach_backup: include DB backup zip in periodic report
- language: bot message language zh/en (default zh)
- enabled_events: comma-sep event list (default 'login,cpu,crash')
Supports: login,cpu,memory,crash,node_down,node_up,block,unblock,expiry,traffic
- expiry_warn_days: remind N days before expiry (0=off)
- traffic_warn_gb: remind when remaining traffic < N GB (0=off)
- proxy_url: socks5:// or http:// proxy for Telegram API
- api_server: custom Bot API server (empty=official)
- EventEnabled(name) helper for per-event gating.
== Client enhancements ==
- Proxy support: http(s):// via http.Transport.Proxy; socks5:// via
golang.org/x/net/proxy SOCKS5 dialer. Parse failure → direct fallback.
- Custom API server (apiBase() replaces hardcoded URL).
- SendDocument: multipart sendDocument for backup file attachment.
- GetMe + SetMyCommands: for bot-info + set-my-commands endpoints.
- sendWithKeyboard: sendMessage with reply_markup (inline keyboards).
- answerCallbackQuery: clear callback loading spinner.
== Bot commands + inline menus ==
- /id: reply with sender's Telegram numeric ID.
- /usage: admin → search users; bound user → self-query traffic/expiry/sub URL.
- /start + /help: send inline keyboard menu (admin menu for admin chats,
user menu for bound users, plain text for unbound).
- Admin menu: 8 buttons (status/users/traffic/online/listeners/deldepleted/
backup/restart) in 4 rows.
- User menu: my_usage + my_sub buttons.
- callback_query handling: answerCallbackQuery + dispatch on callback_data.
- Access control: admin chats always pass; non-admin chats pass only when
FromID matches a ProxyUser.TelegramID.
- Bot struct: added userSvc field for GetByTelegramID lookups.
- NewBot signature: NewBot(db, mihomoSvc, userSvc).
== Cron scheduler (new telegram/scheduler.go) ==
- Periodic report goroutine driven by Settings.Schedule.
- Supports @hourly/@daily/@weekly/@monthly/@every <dur>/5-field cron.
- Report: host, version, uptime, CPU/mem/disk, user stats, expiring+depleted
counts.
- Optional backup: AttachBackup → system.WriteZip → SendDocument.
- Settings reload on every tick (no restart needed for schedule changes).
- NotifyEvent(event, details): generic event emitter for one-shot alerts.
== Events layer ==
- login.attempt: NotifyLogin (success) + NotifyLoginFailed (failure).
Failure path added to auth/api.go Login handler. Both gated by
EventEnabled('login') — admins can mute success spam yet keep failure alerts.
- memory.high: emitMemoryWarning via gopsutil/v4/mem. Reuses CPUWarnPct as
shared 'resource warn %' threshold. 1-hour cooldown dedup.
- crash: mihomo ProcessManager.SetCrashHandler → telegram.NotifyCrash.
Fires on non-zero exit while desired==true (unexpected crash, not admin stop).
Wired in app/container.go.
- Dual thresholds: expiry (hours + days), traffic (percent + GB) with
separate dedup keys so neither suppresses the other.
== API endpoints ==
- POST /telegram/set-my-commands: registers 12-command menu with Telegram.
- GET /telegram/bot-info: returns bot username/first_name/id.
== Frontend ==
- telegram.ts: 8 new fields in TelegramSettings interface + setTelegramCommands
+ fetchTelegramBotInfo API functions.
- Settings.tsx: 8 new form controls (schedule Input, language Select,
enabled_events multi-Select with 10 options, expiry_warn_days + traffic_warn_gb
InputNumber, attach_backup Switch, proxy_url Input, api_server Input).
Added 'Set bot commands' button calling setTelegramCommands.
- i18n: 11 new keys (zh + en) for the new settings labels.
== Verification ==
- go build ./... : PASS
- go vet ./... : PASS
- go test ./... : all 15 packages PASS
- npm run build (tsc + vite) : PASS, 3241 modules
- gofmt : clean
feat(telegram): full bot enhancement with inline menus, cron reports, events
Reference: https://docs.sanaei.dev/zh/docs/operations/telegram-bot/
Field naming follows existing 3m-ui snake_case convention (not sanaei's
tg* prefix) per project maintainer's request.
== Data layer ==
- ProxyUser: add TelegramID (indexed) + TelegramName fields for linking
proxy users to their Telegram accounts (self-service queries).
- SafeUser + ToSafeUser: expose both new fields.
- user.Service: BindTelegram / UnbindTelegram / GetByTelegramID methods.
- user API: GET /by-telegram/:tgid, PUT /:id/telegram, DELETE /:id/telegram
(registered before /:id to avoid path capture).
- UpdateInput/CreateInput: accept TelegramID + TelegramName.
== Settings expansion (8 new fields, snake_case) ==
- schedule: cron expr or @daily/@every 6h for periodic reports (default @daily)
- attach_backup: include DB backup zip in periodic report
- language: bot message language zh/en (default zh)
- enabled_events: comma-sep event list (default 'login,cpu,crash')
Supports: login,cpu,memory,crash,node_down,node_up,block,unblock,expiry,traffic
- expiry_warn_days: remind N days before expiry (0=off)
- traffic_warn_gb: remind when remaining traffic < N GB (0=off)
- proxy_url: socks5:// or http:// proxy for Telegram API
- api_server: custom Bot API server (empty=official)
- EventEnabled(name) helper for per-event gating.
== Client enhancements ==
- Proxy support: http(s):// via http.Transport.Proxy; socks5:// via
golang.org/x/net/proxy SOCKS5 dialer. Parse failure → direct fallback.
- Custom API server (apiBase() replaces hardcoded URL).
- SendDocument: multipart sendDocument for backup file attachment.
- GetMe + SetMyCommands: for bot-info + set-my-commands endpoints.
- sendWithKeyboard: sendMessage with reply_markup (inline keyboards).
- answerCallbackQuery: clear callback loading spinner.
== Bot commands + inline menus ==
- /id: reply with sender's Telegram numeric ID.
- /usage: admin → search users; bound user → self-query traffic/expiry/sub URL.
- /start + /help: send inline keyboard menu (admin menu for admin chats,
user menu for bound users, plain text for unbound).
- Admin menu: 8 buttons (status/users/traffic/online/listeners/deldepleted/
backup/restart) in 4 rows.
- User menu: my_usage + my_sub buttons.
- callback_query handling: answerCallbackQuery + dispatch on callback_data.
- Access control: admin chats always pass; non-admin chats pass only when
FromID matches a ProxyUser.TelegramID.
- Bot struct: added userSvc field for GetByTelegramID lookups.
- NewBot signature: NewBot(db, mihomoSvc, userSvc).
== Cron scheduler (new telegram/scheduler.go) ==
- Periodic report goroutine driven by Settings.Schedule.
- Supports @hourly/@daily/@weekly/@monthly/@every <dur>/5-field cron.
- Report: host, version, uptime, CPU/mem/disk, user stats, expiring+depleted
counts.
- Optional backup: AttachBackup → system.WriteZip → SendDocument.
- Settings reload on every tick (no restart needed for schedule changes).
- NotifyEvent(event, details): generic event emitter for one-shot alerts.
== Events layer ==
- login.attempt: NotifyLogin (success) + NotifyLoginFailed (failure).
Failure path added to auth/api.go Login handler. Both gated by
EventEnabled('login') — admins can mute success spam yet keep failure alerts.
- memory.high: emitMemoryWarning via gopsutil/v4/mem. Reuses CPUWarnPct as
shared 'resource warn %' threshold. 1-hour cooldown dedup.
- crash: mihomo ProcessManager.SetCrashHandler → telegram.NotifyCrash.
Fires on non-zero exit while desired==true (unexpected crash, not admin stop).
Wired in app/container.go.
- Dual thresholds: expiry (hours + days), traffic (percent + GB) with
separate dedup keys so neither suppresses the other.
== API endpoints ==
- POST /telegram/set-my-commands: registers 12-command menu with Telegram.
- GET /telegram/bot-info: returns bot username/first_name/id.
== Frontend ==
- telegram.ts: 8 new fields in TelegramSettings interface + setTelegramCommands
+ fetchTelegramBotInfo API functions.
- Settings.tsx: 8 new form controls (schedule Input, language Select,
enabled_events multi-Select with 10 options, expiry_warn_days + traffic_warn_gb
InputNumber, attach_backup Switch, proxy_url Input, api_server Input).
Added 'Set bot commands' button calling setTelegramCommands.
- i18n: 11 new keys (zh + en) for the new settings labels.
== Verification ==
- go build ./... : PASS
- go vet ./... : PASS
- go test ./... : all 15 packages PASS
- npm run build (tsc + vite) : PASS, 3241 modules
- gofmt : clean
feat(telegram): full bot enhancement with inline menus, cron reports, events
Reference: https://docs.sanaei.dev/zh/docs/operations/telegram-bot/
Field naming follows existing 3m-ui snake_case convention (not sanaei's
tg* prefix) per project maintainer's request.
== Data layer ==
- ProxyUser: add TelegramID (indexed) + TelegramName fields for linking
proxy users to their Telegram accounts (self-service queries).
- SafeUser + ToSafeUser: expose both new fields.
- user.Service: BindTelegram / UnbindTelegram / GetByTelegramID methods.
- user API: GET /by-telegram/:tgid, PUT /:id/telegram, DELETE /:id/telegram
(registered before /:id to avoid path capture).
- UpdateInput/CreateInput: accept TelegramID + TelegramName.
== Settings expansion (8 new fields, snake_case) ==
- schedule: cron expr or @daily/@every 6h for periodic reports (default @daily)
- attach_backup: include DB backup zip in periodic report
- language: bot message language zh/en (default zh)
- enabled_events: comma-sep event list (default 'login,cpu,crash')
Supports: login,cpu,memory,crash,node_down,node_up,block,unblock,expiry,traffic
- expiry_warn_days: remind N days before expiry (0=off)
- traffic_warn_gb: remind when remaining traffic < N GB (0=off)
- proxy_url: socks5:// or http:// proxy for Telegram API
- api_server: custom Bot API server (empty=official)
- EventEnabled(name) helper for per-event gating.
== Client enhancements ==
- Proxy support: http(s):// via http.Transport.Proxy; socks5:// via
golang.org/x/net/proxy SOCKS5 dialer. Parse failure → direct fallback.
- Custom API server (apiBase() replaces hardcoded URL).
- SendDocument: multipart sendDocument for backup file attachment.
- GetMe + SetMyCommands: for bot-info + set-my-commands endpoints.
- sendWithKeyboard: sendMessage with reply_markup (inline keyboards).
- answerCallbackQuery: clear callback loading spinner.
== Bot commands + inline menus ==
- /id: reply with sender's Telegram numeric ID.
- /usage: admin → search users; bound user → self-query traffic/expiry/sub URL.
- /start + /help: send inline keyboard menu (admin menu for admin chats,
user menu for bound users, plain text for unbound).
- Admin menu: 8 buttons (status/users/traffic/online/listeners/deldepleted/
backup/restart) in 4 rows.
- User menu: my_usage + my_sub buttons.
- callback_query handling: answerCallbackQuery + dispatch on callback_data.
- Access control: admin chats always pass; non-admin chats pass only when
FromID matches a ProxyUser.TelegramID.
- Bot struct: added userSvc field for GetByTelegramID lookups.
- NewBot signature: NewBot(db, mihomoSvc, userSvc).
== Cron scheduler (new telegram/scheduler.go) ==
- Periodic report goroutine driven by Settings.Schedule.
- Supports @hourly/@daily/@weekly/@monthly/@every <dur>/5-field cron.
- Report: host, version, uptime, CPU/mem/disk, user stats, expiring+depleted
counts.
- Optional backup: AttachBackup → system.WriteZip → SendDocument.
- Settings reload on every tick (no restart needed for schedule changes).
- NotifyEvent(event, details): generic event emitter for one-shot alerts.
== Events layer ==
- login.attempt: NotifyLogin (success) + NotifyLoginFailed (failure).
Failure path added to auth/api.go Login handler. Both gated by
EventEnabled('login') — admins can mute success spam yet keep failure alerts.
- memory.high: emitMemoryWarning via gopsutil/v4/mem. Reuses CPUWarnPct as
shared 'resource warn %' threshold. 1-hour cooldown dedup.
- crash: mihomo ProcessManager.SetCrashHandler → telegram.NotifyCrash.
Fires on non-zero exit while desired==true (unexpected crash, not admin stop).
Wired in app/container.go.
- Dual thresholds: expiry (hours + days), traffic (percent + GB) with
separate dedup keys so neither suppresses the other.
== API endpoints ==
- POST /telegram/set-my-commands: registers 12-command menu with Telegram.
- GET /telegram/bot-info: returns bot username/first_name/id.
== Frontend ==
- telegram.ts: 8 new fields in TelegramSettings interface + setTelegramCommands
+ fetchTelegramBotInfo API functions.
- Settings.tsx: 8 new form controls (schedule Input, language Select,
enabled_events multi-Select with 10 options, expiry_warn_days + traffic_warn_gb
InputNumber, attach_backup Switch, proxy_url Input, api_server Input).
Added 'Set bot commands' button calling setTelegramCommands.
- i18n: 11 new keys (zh + en) for the new settings labels.
== Verification ==
- go build ./... : PASS
- go vet ./... : PASS
- go test ./... : all 15 packages PASS
- npm run build (tsc + vite) : PASS, 3241 modules
- gofmt : clean
feat(telegram): full bot enhancement with inline menus, cron reports, events
Reference: https://docs.sanaei.dev/zh/docs/operations/telegram-bot/
Field naming follows existing 3m-ui snake_case convention (not sanaei's
tg* prefix) per project maintainer's request.
== Data layer ==
- ProxyUser: add TelegramID (indexed) + TelegramName fields for linking
proxy users to their Telegram accounts (self-service queries).
- SafeUser + ToSafeUser: expose both new fields.
- user.Service: BindTelegram / UnbindTelegram / GetByTelegramID methods.
- user API: GET /by-telegram/:tgid, PUT /:id/telegram, DELETE /:id/telegram
(registered before /:id to avoid path capture).
- UpdateInput/CreateInput: accept TelegramID + TelegramName.
== Settings expansion (8 new fields, snake_case) ==
- schedule: cron expr or @daily/@every 6h for periodic reports (default @daily)
- attach_backup: include DB backup zip in periodic report
- language: bot message language zh/en (default zh)
- enabled_events: comma-sep event list (default 'login,cpu,crash')
Supports: login,cpu,memory,crash,node_down,node_up,block,unblock,expiry,traffic
- expiry_warn_days: remind N days before expiry (0=off)
- traffic_warn_gb: remind when remaining traffic < N GB (0=off)
- proxy_url: socks5:// or http:// proxy for Telegram API
- api_server: custom Bot API server (empty=official)
- EventEnabled(name) helper for per-event gating.
== Client enhancements ==
- Proxy support: http(s):// via http.Transport.Proxy; socks5:// via
golang.org/x/net/proxy SOCKS5 dialer. Parse failure → direct fallback.
- Custom API server (apiBase() replaces hardcoded URL).
- SendDocument: multipart sendDocument for backup file attachment.
- GetMe + SetMyCommands: for bot-info + set-my-commands endpoints.
- sendWithKeyboard: sendMessage with reply_markup (inline keyboards).
- answerCallbackQuery: clear callback loading spinner.
== Bot commands + inline menus ==
- /id: reply with sender's Telegram numeric ID.
- /usage: admin → search users; bound user → self-query traffic/expiry/sub URL.
- /start + /help: send inline keyboard menu (admin menu for admin chats,
user menu for bound users, plain text for unbound).
- Admin menu: 8 buttons (status/users/traffic/online/listeners/deldepleted/
backup/restart) in 4 rows.
- User menu: my_usage + my_sub buttons.
- callback_query handling: answerCallbackQuery + dispatch on callback_data.
- Access control: admin chats always pass; non-admin chats pass only when
FromID matches a ProxyUser.TelegramID.
- Bot struct: added userSvc field for GetByTelegramID lookups.
- NewBot signature: NewBot(db, mihomoSvc, userSvc).
== Cron scheduler (new telegram/scheduler.go) ==
- Periodic report goroutine driven by Settings.Schedule.
- Supports @hourly/@daily/@weekly/@monthly/@every <dur>/5-field cron.
- Report: host, version, uptime, CPU/mem/disk, user stats, expiring+depleted
counts.
- Optional backup: AttachBackup → system.WriteZip → SendDocument.
- Settings reload on every tick (no restart needed for schedule changes).
- NotifyEvent(event, details): generic event emitter for one-shot alerts.
== Events layer ==
- login.attempt: NotifyLogin (success) + NotifyLoginFailed (failure).
Failure path added to auth/api.go Login handler. Both gated by
EventEnabled('login') — admins can mute success spam yet keep failure alerts.
- memory.high: emitMemoryWarning via gopsutil/v4/mem. Reuses CPUWarnPct as
shared 'resource warn %' threshold. 1-hour cooldown dedup.
- crash: mihomo ProcessManager.SetCrashHandler → telegram.NotifyCrash.
Fires on non-zero exit while desired==true (unexpected crash, not admin stop).
Wired in app/container.go.
- Dual thresholds: expiry (hours + days), traffic (percent + GB) with
separate dedup keys so neither suppresses the other.
== API endpoints ==
- POST /telegram/set-my-commands: registers 12-command menu with Telegram.
- GET /telegram/bot-info: returns bot username/first_name/id.
== Frontend ==
- telegram.ts: 8 new fields in TelegramSettings interface + setTelegramCommands
+ fetchTelegramBotInfo API functions.
- Settings.tsx: 8 new form controls (schedule Input, language Select,
enabled_events multi-Select with 10 options, expiry_warn_days + traffic_warn_gb
InputNumber, attach_backup Switch, proxy_url Input, api_server Input).
Added 'Set bot commands' button calling setTelegramCommands.
- i18n: 11 new keys (zh + en) for the new settings labels.
== Verification ==
- go build ./... : PASS
- go vet ./... : PASS
- go test ./... : all 15 packages PASS
- npm run build (tsc + vite) : PASS, 3241 modules
- gofmt : clean
feat(telegram): full bot enhancement with inline menus, cron reports, events
Reference: https://docs.sanaei.dev/zh/docs/operations/telegram-bot/
Field naming follows existing 3m-ui snake_case convention (not sanaei's
tg* prefix) per project maintainer's request.
== Data layer ==
- ProxyUser: add TelegramID (indexed) + TelegramName fields for linking
proxy users to their Telegram accounts (self-service queries).
- SafeUser + ToSafeUser: expose both new fields.
- user.Service: BindTelegram / UnbindTelegram / GetByTelegramID methods.
- user API: GET /by-telegram/:tgid, PUT /:id/telegram, DELETE /:id/telegram
(registered before /:id to avoid path capture).
- UpdateInput/CreateInput: accept TelegramID + TelegramName.
== Settings expansion (8 new fields, snake_case) ==
- schedule: cron expr or @daily/@every 6h for periodic reports (default @daily)
- attach_backup: include DB backup zip in periodic report
- language: bot message language zh/en (default zh)
- enabled_events: comma-sep event list (default 'login,cpu,crash')
Supports: login,cpu,memory,crash,node_down,node_up,block,unblock,expiry,traffic
- expiry_warn_days: remind N days before expiry (0=off)
- traffic_warn_gb: remind when remaining traffic < N GB (0=off)
- proxy_url: socks5:// or http:// proxy for Telegram API
- api_server: custom Bot API server (empty=official)
- EventEnabled(name) helper for per-event gating.
== Client enhancements ==
- Proxy support: http(s):// via http.Transport.Proxy; socks5:// via
golang.org/x/net/proxy SOCKS5 dialer. Parse failure → direct fallback.
- Custom API server (apiBase() replaces hardcoded URL).
- SendDocument: multipart sendDocument for backup file attachment.
- GetMe + SetMyCommands: for bot-info + set-my-commands endpoints.
- sendWithKeyboard: sendMessage with reply_markup (inline keyboards).
- answerCallbackQuery: clear callback loading spinner.
== Bot commands + inline menus ==
- /id: reply with sender's Telegram numeric ID.
- /usage: admin → search users; bound user → self-query traffic/expiry/sub URL.
- /start + /help: send inline keyboard menu (admin menu for admin chats,
user menu for bound users, plain text for unbound).
- Admin menu: 8 buttons (status/users/traffic/online/listeners/deldepleted/
backup/restart) in 4 rows.
- User menu: my_usage + my_sub buttons.
- callback_query handling: answerCallbackQuery + dispatch on callback_data.
- Access control: admin chats always pass; non-admin chats pass only when
FromID matches a ProxyUser.TelegramID.
- Bot struct: added userSvc field for GetByTelegramID lookups.
- NewBot signature: NewBot(db, mihomoSvc, userSvc).
== Cron scheduler (new telegram/scheduler.go) ==
- Periodic report goroutine driven by Settings.Schedule.
- Supports @hourly/@daily/@weekly/@monthly/@every <dur>/5-field cron.
- Report: host, version, uptime, CPU/mem/disk, user stats, expiring+depleted
counts.
- Optional backup: AttachBackup → system.WriteZip → SendDocument.
- Settings reload on every tick (no restart needed for schedule changes).
- NotifyEvent(event, details): generic event emitter for one-shot alerts.
== Events layer ==
- login.attempt: NotifyLogin (success) + NotifyLoginFailed (failure).
Failure path added to auth/api.go Login handler. Both gated by
EventEnabled('login') — admins can mute success spam yet keep failure alerts.
- memory.high: emitMemoryWarning via gopsutil/v4/mem. Reuses CPUWarnPct as
shared 'resource warn %' threshold. 1-hour cooldown dedup.
- crash: mihomo ProcessManager.SetCrashHandler → telegram.NotifyCrash.
Fires on non-zero exit while desired==true (unexpected crash, not admin stop).
Wired in app/container.go.
- Dual thresholds: expiry (hours + days), traffic (percent + GB) with
separate dedup keys so neither suppresses the other.
== API endpoints ==
- POST /telegram/set-my-commands: registers 12-command menu with Telegram.
- GET /telegram/bot-info: returns bot username/first_name/id.
== Frontend ==
- telegram.ts: 8 new fields in TelegramSettings interface + setTelegramCommands
+ fetchTelegramBotInfo API functions.
- Settings.tsx: 8 new form controls (schedule Input, language Select,
enabled_events multi-Select with 10 options, expiry_warn_days + traffic_warn_gb
InputNumber, attach_backup Switch, proxy_url Input, api_server Input).
Added 'Set bot commands' button calling setTelegramCommands.
- i18n: 11 new keys (zh + en) for the new settings labels.
== Verification ==
- go build ./... : PASS
- go vet ./... : PASS
- go test ./... : all 15 packages PASS
- npm run build (tsc + vite) : PASS, 3241 modules
- gofmt : clean
feat(telegram): full bot enhancement with inline menus, cron reports, events
Reference: https://docs.sanaei.dev/zh/docs/operations/telegram-bot/
Field naming follows existing 3m-ui snake_case convention (not sanaei's
tg* prefix) per project maintainer's request.
== Data layer ==
- ProxyUser: add TelegramID (indexed) + TelegramName fields for linking
proxy users to their Telegram accounts (self-service queries).
- SafeUser + ToSafeUser: expose both new fields.
- user.Service: BindTelegram / UnbindTelegram / GetByTelegramID methods.
- user API: GET /by-telegram/:tgid, PUT /:id/telegram, DELETE /:id/telegram
(registered before /:id to avoid path capture).
- UpdateInput/CreateInput: accept TelegramID + TelegramName.
== Settings expansion (8 new fields, snake_case) ==
- schedule: cron expr or @daily/@every 6h for periodic reports (default @daily)
- attach_backup: include DB backup zip in periodic report
- language: bot message language zh/en (default zh)
- enabled_events: comma-sep event list (default 'login,cpu,crash')
Supports: login,cpu,memory,crash,node_down,node_up,block,unblock,expiry,traffic
- expiry_warn_days: remind N days before expiry (0=off)
- traffic_warn_gb: remind when remaining traffic < N GB (0=off)
- proxy_url: socks5:// or http:// proxy for Telegram API
- api_server: custom Bot API server (empty=official)
- EventEnabled(name) helper for per-event gating.
== Client enhancements ==
- Proxy support: http(s):// via http.Transport.Proxy; socks5:// via
golang.org/x/net/proxy SOCKS5 dialer. Parse failure → direct fallback.
- Custom API server (apiBase() replaces hardcoded URL).
- SendDocument: multipart sendDocument for backup file attachment.
- GetMe + SetMyCommands: for bot-info + set-my-commands endpoints.
- sendWithKeyboard: sendMessage with reply_markup (inline keyboards).
- answerCallbackQuery: clear callback loading spinner.
== Bot commands + inline menus ==
- /id: reply with sender's Telegram numeric ID.
- /usage: admin → search users; bound user → self-query traffic/expiry/sub URL.
- /start + /help: send inline keyboard menu (admin menu for admin chats,
user menu for bound users, plain text for unbound).
- Admin menu: 8 buttons (status/users/traffic/online/listeners/deldepleted/
backup/restart) in 4 rows.
- User menu: my_usage + my_sub buttons.
- callback_query handling: answerCallbackQuery + dispatch on callback_data.
- Access control: admin chats always pass; non-admin chats pass only when
FromID matches a ProxyUser.TelegramID.
- Bot struct: added userSvc field for GetByTelegramID lookups.
- NewBot signature: NewBot(db, mihomoSvc, userSvc).
== Cron scheduler (new telegram/scheduler.go) ==
- Periodic report goroutine driven by Settings.Schedule.
- Supports @hourly/@daily/@weekly/@monthly/@every <dur>/5-field cron.
- Report: host, version, uptime, CPU/mem/disk, user stats, expiring+depleted
counts.
- Optional backup: AttachBackup → system.WriteZip → SendDocument.
- Settings reload on every tick (no restart needed for schedule changes).
- NotifyEvent(event, details): generic event emitter for one-shot alerts.
== Events layer ==
- login.attempt: NotifyLogin (success) + NotifyLoginFailed (failure).
Failure path added to auth/api.go Login handler. Both gated by
EventEnabled('login') — admins can mute success spam yet keep failure alerts.
- memory.high: emitMemoryWarning via gopsutil/v4/mem. Reuses CPUWarnPct as
shared 'resource warn %' threshold. 1-hour cooldown dedup.
- crash: mihomo ProcessManager.SetCrashHandler → telegram.NotifyCrash.
Fires on non-zero exit while desired==true (unexpected crash, not admin stop).
Wired in app/container.go.
- Dual thresholds: expiry (hours + days), traffic (percent + GB) with
separate dedup keys so neither suppresses the other.
== API endpoints ==
- POST /telegram/set-my-commands: registers 12-command menu with Telegram.
- GET /telegram/bot-info: returns bot username/first_name/id.
== Frontend ==
- telegram.ts: 8 new fields in TelegramSettings interface + setTelegramCommands
+ fetchTelegramBotInfo API functions.
- Settings.tsx: 8 new form controls (schedule Input, language Select,
enabled_events multi-Select with 10 options, expiry_warn_days + traffic_warn_gb
InputNumber, attach_backup Switch, proxy_url Input, api_server Input).
Added 'Set bot commands' button calling setTelegramCommands.
- i18n: 11 new keys (zh + en) for the new settings labels.
== Verification ==
- go build ./... : PASS
- go vet ./... : PASS
- go test ./... : all 15 packages PASS
- npm run build (tsc + vite) : PASS, 3241 modules
- gofmt : clean
feat(telegram): full bot enhancement with inline menus, cron reports, events
Reference: https://docs.sanaei.dev/zh/docs/operations/telegram-bot/
Field naming follows existing 3m-ui snake_case convention (not sanaei's
tg* prefix) per project maintainer's request.
== Data layer ==
- ProxyUser: add TelegramID (indexed) + TelegramName fields for linking
proxy users to their Telegram accounts (self-service queries).
- SafeUser + ToSafeUser: expose both new fields.
- user.Service: BindTelegram / UnbindTelegram / GetByTelegramID methods.
- user API: GET /by-telegram/:tgid, PUT /:id/telegram, DELETE /:id/telegram
(registered before /:id to avoid path capture).
- UpdateInput/CreateInput: accept TelegramID + TelegramName.
== Settings expansion (8 new fields, snake_case) ==
- schedule: cron expr or @daily/@every 6h for periodic reports (default @daily)
- attach_backup: include DB backup zip in periodic report
- language: bot message language zh/en (default zh)
- enabled_events: comma-sep event list (default 'login,cpu,crash')
Supports: login,cpu,memory,crash,node_down,node_up,block,unblock,expiry,traffic
- expiry_warn_days: remind N days before expiry (0=off)
- traffic_warn_gb: remind when remaining traffic < N GB (0=off)
- proxy_url: socks5:// or http:// proxy for Telegram API
- api_server: custom Bot API server (empty=official)
- EventEnabled(name) helper for per-event gating.
== Client enhancements ==
- Proxy support: http(s):// via http.Transport.Proxy; socks5:// via
golang.org/x/net/proxy SOCKS5 dialer. Parse failure → direct fallback.
- Custom API server (apiBase() replaces hardcoded URL).
- SendDocument: multipart sendDocument for backup file attachment.
- GetMe + SetMyCommands: for bot-info + set-my-commands endpoints.
- sendWithKeyboard: sendMessage with reply_markup (inline keyboards).
- answerCallbackQuery: clear callback loading spinner.
== Bot commands + inline menus ==
- /id: reply with sender's Telegram numeric ID.
- /usage: admin → search users; bound user → self-query traffic/expiry/sub URL.
- /start + /help: send inline keyboard menu (admin menu for admin chats,
user menu for bound users, plain text for unbound).
- Admin menu: 8 buttons (status/users/traffic/online/listeners/deldepleted/
backup/restart) in 4 rows.
- User menu: my_usage + my_sub buttons.
- callback_query handling: answerCallbackQuery + dispatch on callback_data.
- Access control: admin chats always pass; non-admin chats pass only when
FromID matches a ProxyUser.TelegramID.
- Bot struct: added userSvc field for GetByTelegramID lookups.
- NewBot signature: NewBot(db, mihomoSvc, userSvc).
== Cron scheduler (new telegram/scheduler.go) ==
- Periodic report goroutine driven by Settings.Schedule.
- Supports @hourly/@daily/@weekly/@monthly/@every <dur>/5-field cron.
- Report: host, version, uptime, CPU/mem/disk, user stats, expiring+depleted
counts.
- Optional backup: AttachBackup → system.WriteZip → SendDocument.
- Settings reload on every tick (no restart needed for schedule changes).
- NotifyEvent(event, details): generic event emitter for one-shot alerts.
== Events layer ==
- login.attempt: NotifyLogin (success) + NotifyLoginFailed (failure).
Failure path added to auth/api.go Login handler. Both gated by
EventEnabled('login') — admins can mute success spam yet keep failure alerts.
- memory.high: emitMemoryWarning via gopsutil/v4/mem. Reuses CPUWarnPct as
shared 'resource warn %' threshold. 1-hour cooldown dedup.
- crash: mihomo ProcessManager.SetCrashHandler → telegram.NotifyCrash.
Fires on non-zero exit while desired==true (unexpected crash, not admin stop).
Wired in app/container.go.
- Dual thresholds: expiry (hours + days), traffic (percent + GB) with
separate dedup keys so neither suppresses the other.
== API endpoints ==
- POST /telegram/set-my-commands: registers 12-command menu with Telegram.
- GET /telegram/bot-info: returns bot username/first_name/id.
== Frontend ==
- telegram.ts: 8 new fields in TelegramSettings interface + setTelegramCommands
+ fetchTelegramBotInfo API functions.
- Settings.tsx: 8 new form controls (schedule Input, language Select,
enabled_events multi-Select with 10 options, expiry_warn_days + traffic_warn_gb
InputNumber, attach_backup Switch, proxy_url Input, api_server Input).
Added 'Set bot commands' button calling setTelegramCommands.
- i18n: 11 new keys (zh + en) for the new settings labels.
== Verification ==
- go build ./... : PASS
- go vet ./... : PASS
- go test ./... : all 15 packages PASS
- npm run build (tsc + vite) : PASS, 3241 modules
- gofmt : clean
feat(telegram): full bot enhancement with inline menus, cron reports, events
Reference: https://docs.sanaei.dev/zh/docs/operations/telegram-bot/
Field naming follows existing 3m-ui snake_case convention (not sanaei's
tg* prefix) per project maintainer's request.
== Data layer ==
- ProxyUser: add TelegramID (indexed) + TelegramName fields for linking
proxy users to their Telegram accounts (self-service queries).
- SafeUser + ToSafeUser: expose both new fields.
- user.Service: BindTelegram / UnbindTelegram / GetByTelegramID methods.
- user API: GET /by-telegram/:tgid, PUT /:id/telegram, DELETE /:id/telegram
(registered before /:id to avoid path capture).
- UpdateInput/CreateInput: accept TelegramID + TelegramName.
== Settings expansion (8 new fields, snake_case) ==
- schedule: cron expr or @daily/@every 6h for periodic reports (default @daily)
- attach_backup: include DB backup zip in periodic report
- language: bot message language zh/en (default zh)
- enabled_events: comma-sep event list (default 'login,cpu,crash')
Supports: login,cpu,memory,crash,node_down,node_up,block,unblock,expiry,traffic
- expiry_warn_days: remind N days before expiry (0=off)
- traffic_warn_gb: remind when remaining traffic < N GB (0=off)
- proxy_url: socks5:// or http:// proxy for Telegram API
- api_server: custom Bot API server (empty=official)
- EventEnabled(name) helper for per-event gating.
== Client enhancements ==
- Proxy support: http(s):// via http.Transport.Proxy; socks5:// via
golang.org/x/net/proxy SOCKS5 dialer. Parse failure → direct fallback.
- Custom API server (apiBase() replaces hardcoded URL).
- SendDocument: multipart sendDocument for backup file attachment.
- GetMe + SetMyCommands: for bot-info + set-my-commands endpoints.
- sendWithKeyboard: sendMessage with reply_markup (inline keyboards).
- answerCallbackQuery: clear callback loading spinner.
== Bot commands + inline menus ==
- /id: reply with sender's Telegram numeric ID.
- /usage: admin → search users; bound user → self-query traffic/expiry/sub URL.
- /start + /help: send inline keyboard menu (admin menu for admin chats,
user menu for bound users, plain text for unbound).
- Admin menu: 8 buttons (status/users/traffic/online/listeners/deldepleted/
backup/restart) in 4 rows.
- User menu: my_usage + my_sub buttons.
- callback_query handling: answerCallbackQuery + dispatch on callback_data.
- Access control: admin chats always pass; non-admin chats pass only when
FromID matches a ProxyUser.TelegramID.
- Bot struct: added userSvc field for GetByTelegramID lookups.
- NewBot signature: NewBot(db, mihomoSvc, userSvc).
== Cron scheduler (new telegram/scheduler.go) ==
- Periodic report goroutine driven by Settings.Schedule.
- Supports @hourly/@daily/@weekly/@monthly/@every <dur>/5-field cron.
- Report: host, version, uptime, CPU/mem/disk, user stats, expiring+depleted
counts.
- Optional backup: AttachBackup → system.WriteZip → SendDocument.
- Settings reload on every tick (no restart needed for schedule changes).
- NotifyEvent(event, details): generic event emitter for one-shot alerts.
== Events layer ==
- login.attempt: NotifyLogin (success) + NotifyLoginFailed (failure).
Failure path added to auth/api.go Login handler. Both gated by
EventEnabled('login') — admins can mute success spam yet keep failure alerts.
- memory.high: emitMemoryWarning via gopsutil/v4/mem. Reuses CPUWarnPct as
shared 'resource warn %' threshold. 1-hour cooldown dedup.
- crash: mihomo ProcessManager.SetCrashHandler → telegram.NotifyCrash.
Fires on non-zero exit while desired==true (unexpected crash, not admin stop).
Wired in app/container.go.
- Dual thresholds: expiry (hours + days), traffic (percent + GB) with
separate dedup keys so neither suppresses the other.
== API endpoints ==
- POST /telegram/set-my-commands: registers 12-command menu with Telegram.
- GET /telegram/bot-info: returns bot username/first_name/id.
== Frontend ==
- telegram.ts: 8 new fields in TelegramSettings interface + setTelegramCommands
+ fetchTelegramBotInfo API functions.
- Settings.tsx: 8 new form controls (schedule Input, language Select,
enabled_events multi-Select with 10 options, expiry_warn_days + traffic_warn_gb
InputNumber, attach_backup Switch, proxy_url Input, api_server Input).
Added 'Set bot commands' button calling setTelegramCommands.
- i18n: 11 new keys (zh + en) for the new settings labels.
== Verification ==
- go build ./... : PASS
- go vet ./... : PASS
- go test ./... : all 15 packages PASS
- npm run build (tsc + vite) : PASS, 3241 modules
- gofmt : clean
feat(telegram): full bot enhancement with inline menus, cron reports, events
Reference: https://docs.sanaei.dev/zh/docs/operations/telegram-bot/
Field naming follows existing 3m-ui snake_case convention (not sanaei's
tg* prefix) per project maintainer's request.
== Data layer ==
- ProxyUser: add TelegramID (indexed) + TelegramName fields for linking
proxy users to their Telegram accounts (self-service queries).
- SafeUser + ToSafeUser: expose both new fields.
- user.Service: BindTelegram / UnbindTelegram / GetByTelegramID methods.
- user API: GET /by-telegram/:tgid, PUT /:id/telegram, DELETE /:id/telegram
(registered before /:id to avoid path capture).
- UpdateInput/CreateInput: accept TelegramID + TelegramName.
== Settings expansion (8 new fields, snake_case) ==
- schedule: cron expr or @daily/@every 6h for periodic reports (default @daily)
- attach_backup: include DB backup zip in periodic report
- language: bot message language zh/en (default zh)
- enabled_events: comma-sep event list (default 'login,cpu,crash')
Supports: login,cpu,memory,crash,node_down,node_up,block,unblock,expiry,traffic
- expiry_warn_days: remind N days before expiry (0=off)
- traffic_warn_gb: remind when remaining traffic < N GB (0=off)
- proxy_url: socks5:// or http:// proxy for Telegram API
- api_server: custom Bot API server (empty=official)
- EventEnabled(name) helper for per-event gating.
== Client enhancements ==
- Proxy support: http(s):// via http.Transport.Proxy; socks5:// via
golang.org/x/net/proxy SOCKS5 dialer. Parse failure → direct fallback.
- Custom API server (apiBase() replaces hardcoded URL).
- SendDocument: multipart sendDocument for backup file attachment.
- GetMe + SetMyCommands: for bot-info + set-my-commands endpoints.
- sendWithKeyboard: sendMessage with reply_markup (inline keyboards).
- answerCallbackQuery: clear callback loading spinner.
== Bot commands + inline menus ==
- /id: reply with sender's Telegram numeric ID.
- /usage: admin → search users; bound user → self-query traffic/expiry/sub URL.
- /start + /help: send inline keyboard menu (admin menu for admin chats,
user menu for bound users, plain text for unbound).
- Admin menu: 8 buttons (status/users/traffic/online/listeners/deldepleted/
backup/restart) in 4 rows.
- User menu: my_usage + my_sub buttons.
- callback_query handling: answerCallbackQuery + dispatch on callback_data.
- Access control: admin chats always pass; non-admin chats pass only when
FromID matches a ProxyUser.TelegramID.
- Bot struct: added userSvc field for GetByTelegramID lookups.
- NewBot signature: NewBot(db, mihomoSvc, userSvc).
== Cron scheduler (new telegram/scheduler.go) ==
- Periodic report goroutine driven by Settings.Schedule.
- Supports @hourly/@daily/@weekly/@monthly/@every <dur>/5-field cron.
- Report: host, version, uptime, CPU/mem/disk, user stats, expiring+depleted
counts.
- Optional backup: AttachBackup → system.WriteZip → SendDocument.
- Settings reload on every tick (no restart needed for schedule changes).
- NotifyEvent(event, details): generic event emitter for one-shot alerts.
== Events layer ==
- login.attempt: NotifyLogin (success) + NotifyLoginFailed (failure).
Failure path added to auth/api.go Login handler. Both gated by
EventEnabled('login') — admins can mute success spam yet keep failure alerts.
- memory.high: emitMemoryWarning via gopsutil/v4/mem. Reuses CPUWarnPct as
shared 'resource warn %' threshold. 1-hour cooldown dedup.
- crash: mihomo ProcessManager.SetCrashHandler → telegram.NotifyCrash.
Fires on non-zero exit while desired==true (unexpected crash, not admin stop).
Wired in app/container.go.
- Dual thresholds: expiry (hours + days), traffic (percent + GB) with
separate dedup keys so neither suppresses the other.
== API endpoints ==
- POST /telegram/set-my-commands: registers 12-command menu with Telegram.
- GET /telegram/bot-info: returns bot username/first_name/id.
== Frontend ==
- telegram.ts: 8 new fields in TelegramSettings interface + setTelegramCommands
+ fetchTelegramBotInfo API functions.
- Settings.tsx: 8 new form controls (schedule Input, language Select,
enabled_events multi-Select with 10 options, expiry_warn_days + traffic_warn_gb
InputNumber, attach_backup Switch, proxy_url Input, api_server Input).
Added 'Set bot commands' button calling setTelegramCommands.
- i18n: 11 new keys (zh + en) for the new settings labels.
== Verification ==
- go build ./... : PASS
- go vet ./... : PASS
- go test ./... : all 15 packages PASS
- npm run build (tsc + vite) : PASS, 3241 modules
- gofmt : clean
feat(telegram): full bot enhancement with inline menus, cron reports, events
Reference: https://docs.sanaei.dev/zh/docs/operations/telegram-bot/
Field naming follows existing 3m-ui snake_case convention (not sanaei's
tg* prefix) per project maintainer's request.
== Data layer ==
- ProxyUser: add TelegramID (indexed) + TelegramName fields for linking
proxy users to their Telegram accounts (self-service queries).
- SafeUser + ToSafeUser: expose both new fields.
- user.Service: BindTelegram / UnbindTelegram / GetByTelegramID methods.
- user API: GET /by-telegram/:tgid, PUT /:id/telegram, DELETE /:id/telegram
(registered before /:id to avoid path capture).
- UpdateInput/CreateInput: accept TelegramID + TelegramName.
== Settings expansion (8 new fields, snake_case) ==
- schedule: cron expr or @daily/@every 6h for periodic reports (default @daily)
- attach_backup: include DB backup zip in periodic report
- language: bot message language zh/en (default zh)
- enabled_events: comma-sep event list (default 'login,cpu,crash')
Supports: login,cpu,memory,crash,node_down,node_up,block,unblock,expiry,traffic
- expiry_warn_days: remind N days before expiry (0=off)
- traffic_warn_gb: remind when remaining traffic < N GB (0=off)
- proxy_url: socks5:// or http:// proxy for Telegram API
- api_server: custom Bot API server (empty=official)
- EventEnabled(name) helper for per-event gating.
== Client enhancements ==
- Proxy support: http(s):// via http.Transport.Proxy; socks5:// via
golang.org/x/net/proxy SOCKS5 dialer. Parse failure → direct fallback.
- Custom API server (apiBase() replaces hardcoded URL).
- SendDocument: multipart sendDocument for backup file attachment.
- GetMe + SetMyCommands: for bot-info + set-my-commands endpoints.
- sendWithKeyboard: sendMessage with reply_markup (inline keyboards).
- answerCallbackQuery: clear callback loading spinner.
== Bot commands + inline menus ==
- /id: reply with sender's Telegram numeric ID.
- /usage: admin → search users; bound user → self-query traffic/expiry/sub URL.
- /start + /help: send inline keyboard menu (admin menu for admin chats,
user menu for bound users, plain text for unbound).
- Admin menu: 8 buttons (status/users/traffic/online/listeners/deldepleted/
backup/restart) in 4 rows.
- User menu: my_usage + my_sub buttons.
- callback_query handling: answerCallbackQuery + dispatch on callback_data.
- Access control: admin chats always pass; non-admin chats pass only when
FromID matches a ProxyUser.TelegramID.
- Bot struct: added userSvc field for GetByTelegramID lookups.
- NewBot signature: NewBot(db, mihomoSvc, userSvc).
== Cron scheduler (new telegram/scheduler.go) ==
- Periodic report goroutine driven by Settings.Schedule.
- Supports @hourly/@daily/@weekly/@monthly/@every <dur>/5-field cron.
- Report: host, version, uptime, CPU/mem/disk, user stats, expiring+depleted
counts.
- Optional backup: AttachBackup → system.WriteZip → SendDocument.
- Settings reload on every tick (no restart needed for schedule changes).
- NotifyEvent(event, details): generic event emitter for one-shot alerts.
== Events layer ==
- login.attempt: NotifyLogin (success) + NotifyLoginFailed (failure).
Failure path added to auth/api.go Login handler. Both gated by
EventEnabled('login') — admins can mute success spam yet keep failure alerts.
- memory.high: emitMemoryWarning via gopsutil/v4/mem. Reuses CPUWarnPct as
shared 'resource warn %' threshold. 1-hour cooldown dedup.
- crash: mihomo ProcessManager.SetCrashHandler → telegram.NotifyCrash.
Fires on non-zero exit while desired==true (unexpected crash, not admin stop).
Wired in app/container.go.
- Dual thresholds: expiry (hours + days), traffic (percent + GB) with
separate dedup keys so neither suppresses the other.
== API endpoints ==
- POST /telegram/set-my-commands: registers 12-command menu with Telegram.
- GET /telegram/bot-info: returns bot username/first_name/id.
== Frontend ==
- telegram.ts: 8 new fields in TelegramSettings interface + setTelegramCommands
+ fetchTelegramBotInfo API functions.
- Settings.tsx: 8 new form controls (schedule Input, language Select,
enabled_events multi-Select with 10 options, expiry_warn_days + traffic_warn_gb
InputNumber, attach_backup Switch, proxy_url Input, api_server Input).
Added 'Set bot commands' button calling setTelegramCommands.
- i18n: 11 new keys (zh + en) for the new settings labels.
== Verification ==
- go build ./... : PASS
- go vet ./... : PASS
- go test ./... : all 15 packages PASS
- npm run build (tsc + vite) : PASS, 3241 modules
- gofmt : clean
feat(telegram): full bot enhancement with inline menus, cron reports, events
Reference: https://docs.sanaei.dev/zh/docs/operations/telegram-bot/
Field naming follows existing 3m-ui snake_case convention (not sanaei's
tg* prefix) per project maintainer's request.
== Data layer ==
- ProxyUser: add TelegramID (indexed) + TelegramName fields for linking
proxy users to their Telegram accounts (self-service queries).
- SafeUser + ToSafeUser: expose both new fields.
- user.Service: BindTelegram / UnbindTelegram / GetByTelegramID methods.
- user API: GET /by-telegram/:tgid, PUT /:id/telegram, DELETE /:id/telegram
(registered before /:id to avoid path capture).
- UpdateInput/CreateInput: accept TelegramID + TelegramName.
== Settings expansion (8 new fields, snake_case) ==
- schedule: cron expr or @daily/@every 6h for periodic reports (default @daily)
- attach_backup: include DB backup zip in periodic report
- language: bot message language zh/en (default zh)
- enabled_events: comma-sep event list (default 'login,cpu,crash')
Supports: login,cpu,memory,crash,node_down,node_up,block,unblock,expiry,traffic
- expiry_warn_days: remind N days before expiry (0=off)
- traffic_warn_gb: remind when remaining traffic < N GB (0=off)
- proxy_url: socks5:// or http:// proxy for Telegram API
- api_server: custom Bot API server (empty=official)
- EventEnabled(name) helper for per-event gating.
== Client enhancements ==
- Proxy support: http(s):// via http.Transport.Proxy; socks5:// via
golang.org/x/net/proxy SOCKS5 dialer. Parse failure → direct fallback.
- Custom API server (apiBase() replaces hardcoded URL).
- SendDocument: multipart sendDocument for backup file attachment.
- GetMe + SetMyCommands: for bot-info + set-my-commands endpoints.
- sendWithKeyboard: sendMessage with reply_markup (inline keyboards).
- answerCallbackQuery: clear callback loading spinner.
== Bot commands + inline menus ==
- /id: reply with sender's Telegram numeric ID.
- /usage: admin → search users; bound user → self-query traffic/expiry/sub URL.
- /start + /help: send inline keyboard menu (admin menu for admin chats,
user menu for bound users, plain text for unbound).
- Admin menu: 8 buttons (status/users/traffic/online/listeners/deldepleted/
backup/restart) in 4 rows.
- User menu: my_usage + my_sub buttons.
- callback_query handling: answerCallbackQuery + dispatch on callback_data.
- Access control: admin chats always pass; non-admin chats pass only when
FromID matches a ProxyUser.TelegramID.
- Bot struct: added userSvc field for GetByTelegramID lookups.
- NewBot signature: NewBot(db, mihomoSvc, userSvc).
== Cron scheduler (new telegram/scheduler.go) ==
- Periodic report goroutine driven by Settings.Schedule.
- Supports @hourly/@daily/@weekly/@monthly/@every <dur>/5-field cron.
- Report: host, version, uptime, CPU/mem/disk, user stats, expiring+depleted
counts.
- Optional backup: AttachBackup → system.WriteZip → SendDocument.
- Settings reload on every tick (no restart needed for schedule changes).
- NotifyEvent(event, details): generic event emitter for one-shot alerts.
== Events layer ==
- login.attempt: NotifyLogin (success) + NotifyLoginFailed (failure).
Failure path added to auth/api.go Login handler. Both gated by
EventEnabled('login') — admins can mute success spam yet keep failure alerts.
- memory.high: emitMemoryWarning via gopsutil/v4/mem. Reuses CPUWarnPct as
shared 'resource warn %' threshold. 1-hour cooldown dedup.
- crash: mihomo ProcessManager.SetCrashHandler → telegram.NotifyCrash.
Fires on non-zero exit while desired==true (unexpected crash, not admin stop).
Wired in app/container.go.
- Dual thresholds: expiry (hours + days), traffic (percent + GB) with
separate dedup keys so neither suppresses the other.
== API endpoints ==
- POST /telegram/set-my-commands: registers 12-command menu with Telegram.
- GET /telegram/bot-info: returns bot username/first_name/id.
== Frontend ==
- telegram.ts: 8 new fields in TelegramSettings interface + setTelegramCommands
+ fetchTelegramBotInfo API functions.
- Settings.tsx: 8 new form controls (schedule Input, language Select,
enabled_events multi-Select with 10 options, expiry_warn_days + traffic_warn_gb
InputNumber, attach_backup Switch, proxy_url Input, api_server Input).
Added 'Set bot commands' button calling setTelegramCommands.
- i18n: 11 new keys (zh + en) for the new settings labels.
== Verification ==
- go build ./... : PASS
- go vet ./... : PASS
- go test ./... : all 15 packages PASS
- npm run build (tsc + vite) : PASS, 3241 modules
- gofmt : clean
2026-08-29 12:19:46 +00:00
風雪 69df7e5165 fix(db): Unscoped dedupe so unique indexes cannot block panel boot 2026-08-28 22:48:56 +08:00
風雪 9d95c97e7e fix(security): InitDB dedupe + cluster private URL hardening 2026-08-28 22:33:19 +08:00
風雪 e0e301cfc4 fix(security): unique listener/sub_token indexes; harden cluster SSRF 2026-08-28 22:32:29 +08:00
風雪 8d116f9c61 feat: multi-node remote panel registry, health-all, restricted remote control 2026-08-21 15:56:21 +00:00
風雪 885a68e57f chore: remove internal parity wording from comments and UI 2026-08-20 15:40:26 +00:00
風雪 6b3a09a09c update
update
update
update
update
update
update
update
update
update
update
update
2026-08-19 12:49:36 +08:00
風雪 ef236c6a6f feat: per-node Access Profile fields on Listener model 2026-08-18 17:09:36 +08:00
風雪 5fa916d982 security: restrict SQLite database filesystem permissions
security: restrict SQLite database filesystem permissions
security: restrict SQLite database filesystem permissions
security: restrict SQLite database filesystem permissions
security: restrict SQLite database filesystem permissions
security: restrict SQLite database filesystem permissions
security: restrict SQLite database filesystem permissions
security: restrict SQLite database filesystem permissions
security: restrict SQLite database filesystem permissions
security: restrict SQLite database filesystem permissions
security: restrict SQLite database filesystem permissions
security: restrict SQLite database filesystem permissions
2026-08-18 09:39:04 +08:00
風雪 0e297a9786 fix(audit): SubToken index (avoid empty unique clash) + token uniqueness retry + tests 2026-08-17 21:50:54 +08:00
風雪 768a428154 feat: user SubToken model + monthly traffic reset + panel-settings API 2026-08-17 21:24:11 +08:00
風雪 62a8f83b24 feat(users): ip_limit + remark ( limitIP parity) 2026-08-17 20:41:04 +08:00
風雪 d9fcbae4e2 fix(ci): BaseModel test literals for go test/vet 2026-08-17 16:25:26 +08:00
風雪 211e2b600f fix: migrate remaining models to BaseModel (lowercase id JSON) 2026-08-17 15:34:09 +08:00
風雪 48da56065d fix: BaseModel with json id to fix Listener delete invalid node id 2026-08-17 15:33:46 +08:00
風雪 80c6ef4996 feat: migrate listener templates and versions 2026-08-17 12:36:59 +08:00
風雪 229a588352 feat: add listener templates 2026-08-17 12:36:51 +08:00
風雪 222d6614cf feat: add listener version history 2026-08-17 12:36:45 +08:00
風雪 7c17d3d99f feat(telegram): link proxy users to Telegram accounts 2026-08-17 09:47:05 +08:00
風雪 be035f26e2 test: prevent listener ID JSON regression 2026-08-17 08:58:57 +08:00
風雪 96167d27ea fix: expose listener ID as id in JSON API 2026-08-17 08:58:53 +08:00
風雪 d238ba470e feat: migrate PanelSetting/RemoteServer; ACME/nginx templates 2026-08-16 22:56:07 +08:00
風雪 2409060e14 feat(telegram): client, settings store, block notifier 2026-08-16 22:51:53 +08:00
dzx941 5b4cb63a73 fix: align listener generation with mihomo official spec
- Port now supports mihomo ports format (single/range/list)
- Add explicit RoutingMark field support
- Auto-propagate UDP flag for vmess/vless/trojan/anytls/trusttunnel
- Update validator to accept port ranges
- Sync visual config and client converter port types
- Rename module from dzx941 to kazeyukiro
- Fix missing ExpiresAt in JWTClaims
- Fix nodeDTO Port type to string
- Fix frontend tsconfig and add missing dependencies
2026-08-16 09:21:42 +08:00