- 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
- 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
- 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
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
* 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
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
- 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
- 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
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
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
- Add replaceForwardPortsPreservingInIP to maintain existing InIP values
- Track inIpTouched state in frontend to distinguish user changes
- Only send inIp in update request when user explicitly changed it
- Add unit tests for forward port replacement with preserved InIP
- Support optional listen_port field for automatic port assignment
- Add alias field mapping (dest/dst/target, listenPort/port, name/forward_name)
- Update help text to document auto port assignment
- Add parser tests for alias fields and missing port handling
Entire-Checkpoint: efae74a1f03c
- Pass connectIp through resolveChainProbeTarget in diagnosis stream start items
- Pass connectIp in appendChainHopDiagnosis for full chain probes
- Reconstruct tunnel state with connectIp field preserved
- Fix forward service config when bindIP already contains port
- Add contract tests for connectIp diagnosis scenarios
- Add unit test for bindIP with port in buildForwardServiceConfigs
- Update AGENTS.md with plan document rules
Entire-Checkpoint: 35a2e61c2431