Commit Graph

822 Commits

Author SHA1 Message Date
sagitchu a98c9f4f59 merge(main): resolve node page conflicts with renewal UX updates 2026-03-09 17:52:18 +08:00
sagit 5cb935e0e5 fix(frontend): refine node renewal UI and filters (#299)
* style: restore Prettier formatting in renewal.ts

* fix(frontend): refine node renewal UI and filters

Entire-Checkpoint: 88c8ae47fb7d

* refactor(nodes): remove unused tags field from node model

* refactor(node): improve card layout and reorder elements

Entire-Checkpoint: fb89f3ebef5c
2026-03-09 08:37:57 +00:00
sagitchu 647446a2a2 fix(node): isolate tab search and selection state 2026-03-09 12:17:25 +08:00
sagit 42d6249af5 style: restore Prettier formatting in renewal.ts (#298) 2.1.8-alpha5 2026-03-09 10:29:33 +08:00
sagit de9ab51def feat: node management enhancements and UX improvements (#297)
* feat(nodes): add renewal cycle and auto-advance scheduling

- Add renewal_cycle field to nodes for tracking paid vs free cycles
- Implement auto-advance scheduling when renewal is processed
- Add migration test for renewal_cycle column
- Update dashboard to show renewal cycle count
- Add renewal status display on node detail page

* fix(frontend): show rule count in compact view mode for forward pages

* style(frontend): format code and improve node card layout

Entire-Checkpoint: 08b760b76538

* fix: restore renewal.ts from main to resolve build errors
2026-03-09 10:01:55 +08:00
sagit 413081f72a feat(nodes): add renewal cycle and auto-advance scheduling (#296)
- Add renewal_cycle field to nodes for tracking paid vs free cycles
- Implement auto-advance scheduling when renewal is processed
- Add migration test for renewal_cycle column
- Update dashboard to show renewal cycle count
- Add renewal status display on node detail page
2.1.8-alpha4
2026-03-08 22:05:25 +08:00
sagit 508a37a84c feat(nodes): add node metadata and expiry reminders (#293)
## Summary

- 为节点新增备注、标签、到期时间字段,并贯通后端存储、导入导出与前端 API
- 节点管理页支持编辑、搜索、筛选并高亮即将到期或已过期节点
- Dashboard 为管理员新增节点到期提醒卡片,集中展示 7 天内到期和已过期节点

## Changes

### Backend
- `node/create` 和 `node/update` 支持 `remark`、`tags`、`expiryTime`
- 节点列表接口返回新增字段
- 节点导入导出保留备注、标签与到期时间

### Frontend
- 节点页面新增备注、标签、到期时间表单项
- 节点列表支持按备注/标签搜索,并支持到期状态筛选
- 节点卡片展示备注、标签、到期时间以及过期提醒样式
- Dashboard 管理员视图新增节点到期提醒模块

## Plans

- `plans/021-node-remarks-tags-expiry.md`
- `plans/022-node-expiry-highlights-dashboard-reminders.md`

## Issue

Closes #246
2.1.8-alpha3
2026-03-08 20:02:36 +08:00
sagitchu d60655045a feat(forward): display tunnel traffic ratio on forward page 2026-03-08 20:00:26 +08:00
sagitchu 31ef861504 feat(nodes): add node metadata and expiry reminders (#246)
Entire-Checkpoint: d8b429492cbe
2026-03-08 19:44:46 +08:00
sagitchu f1bdb2e2ef feat(frontend): implement AJAX no-refresh UX improvements (#276)
- Add dashboard auto-refresh with 5s polling and visibility-aware pause
- Harden node realtime reconnection with exponential backoff and polling fallback
- Implement local state patching for forward/tunnel/user mutations
- Add batch operation progress feedback UI
- Add shared list-state helpers for replace/remove operations
- Preserve derived UI state during server payload merges

Closes #276

Entire-Checkpoint: 7d6188355d7f
2026-03-08 19:15:02 +08:00
Su-cyber-art 61b71a11c7 feat(node): split node page into local and remote sections 2026-03-08 18:45:56 +08:00
Su-cyber-art 4c69ff491d feat(node): render remote usage details on remote node cards
(cherry picked from commit 67294fa76422f994de8d95ec88f8f03e02ea6b9f)
2026-03-08 18:42:40 +08:00
Su-cyber-art 0ad4904e20 feat(node): split local and remote nodes into separate tabs
(cherry picked from commit 30793b2997040dd29ff5fe6397d0bcab174ecc9e)
2026-03-08 18:42:36 +08:00
sagit bd30b61018 fix(backend): migrate PostgreSQL traffic columns from int4 to bigint (#290)
## Summary

- Widens legacy PostgreSQL traffic/quota columns from `integer` to
`bigint` to prevent int4 overflow
- Fixes federation share creation failure when traffic limits exceed 2GB
(e.g., `536870912000` bytes = 500GB)
- Bumps schema version from 4 to 5 with auto-migration on backend
startup

## Affected Tables

- `user`: `flow`, `in_flow`, `out_flow`
- `forward`: `in_flow`, `out_flow`
- `statistics_flow`: `flow`, `total_flow`
- `tunnel`: `flow`
- `user_tunnel`: `flow`, `in_flow`, `out_flow`
- `peer_share`: `max_bandwidth`, `current_flow`

## Test Plan

- ✅ Unit tests added for migration execution and error handling
- ✅ Contract tests passed
- ✅ Repository tests passed

Commands:
```bash
cd go-backend && go test ./internal/store/repo/...
cd go-backend && go test ./tests/contract/...
```
2.1.8-alpha2
2026-03-08 11:50:14 +08:00
sagitchu e0dd70a054 fix(backend): migrate PostgreSQL traffic columns from int4 to bigint
Widens legacy PostgreSQL traffic/quota columns to BIGINT to prevent
int4 overflow when storing large values like 536870912000 (500GB).

Affected tables:
- user (flow, in_flow, out_flow)
- forward (in_flow, out_flow)
- statistics_flow (flow, total_flow)
- tunnel (flow)
- user_tunnel (flow, in_flow, out_flow)
- peer_share (max_bandwidth, current_flow)

Schema version bumped from 4 to 5 with auto-migration on startup.
2026-03-08 11:48:36 +08:00
sagit 4966a8aad1 fix(backend): sync user tunnel status and relax forward speedId permission check (#288)
## Summary

- Return actual `user_tunnel.status` in admin permission list instead of
hardcoded enabled state (1)
- Allow non-admin users to update forwards when keeping the same
`speedId` selection
- Add contract tests for user tunnel status mapping and forward
permission edge case

## Test Plan

- [x] Contract tests pass: `cd go-backend && go test
./tests/contract/...`
- [x] User tunnel permission list returns correct status values
(enabled/disabled)
- [x] Non-admin users can update forward details when keeping existing
speedId
2.1.8-alpha1
2026-03-08 00:57:57 +08:00
sagitchu 3e11549370 fix(backend): sync user tunnel status and relax forward speedId permission check
- Return actual user_tunnel.status in admin permission list instead of hardcoded 1
- Allow non-admin users to update forwards when keeping the same speedId selection
- Add contract tests for user tunnel status mapping and forward permission edge case

Entire-Checkpoint: deb90fb942ee
2026-03-08 00:56:13 +08:00
sagit addf83a249 fix(ui): improve date input parsing and add missing back navigation (#284)
## Summary
- Improve DatePicker text parsing to accept more input formats
(including `YYYYMMDD`) without requiring explicit separators
- Add missing H5 back-navigation for panel-sharing by using simple
layout route
- Add a back button on config page with history fallback (`navigate(-1)`
then `/profile`)

## Why
These are usability/accessibility improvements that are generic and not
project-brand specific:
- Mobile keyboards may not easily input `-` in date fields
- Certain pages in H5 lacked a consistent return path
- Config page had no explicit in-page back action

## Scope
- `vite-frontend/src/shadcn-bridge/heroui/date-picker.tsx`
- `vite-frontend/src/App.tsx`
- `vite-frontend/src/pages/config.tsx`

## Notes
No branding/identity/ownership/visual-theme customizations included in
this PR.
2.1.7
2026-03-07 18:07:07 +08:00
sagitchu c3e35fd416 fix(ui): tighten date parsing and back navigation
Entire-Checkpoint: fea62b38d8c7
2026-03-07 18:02:00 +08:00
sagit 775dfe19f1 Merge branch 'main' into fix/upstream-friendly-ui-3pack 2026-03-07 17:36:29 +08:00
sagit db3b2f651b fix: improve bind-conflict detection and forward cleanup reliability (#287)
## Summary
- Normalize whitespace in bind-conflict error messages to handle
collapsed variants (e.g., "address alreadyin use")
- Update forward cleanup to delete all service name variants (_tcp,
_udp, base) instead of stopping after first success
- Add comprehensive test coverage for edge cases with missing-space
error variants

## Test plan
- ✅ Unit tests: `cd go-backend && go test ./internal/http/handler/...`
- ✅ Contract tests: `cd go-backend && go test ./tests/contract/... -run
'TestForwardUpdateRecoversFromAddressInUseContract|TestTunnelUpdateRecoversFromAddressInUseContract'`
2.1.7-rc10
2026-03-07 17:21:00 +08:00
sagitchu 669323f926 fix: improve bind-conflict detection and forward cleanup reliability
- Normalize whitespace in error messages to handle collapsed variants (e.g., 'address alreadyin use')
- Delete all forward service name variants (_tcp, _udp, base) during cleanup instead of stopping after first success
- Add comprehensive test coverage for edge cases
2026-03-07 17:19:28 +08:00
𝓐𝓵𝓽𝓲𝓸𝓷 7202b69e4e Merge branch 'main' into fix/upstream-friendly-ui-3pack 2026-03-07 17:00:31 +08:00
sagit 31977a62e6 fix: add retry mechanism for tunnel service bind conflicts (#286)
## Summary
- Add retry logic for tunnel service creation/update when encountering
"address already in use" bind errors
- Automatically cleanup stale service and retry once before failing
- Add comprehensive unit and contract tests for bind conflict scenarios

## Changes
- `mutations.go`: Add `retryTunnelServiceAddWithCleanup` helper and
`addTunnelServiceOnNode` wrapper
- `control_plane_test.go`: Unit tests for retry behavior on address
conflicts
- `dual_stack_test.go`: Test fallback to node listen address
- `forward_contract_test.go`: Contract test for forward update with bind
retry
- `limiter_sync_failure_contract_test.go`: Contract test for tunnel
update with bind retry
- `plans/016-tunnel-runtime-bind-conflict-retry.md`: Implementation plan
document

## Test Plan
- Unit tests verify retry logic executes correctly
- Contract tests validate end-to-end behavior with mock nodes
- All tests pass with race detector enabled
2.1.7-rc9
2026-03-07 16:23:13 +08:00
sagitchu 87479c2ac1 fix: add retry mechanism for tunnel service bind conflicts
When tunnel services encounter 'address already in use' errors during
creation/update, automatically cleanup and retry once instead of failing
immediately. This handles race conditions during rapid tunnel reconfiguration.

Entire-Checkpoint: 39e6fb9de836
2026-03-07 16:21:44 +08:00
Su-cyber-art ffda0fb71a fix(ui): improve date input parsing and add missing back navigation 2026-03-07 14:19:23 +08:00
sagit 9c0e7341c3 feat: add helpful hints for form fields in tunnel and node management (#279)
Entire-Checkpoint: 20cc01a9700d
2026-03-06 08:21:19 +00:00
sagit 1db5452be9 fix: add forward port occupancy validation and runtime residual cleanup (#278)
* fix: tolerate service not found during forward deletion

- Refactor deleteForwardServicesOnNode to handle not-found errors gracefully
- Extract deleteForwardServiceCandidates helper for reuse
- Add tests for not-found tolerance scenarios
- Ensures compatibility with legacy node versions

Entire-Checkpoint: a3bacf836c57

* fix: add forward port occupancy validation and runtime residual cleanup

- Add forward port occupancy validation on create/update paths
- Extend self-occupy recovery to clean residual candidate service names
- Add regression tests for address-in-use recovery with legacy runtime residue

Fixes port conflict issues when upgrading from 2.1.6 to later versions

Entire-Checkpoint: fb0a2aee4cb5
2.1.7-rc8
2026-03-06 10:57:07 +08:00
sagit c10f894afd fix: tolerate service not found during forward deletion (#277)
- Refactor deleteForwardServicesOnNode to handle not-found errors gracefully
- Extract deleteForwardServiceCandidates helper for reuse
- Add tests for not-found tolerance scenarios
- Ensures compatibility with legacy node versions

Entire-Checkpoint: a3bacf836c57
2.1.7-rc7
2026-03-06 09:03:28 +08:00
sagit 7fb75baa73 feat: allow user custom inport with range validation (#274)
## Summary
- Allow users to specify custom inlet ports within a defined range
- Add port range validation for tunnel configurations
- Implement UI controls for custom port selection
- Add contract tests for custom port functionality
2.1.7-rc6
2026-03-05 17:04:58 +08:00
sagitchu 15e6cd69eb feat: allow user custom inport with range validation
Entire-Checkpoint: fcd76aac10e9
2026-03-05 17:03:19 +08:00
sagit f6eb88d75e refactor: 统一术语,将'转发'改为'规则' (#273)
- 更新所有页面中的'转发'术语为'规则'
- 统一UI文案,提升用户体验一致性
- 关联 #269 #271

Entire-Checkpoint: 5646e42aa33b
2.1.7-rc5
2026-03-05 15:07:42 +08:00
sagit f45b580984 fix: prevent effect execution when forwards list is empty (#272)
## Summary
- 添加空列表检查,防止在forwards为空时执行effect
- 避免不必要的groupOrder状态更新和持久化操作
2026-03-05 14:09:19 +08:00
sagitchu 4f50c47550 fix: prevent effect execution when forwards list is empty
Entire-Checkpoint: 69eeade13bf9
2.1.7-rc4
2026-03-05 14:07:25 +08:00
sagit 2e1d75dc36 fix: add self-healing for forward service name migration (#270)
## Summary
- Fix `service not found` errors when upgrading from older versions
where service names migrated from placeholder IDs (`forward_user_0`) to
real `user_tunnel_id`
- Add fallback cleanup+rebuild logic on `UpdateService` when service not
found during upgrade transition
- Add self-healing retry on `Pause/Resume` operations when all service
variants are missing
- Refactor `controlForwardServicesOnNode` to support unit testing
- Add tests for the new helper functions

## Test plan
- [x] Unit tests pass: `cd go-backend && go test
./internal/http/handler/...`

## Upgrade path
1. Deploy this backend patch first (no need to wait for all agents)
2. Gradually upgrade agents in batches (10-20%)
3. Run "forward batch redeploy" after each batch to unify service naming
4. Monitor logs for `service .* not found` errors
2.1.7-rc3
2026-03-05 12:42:04 +08:00
sagitchu f496f58a4d fix: add self-healing for forward service name migration
When upgrading from older versions, service names changed from
placeholder IDs (forward_user_0) to real user_tunnel IDs, causing
service not found errors during control operations.

- Add fallback cleanup+rebuild logic on UpdateService when service
  not found during the upgrade transition period.
- Add self-healing retry on Pause/Resume when all variants are missing.
- Refactor controlForwardServicesOnNode to support unit testing.
- Add tests for shouldSelfHealForwardServiceControl and
  controlForwardServiceCommand helper functions.

Entire-Checkpoint: a7f0c3175d06
2026-03-05 12:40:20 +08:00
sagit 32474bec20 fix: resolve user tunnel early to use real ID in service name (#265)
## Summary
- Fix service name generation to use the actual user_tunnel ID instead
of 0
- Move user tunnel resolution before building service base name
- Add `buildForwardServiceBaseWithResolvedUserTunnel` helper function

## Details
Previously, the service base name was built with `userTunnelID=0` before
the actual user tunnel was resolved. This caused the runtime service
name to not carry the real user_tunnel ID.

The fix resolves the user tunnel early and passes the resolved ID to the
service name builder, ensuring proper service identification.
2.1.7-rc2
2026-03-04 19:35:47 +08:00
sagitchu 581cda7edc fix: resolve user tunnel early to use real ID in service name
- Move user tunnel resolution before building service base name
- Add buildForwardServiceBaseWithResolvedUserTunnel helper
- Ensure service names carry the actual user_tunnel ID instead of 0

Entire-Checkpoint: 9559e6447fda
2026-03-04 19:34:16 +08:00
sagit 96aebb8d61 fix: handle drag-and-drop order correctly in compact mode (#264) 2.1.7-rc1 2026-03-04 16:49:03 +08:00
sagit 735fd40786 fix: correct SortableContext nesting for table drag-and-drop (#263)
## Summary
- Fixed incorrect nesting of SortableContext component in forward table
- Moved SortableContext wrapper to properly wrap the entire Table
component instead of wrapping individual rows
- This ensures drag-and-drop functionality works correctly with the
table structure
2026-03-04 16:01:38 +08:00
sagitchu a3b0bf4898 fix: correct SortableContext nesting for table drag-and-drop
Entire-Checkpoint: 356ceb26d6bc
2026-03-04 16:00:07 +08:00
sagit 9703e4a081 feat: restrict user permissions and multi-node IP constraints (#262)
* feat: restrict user permissions and multi-node IP constraints

- Non-admin users cannot set speedId or inPort on forward create/update
- Multi-entrance tunnels disable custom listen IP for forwards
- Multi-exit tunnels disable custom connect IP
- Multi-node hop chains disable custom connect IP per hop
- Remove tunnel-first-IP fallback in forward ingress resolution
- Add contract tests for non-admin permission restrictions

Entire-Checkpoint: 133693290660

* fix: allow non-admin users to submit null speedId and zero inPort

- Backend: Check speedId is not nil before rejecting non-admin requests
- Backend: Only reject inPort if value > 0 for non-admin users
- Frontend: Only include speedId and inPort in payload for admin users
- Tests: Add contract tests for null speedId and zero inPort cases

* refactor: simplify forward mutation payload construction
2.1.7-beta8 2.1.7-beta9
2026-03-04 15:05:05 +08:00
sagit a43653f252 fix: permission checks for speedId and inPort + multi-node IP constraints (#261)
* feat: restrict user permissions and multi-node IP constraints

- Non-admin users cannot set speedId or inPort on forward create/update
- Multi-entrance tunnels disable custom listen IP for forwards
- Multi-exit tunnels disable custom connect IP
- Multi-node hop chains disable custom connect IP per hop
- Remove tunnel-first-IP fallback in forward ingress resolution
- Add contract tests for non-admin permission restrictions

Entire-Checkpoint: 133693290660

* fix: allow non-admin users to submit null speedId and zero inPort

- Backend: Check speedId is not nil before rejecting non-admin requests
- Backend: Only reject inPort if value > 0 for non-admin users
- Frontend: Only include speedId and inPort in payload for admin users
- Tests: Add contract tests for null speedId and zero inPort cases
2026-03-04 14:50:36 +08:00
sagit 348900de01 feat: restrict user permissions and multi-node IP constraints (#260)
- Non-admin users cannot set speedId or inPort on forward create/update
- Multi-entrance tunnels disable custom listen IP for forwards
- Multi-exit tunnels disable custom connect IP
- Multi-node hop chains disable custom connect IP per hop
- Remove tunnel-first-IP fallback in forward ingress resolution
- Add contract tests for non-admin permission restrictions

Entire-Checkpoint: 133693290660
2026-03-04 14:04:22 +08:00
sagit b93c259fac fix: preserve speed_limit and auto_clear when saving forwards and user tunnels (#259)
## Summary
- Add `speed_limit` and `auto_clear` fields to forward update mutation
to prevent data loss on save
- Update user tunnel save mutation to preserve these fields when editing
tunnels
- Add contract test to verify forward save preserves `speed_limit`
- Add plan documents (006, 007, 008) tracking the fix

## Changes
- `go-backend/internal/http/handler/mutations.go`: Add missing fields to
forward and user tunnel update logic
- `go-backend/tests/contract/forward_contract_test.go`: Add test case
for speed_limit preservation
- `vite-frontend/src/pages/forward.tsx`: Pass speed_limit and auto_clear
on save
- `vite-frontend/src/pages/user.tsx`: Pass speed_limit and auto_clear on
user tunnel save
2.1.7-beta6
2026-03-03 22:11:05 +08:00
sagitchu 2e3d5c9249 fix: preserve speed_limit and auto_clear when saving forwards and user tunnels
- Add speed_limit and auto_clear fields to forward update mutation
- Update user tunnel save to preserve these fields
- Add contract test for forward save preserving speed_limit
- Add plan documents for the fixes
2026-03-03 22:10:33 +08:00
sagit c8c1841058 feat: forward enhancements and auto-fallback for invalid bind IP (#258)
## Summary

This PR introduces comprehensive enhancements to the forward service
management system, including:

- **Auto-fallback for invalid bind IP**: When a forward service is
updated with a bind IP that doesn't exist on the host network
interfaces, the system automatically falls back to the default bind
address (listening on all interfaces) instead of failing. Users receive
warning toasts when fallback occurs.

- **Bind IP preservation**: Forward services now preserve their explicit
bind IP when editing without explicit inIp changes.

- **Port rebind handling**: Fixed forward service rebind when the port
is self-occupied by updating instead of adding.

- **NY format import support**: Added support for importing forwards in
NY format with node-based tunnel matching and auto port assignment.

- **Custom IP selection**: Enabled custom IP selection for nodes,
tunnels, and forwards with proper UI controls.

- **Compact mode**: Added global compact mode for forward list with
alpha8 layout and tunnel-group collapse/ordering.

## Changes

### Backend
- Added `syncForwardServicesWithWarnings` to collect fallback warnings
- Implemented `fallbackForwardPortToDefaultBind` for graceful
degradation
- Added `UpdateForwardPortBindIP` repository method to persist fallback
- Enhanced error detection for 'cannot assign requested address' errors
- Fixed bind IP preservation during forward edits
- Fixed port rebind on self-occupied addresses

### Frontend
- Added warning toast display when bind IP fallback occurs
- Implemented IP selection dropdowns for tunnels and forwards
- Added compact mode toggle in settings
- Enhanced forward list with tunnel-group collapse and drag sorting

### Tests
- Added comprehensive unit tests for error detection functions
- Added migration tests for legacy columns

## Commits Since Last Merge
- feat: auto-fallback to default bind IP when invalid bind address
detected
- fix: handle forward service rebind on self-occupied port
- fix: preserve bind IP when editing forward without explicit inIp
change
- feat: add ny import compatibility with auto port assignment
- refactor: simplify forward import tunnel selection
- feat: add ny format support for forward import with node-based tunnel
matching
- feat: custom IP selection and connectIp diagnosis fixes
- feat: add comprehensive migration test for legacy columns
- feat: add custom IP selection for nodes, tunnels, and forwards
- feat(forward): support tunnel-group collapse and ordering in full mode
- feat(forward): add global compact mode with alpha8 list layout
2.1.7-beta5
2026-03-03 21:34:49 +08:00
sagitchu 1c596fae4b feat: auto-fallback to default bind IP when invalid bind address detected
When a forward service is updated with a bind IP that doesn't exist on the
host network interfaces, the system now automatically falls back to the
default bind address (listening on all interfaces) instead of failing.

- Added syncForwardServicesWithWarnings to collect fallback warnings
- Implemented fallbackForwardPortToDefaultBind for graceful degradation
- Added UpdateForwardPortBindIP repository method to persist fallback
- Enhanced error detection for 'cannot assign requested address' errors
- Frontend displays warning toasts when fallback occurs
- Added comprehensive unit tests for new error detection functions
2026-03-03 21:34:12 +08:00
sagit 2ff52e3275 feat: 2.1.7-beta4 release - forward service stability and UI enhancements (#257)
## Summary

This PR consolidates multiple features and fixes for the 2.1.7-beta4
release:

**Forward Service Stability:**
- Handle forward service rebind on self-occupied port conflicts
- Preserve bind IP when editing forward without explicit inIp change

**Import Enhancements:**
- Add ny format support for forward import with node-based tunnel
matching
- Add ny import compatibility with auto port assignment

**Custom IP Selection:**
- Add custom IP selection for nodes, tunnels, and forwards
- Use configured connectIp for tunnel chain diagnosis

**UI Improvements:**
- Add tunnel group collapse and drag sorting in full mode
- Add global compact mode with alpha8 list layout
- Expose forward compact mode switch in settings

**Infrastructure:**
- Add comprehensive migration test for legacy columns

## Commits

- 7efb49b fix: handle forward service rebind on self-occupied port
- 1450b25 fix: preserve bind IP when editing forward without explicit
inIp change
- 7c54192 feat: add ny import compatibility with auto port assignment
- 7ba6877 refactor: simplify forward import tunnel selection
- ef613c1 feat: add ny format support for forward import with node-based
tunnel matching
- 1c10347 fix: use configured connectIp for tunnel chain diagnosis
- e383359 fix: apply custom IP binding to forward and tunnel chain
services
- 9cf9f4f feat: add comprehensive migration test for legacy columns
- b819341 feat: add custom IP selection for nodes, tunnels, and forwards
- 634c6cd feat(forward): add tunnel group collapse and drag sorting in
full mode
- 98a9e5c fix(config): expose forward compact mode switch in settings
- 77e4387 feat(forward): add global compact mode with alpha8 list layout
2.1.7-beta4
2026-03-03 20:54:26 +08:00
sagitchu 7efb49bdab fix: handle forward service rebind on self-occupied port
When UpdateService encounters bind address conflicts (port already in use),
the handler now automatically deletes existing forward services and retries
the AddService operation. This resolves issues where a forward's own stale
listener prevents the update.

- Add isBindAddressInUseError() to detect port bind conflicts
- Add rebindForwardServiceOnSelfOccupiedPort() for automatic cleanup and retry
- Add HasOtherForwardOnNodePort() repository method to verify port ownership
- Add unit tests for bind conflict detection
2026-03-03 20:53:55 +08:00