## Summary
- Add backend display-state snapshots and response enrichment for best
multi-exit tunnels.
- Surface direct-entry and final-chain-hop owner choices, including
waiting, partial, multi-exit, and stale-exit safeguards.
- Render compact current best-exit text in tunnel table/card views with
native tooltip details.
## Test Plan
- [x] `rtk go test ./...` from `go-backend`
- [x] `pnpm run build` from `vite-frontend`
## Summary
- Prune stale agent traffic counters when services are deleted or config
is reloaded.
- Ignore late traffic updates from services no longer registered, while
preserving pending bytes until the next report flush.
- Add regression tests for stale traffic cleanup and
report-before-delete behavior.
## Test Plan
- rtk go test ./service
- rtk go test ./service ./socket ./api
- rtk go test ./...
- CGO_ENABLED=0 rtk go build .
- rtk git diff --check
## Summary
- Add the design spec for monitoring retention and storage display.
- Add the implementation plan used for the monitoring retention feature.
## Test Plan
- Documentation-only change; no runtime tests required.
## Summary
- Add configurable monitoring retention days for node metrics, tunnel
metrics, service monitor results, and tunnel quality history.
- Add an admin-only storage summary endpoint and show database usage on
the config page.
- Keep tunnel quality cleanup active even when real-time quality probing
is disabled.
## Test Plan
- go test ./... (go-backend)
- pnpm run build (vite-frontend)
## Summary
- Add the completed per-IP rule limits implementation plan to docs.
- Mark all task steps complete and reference PR #479 plus tag
3.0.0-beta2.
## Test Plan
- [x] Verified no unchecked plan step boxes remain
- [x] Reviewed docs diff for accidental secrets or unrelated content
## Summary
- Add per-forward per-IP connection and bandwidth limit fields across
backend persistence, APIs, backup/list paths, and the forward rule form.
- Sync per-IP runtime limiter payloads to GOST while preserving shared
user/total limiter semantics through composite limiter references.
- Add GOST/x coverage and UDP listener support for per-client limiters
without breaking packet semantics.
## Test Plan
- [x] `rtk go test ./...` in `go-backend` (392 passed)
- [x] `rtk go test ./...` in `go-gost/x` (42 passed)
- [x] `pnpm run build` in `vite-frontend`
## Notes
- Existing total `maxConn`/`speedId` behavior is preserved; per-IP
limits are additive.
- Normal users cannot set or modify per-IP bandwidth rules.
* fix: reduce reconnect redeploy and metrics load
Throttle node-online redeploy retries and lower the agent metric cadence so brief reconnect churn no longer fans out into repeated runtime syncs and backend connection pressure.
* docs: add follow-up implementation design notes
Document the planned flow upload batching work and the local remote-address toggle so the next changesets can implement them against an agreed design.
* docs: add implementation plan for max conn limit
* feat: add CLimiters support for websocket reporter
* feat: add max_conn field to user and forward models
* feat: implement max conn limiter dispatching
* feat: add maxConn to user and forward CRUD API
* feat: add max conn UI to user management and forward rules
* fix: load MaxConn in get forward record and add e2e contract test for max conn limit
- Fix KCP tunnel not reclaimed after deletion: service name was
hardcoded to {id}_tls but services were created as {id}_kcp,
causing DeleteService to never find the actual KCP service.
Now reads tunnel.Protocol from DB and derives correct name.
- Fix KCP diagnosis using TCP ping instead of UDP ping:
tunnel.Protocol was always hardcoded to 'tls' at creation,
so isUDPBasedProtocol() never matched kcp tunnels. Now
stores the actual protocol from entry node configuration.
- Fix addTunnelServiceOnNode to extract service name from
serviceData instead of hardcoding _tls suffix.
- Fix rollbackTunnelRuntime to accept protocol parameter
so retry cleanup uses correct service name.
- UpdateTunnelTx now persists protocol on tunnel updates.
- controlForwardServices: skip offline nodes instead of failing entire operation,
so forward pause/resume/delete works when some entry nodes are offline
- onNodeOnline: always sync forward state on node reconnect (not just post-upgrade),
so forwards that changed status while a node was offline get synced
- add ListForwardIDsByNode repo method to sync all forwards (including paused)
- tunnel edit UI: allow deselecting already-selected offline nodes in
entry/chain/exit selectors, matching the backend's existing tolerance
- KCP: switch from fast3 to fast2 mode, enable FEC (10/3), enable
congestion control (nc=0) for automatic rate adaptation
- go-gost/x: support kcp.nc metadata to override mode-initialized
NoCongestion value in dialer and listener Init()
- Diagnosis: add udpPingViaRemoteNode, fix pingViaRemoteNode to
dispatch based on protocol, add Protocol field to federation
diagnose request structs
Replace read-then-subtract pattern in collectAndReport with atomic
swap-to-zero to eliminate race where AddTraffic increments counters
between snapshot and clearReportedTraffic, causing residual traffic
to accumulate indefinitely and inflate user flow counters.
Also add defensive check in processFlowItem to skip AddFlow when
forward no longer exists, and send DeleteService to clean up orphaned
agent services.
Change overflow-hidden to overflow-auto in table wrapper classNames
across all list pages (rules, tunnels, nodes, limits, groups, users,
monitor views). Also add table-fixed min-w to forward all-rules table
and fix unescaped entities in dashboard.
- Pass tunnel protocol through diagnosis work items
- Support protocol-specific ping (TCP/UDP/KCP) via remote nodes
- Add KCP probe support in websocket_reporter for chain hop testing
- Increase dropdown menu padding from p-1 to p-1.5
- Hide scrollbar in dropdown-menu-content and select listbox
- Change login page input bg from white/50 to white/10 for transparency
The metadata parser unconditionally assigned GetInt results (which
return 0 for missing keys) to all KCP config fields, overwriting
defaults like SndWnd=1024, RcvWnd=1024, StreamBuf=2097152 with 0.
KCP's WndSize only applies positive values, so snd_wnd=0 caused
the write path condition waitsnd < s.kcp.snd_wnd to never succeed,
effectively stalling throughput at ~10Mbps instead of 400Mbps+.
- Only apply metadata values when the key actually exists (IsExists check)
- Use Clone() instead of sharing the global DefaultConfig pointer
- Add Config.Clone() deep-copy method
- Add adaptive solid color background support for dark/light themes.
- Replace mesh gradient with semi-transparent blurred background images.
- Fix background scrolling issue on mobile browsers.
- Remove borders from specific cards for consistent UI styling.
- Prevent caching of PWA service worker files in Nginx.
- Introduce interactive toast prompt for PWA updates instead of silent refresh.
* docs: add announcement popup design spec
* docs: add announcement popup implementation plan
* fix(ui): change modal scroll behavior to inside for mobile screens
Fixes layout issue where modal footer and action buttons are pushed off screen on mobile devices.
- Wrap `Routes` with `AnimatePresence` to enable framer-motion page transition exit animations and fix harsh route changes.
- Replace `tw-animate-css` with `tailwindcss-animate` to properly bundle transition classes (like `animate-in`, `animate-accordion-down`) under Tailwind v4.
- This restores animation to modals, accordions, and all page navigations.
- Fix accessibility warning on table cell span element.
Fixes#283
## Summary
- Extracted the `expiry` attribute from Keygen's `ValidateResponse`.
- Updated `licenseActivate` and `validateLicenseJob` to store
`license_expiry` in the database.
- Read `license_expiry` into the frontend `siteConfig` map.
- Updated the description in the commercial license input to dynamically
show the expiry date: '已激活商业版授权 (有效期至: YYYY-MM-DD)' or '已激活商业版授权 (永久有效)'
if it doesn't expire.
## Summary
- Conditionally render brand settings (`app_name`, `app_logo`,
`app_favicon`, `hide_footer_brand`) inside the Commercial License card.
- Hide them from the main Basic Settings list.
- Only show these options if the user has successfully activated a
commercial license.
## Summary
- Display the tunnel's traffic ratio in the forward (rules) list UI to
save administrators an extra click to the tunnels page.
- Resolves #forward-show-tunnel-ratio
## Changes
- Updated the table row in `forward.tsx` to show the traffic multiplier.
- It will only display when the ratio is not `1x` to prevent UI clutter.
- The backend `forwardList` API was already returning `trafficRatio`
from a `LEFT JOIN tunnel`, so no backend modifications were required.
## Summary
- Moved `tx := h.repo.BeginTx()` below `applyFederationRuntime` in
`tunnelUpdate`
- This prevents the database transaction from remaining idle for an
extended period of time while making HTTP network requests to federation
nodes, which can trigger the `idle_in_transaction_session_timeout` or
cause connection pool exhaustion in PostgreSQL.
## Test Plan
- [x] Backend tests passed (`go test ./...`)
- [ ] Verify tunnel updates no longer timeout with PostgreSQL
## Summary
- randomize auto-assigned ports only for newly created tunnel relay and
exit nodes
- keep tunnel updates stable while tightening batch forward
tunnel-switch validation
- update contract coverage for deferred offline runtime handling and
missing entry-node fixtures
## Test Plan
- go test ./... -count=1
* docs: add floating save button design spec for issue #266
* docs: add implementation plan for floating save button
* feat(config): add floating save button (FAB) for issue #266
When user traffic quota is exceeded, services are paused with
ForceClosePortConnections to kill active connections. However,
when admin resets quota and resumes services, the resume logic
was missing this cleanup, causing "address already in use" errors.
Changes:
- Add ForceClosePortConnections call in resumeServices (socket & api)
- Add ForceClosePortConnections call in resumeService (api single)
- Increase wait time from 100ms to 500ms for port release
Fixes#387
- Add missing interfaceName field to node list API response map
- Fixes bug where interface name value disappears after page refresh
- Field is correctly saved to DB but was not returned in API response
Co-authored-by: Alex-WU-Gen-9-png <github@enomria0785.eu.org>
## Summary
- add a global settings toggle to enable or disable real-time tunnel
quality detection
- stop frontend tunnel quality polling and related status UI when the
toggle is off
- gate the backend tunnel quality prober so disabling the setting also
stops server-side probing
## Test plan
- [x] cd go-backend && go test ./...
- [x] cd vite-frontend && npm run build
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Allow admins to disable real-time tunnel quality probing from settings so the monitor UI and backend probe loop stop together.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Fixed OID 25 (text) inference failing to encode int64 by embedding the
node ID format string directly. Replaced CAST(x AS INTEGER) with CAST(x
AS BIGINT) to prevent 32-bit overflow on Unix milliseconds timestamps.
# Please enter a commit message to explain why this merge is necessary,
# especially if it merges an updated upstream into a topic branch.
#
# Lines starting with '#' will be ignored, and an empty message aborts
# the commit.
## Summary
- Add comprehensive monitoring system with
NodeMetric/TunnelMetric/ServiceMonitor models
- Implement metrics ingestion service with per-minute bucket aggregation
and upsert support
- Add health checker for node connectivity monitoring with configurable
intervals
- Wire node metrics from WebSocket SystemInfo messages to metrics
service
- Add tunnel metrics ingestion from flow upload endpoint with
transaction support
- Create monitoring REST API endpoints for nodes, tunnels, and services
- Implement service monitor CRUD and execution (TCP/ICMP health checks)
- Add MonitorPermission model for non-admin access control to monitoring
features
- Create frontend monitor page with node/tunnel/service views
- Include schema migration (v6) for tunnel_metric unique index and
deduplication
- Fix tunnel entry port conflict validation to use transaction (Tx
variants)
- Add missing 'uptime' field to NodeMetricApiItem type definition
- Fix WS message handling: non-UpgradeProgress typed messages now
broadcast via broadcastInfo instead of being silently dropped
- Strengthen looksLikeSystemInfoMessage heuristic to require ≥3
matching keys to avoid false positives
- Fix tab/space indentation inconsistency in admin.tsx useEffect
- Remove duplicate method declarations from merge (repository_control,
mutations)
- Update tunnel_entry_sqlite_test to use renamed Tx suffix function
- Add backend API for tunnel delete rule resolution (allow, deny, confirm)
- Add contract tests for delete resolution endpoint
- Add frontend API types and endpoints for delete resolution
- Add tunnel delete resolution settings UI with resolution mode selector
- Support per-tunnel and global delete resolution configuration
- Fix deadlock when updating tunnel entries with offline nodes
- Add test file for tunnel entry SQLite operations
- Update contract tests for entry port conflict and limiter sync
- Add plan documents for SQLite deadlock fix and contract semantics
- Add NodeMetric/TunnelMetric/ServiceMonitor models and repository methods
- Implement metrics ingestion service with per-minute bucket aggregation
- Add health checker for node connectivity monitoring
- Wire node metrics from WebSocket SystemInfo messages
- Add tunnel metrics ingestion from flow upload endpoint
- Create monitoring REST API endpoints for nodes, tunnels, services
- Implement service monitor CRUD and execution (TCP/ICMP checks)
- Add MonitorPermission for non-admin access control
- Create frontend monitor page with node/tunnel/service views
- Add tunnel metrics ingestion from agent flow reports
- Include schema migration for tunnel_metric unique index
- Fix tunnel entry port conflict validation to use transaction
Entire-Checkpoint: 030821a7c8e3
Restore the 2.1.8-beta9 style of displaying node remark and renewal
info via an info button (ℹ️) in the CardHeader with a hover popover,
instead of inline display in the CardBody.
- Add infoPopoverPlacement state and updateInfoPopoverPlacement callback
- Add info button with hover popover showing expiry reminder and remark
- Restore drag handle with touch support and responsive visibility
- Remove inline info display from CardBody
## Summary
- Fix TypeError "renderCard is not a function" when using non-compact
card view mode on the rules page
- The `SortableForwardCard` component was missing the required
`renderCard` prop in the non-compact grouped view
- Add isIndeterminate support to Checkbox component
- Use showAddressModal in SortableTableRow for multi-address display
- Remove unused onClose parameter in search modal
- Remove unused infoPopoverPlacement and related code in node.tsx
- Merge entry address:port into single '入口' column
- Merge target address:port into single '目标' column
- Remove separate port columns from compact table
- Keep UI improvements: always show checkbox, selection highlight
- Add BatchOperationFailure type import
- Add BatchActionResultModal component import
- Add BatchResultModalState interface and empty state constant
- Add batchResultModal state
- Add presentBatchOutcome callback for unified batch operation result handling
- Update handleBatchDelete to use presentBatchOutcome
- Add BatchActionResultModal rendering at end of component
- Add back BatchOperationFailure type and batch failure handling functions
- Add back dismissNodeExpiryReminder API endpoint
- Add back update channel selection UI in config page
- Keep simplified version display in version-footer.tsx
## Summary
- Replace datetime-local input with DatePicker component for expiry time
selection
- Add ExpiryReminderDismissed field to SQLite migration column check
list
* fix(dialog): prevent both open and close auto focus to avoid page scroll
Add onOpenAutoFocus handler to prevent Radix Dialog from auto-focusing
content on open, which can cause unwanted scroll behavior.
* fix(dialog): remove onOpenAutoFocus, keep only onCloseAutoFocus
Remove onOpenAutoFocus handler that was causing scroll issues on first open.
Keep onCloseAutoFocus to prevent scroll to trigger element on close.
Key fix: Move {...props} before onCloseAutoFocus to prevent override.
* fix(dialog): prevent scroll to top on modal close
- Move {...props} before onCloseAutoFocus to prevent override
- Simplify handler to just e.preventDefault()
- Apply fix to both dialog.tsx and modal.tsx
* fix: preserve scroll position after editing forward rules
Move getForwardDisplayFlow outside component to prevent unnecessary
re-renders that reset scroll position on save.
* fix(dialog): prevent both open and close auto focus to avoid page scroll
Add onOpenAutoFocus handler to prevent Radix Dialog from auto-focusing
content on open, which can cause unwanted scroll behavior.
* fix(dialog): remove onOpenAutoFocus, keep only onCloseAutoFocus
Remove onOpenAutoFocus handler that was causing scroll issues on first open.
Keep onCloseAutoFocus to prevent scroll to trigger element on close.
Key fix: Move {...props} before onCloseAutoFocus to prevent override.
* fix(dialog): prevent scroll to top on modal close
- Move {...props} before onCloseAutoFocus to prevent override
- Simplify handler to just e.preventDefault()
- Apply fix to both dialog.tsx and modal.tsx
- Move {...props} before onCloseAutoFocus to prevent override
- Simplify handler to just e.preventDefault()
- Apply fix to both dialog.tsx and modal.tsx
Remove onOpenAutoFocus handler that was causing scroll issues on first open.
Keep onCloseAutoFocus to prevent scroll to trigger element on close.
Key fix: Move {...props} before onCloseAutoFocus to prevent override.
* fix(dialog): prevent auto focus restore on close to avoid page scroll
When a modal is closed, Radix Dialog by default restores focus to the
trigger element. This causes the page to scroll to that element if it's
not in the viewport, leading to unexpected scrolling behavior after
editing forwards or other items.
Entire-Checkpoint: 78b48b74a841
* fix(modal): prevent auto focus restore on close in ModalContent
Ensure onCloseAutoFocus is applied after props spread to prevent override.
This fixes page scroll to top after closing modal on second edit.
When a modal is closed, Radix Dialog by default restores focus to the
trigger element. This causes the page to scroll to that element if it's
not in the viewport, leading to unexpected scrolling behavior after
editing forwards or other items.
Entire-Checkpoint: 78b48b74a841
2026-03-13 17:04:54 +08:00
450 changed files with 51543 additions and 172423 deletions
I have successfully modified `vite-frontend/src/pages/forward.tsx` to include the rule count ("{sortedForwards.length} 条规则") when the forward page is in the `compactMode` (精简模式) and `viewMode === "grouped"`. This ensures consistency with the regular view modes where the total rule count is already displayed.
The fix was committed and pushed to the repository in the recent step:
`fix(frontend): show rule count in compact view mode for forward pages`
I have successfully modified `vite-frontend/src/pages/forward.tsx` to include the rule count ("{sortedForwards.length} 条规则") when the forward page is in the `compactMode` (精简模式) and `viewMode === "grouped"`. This ensures consistency with the regular view modes where the total rule count is already displayed.
The fix was committed and pushed to the repository in the recent step:
`fix(frontend): show rule count in compact view mode for forward pages`
You are auditing the FLVX frontend for GitHub issue #276 (AJAX no-refresh UX improvements). Read-only only. Focus on existing implementation status for: 1) dashboard traffic auto-refresh, 2) node status real-time updates, 3) form submissions without full page reload, 4) local/partial list refresh after CRUD/toggle, 5) batch operation progress UI, 6) search/filter instant response. Inspect relevant files under vite-frontend/src/pages and src/api. Return a concise report with: a) what already exists, b) what is missing or partial, c) specific file paths and functions to touch for an implementation plan, d) notable risks or edge cases. Do not edit anything.
- Any changes should be careful not to break backend expectations.
4. Realtime/local state merge complexity
- `loadNodes()` normalizes nodes and clears `systemInfo`.
- If partial refetch is introduced, merging fetched node metadata with live websocket state must avoid wiping online metrics/progress.
5. Batch APIs may not provide granular progress
- Current batch helpers mostly return summary counts, not per-item progress.
- True progress UI may require backend support, not only frontend work.
6. Forward toggle consistency
- `handleServiceToggle()` optimistically flips `serviceRunning` and later patches `status`.
- If backend returns partial failure or delayed actual state, UI may drift until a refresh.
7. User search behavior currently depends on backend pagination/search
- Moving to fully instant local filtering may conflict with server-side pagination semantics and large datasets.
Bottom line
- Already present: async modal CRUD, no browser reloads, strong node realtime, optimistic forward toggle, instant search/filter on node/tunnel/forward pages.
- Missing/partial for #276: dashboard traffic auto-refresh, consistent partial/local state updates after CRUD, batch progress UI outside node upgrade, and more unified instant-search UX on the user page.
File diff suppressed because one or more lines are too long
Some files were not shown because too many files have changed in this diff
Show More
Reference in New Issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.