310 Commits

Author SHA1 Message Date
orris-inc
c1eff8d9cf fix: verify telegram webhook registration and fall back to polling on failure
SetWebhook returning OK is not sufficient proof the webhook is live —
the URL can end up unset if DeleteWebhook races in or an intermediary
rewrites the request, after which inbound updates are silently dropped.
Read back getWebhookInfo to confirm Telegram stored the expected URL,
and on any verification failure fall back to polling when an update
handler is configured so the bot keeps receiving updates.
v0.2.3
2026-04-29 14:07:17 +08:00
orris-inc
9beb449393 fix: unify subscription traffic cycle window and reduce log noise
Replace direct uses of sub.CurrentPeriodStart/End with
subscription.ResolveTrafficPeriod across the quota cache, forward usage
endpoints, and DTOs. For calendar_month plans these windows diverge,
causing the node hub real-time enforcer to query usage over the wrong
window after a calendar reset and forward usage endpoints to return
mis-aligned traffic figures. SubscriptionDTO and DashboardSubscriptionDTO
now expose currentTrafficCycleStart/End plus the upload/download
breakdown, so the frontend pairs figures with the matching window and
skips a redundant traffic-stats request.

Also demote context.Canceled / DeadlineExceeded inside Errorw/Error to
WARN. Repository read paths previously logged client cancellations as
ERRORs (e.g. dashboard 30s timeout produced an ERROR per repo on the
call chain), which polluted alerts.
2026-04-29 14:06:20 +08:00
orris-inc
abe0bb74ea fix: honor lifetime billing cycle in Subscription-Userinfo traffic calculation
calculatePeriodTraffic reimplements period resolution locally and was not
updated alongside ResolveTrafficPeriod, so the Subscription-Userinfo
header still applied calendar-month boundaries to lifetime subscriptions.
Clients like clash/v2ray consequently saw the used-traffic counter reset
on the 1st of each month instead of accumulating from the subscription
start. Thread BillingCycle through SubscriptionValidationResult and
short-circuit lifetime subscriptions to the full subscription period,
mirroring the domain's ResolveTrafficPeriod.
v0.2.2
2026-04-23 18:15:17 +08:00
orris-inc
51e9df66f7 fix: fall back to hub-observed address for forward agent next-hop resolution
When a forward agent is used as an intermediate or exit hop in a rule
but has no publicAddress/tunnelAddress configured, the entry agent
receives an empty NextHopAddress and config sync silently produces an
unusable configuration. The hub already observes each agent's remote
address at WebSocket handshake, so record it on AgentHubConn and use
it as a best-effort fallback in both rule sync converters, emitting a
warning so operators can see when auto-detection takes effect.
2026-04-23 16:34:09 +08:00
orris-inc
6a571b88ab fix: skip address/port uniqueness check when node address is empty
Align admin node update with the other three node usecases: an empty
server address is a placeholder and must not participate in
(address, port) uniqueness, otherwise two placeholder nodes sharing a
port would wrongly collide on save.
2026-04-23 16:22:47 +08:00
orris-inc
eb4772c10e fix: exclude lifetime subscriptions from calendar-month traffic resets
Lifetime subscriptions should accumulate traffic from their start date
without being reset at calendar-month boundaries. ResolveTrafficPeriod
now treats lifetime billing cycle as billing_cycle mode regardless of
the plan's reset mode setting.

Also exempt lifetime subscriptions from the automatic usage reset
triggered when a plan's traffic reset mode changes, since their traffic
period is already handled correctly by the domain logic.
v0.2.1
2026-04-03 09:31:58 +08:00
orris-inc
129b79b85b feat: notify node agents to reload config when forward rule route changes
Add NodeConfigChangeNotifier interface and wire it into forward rule
CRUD use cases (create/update/delete/enable/disable) so that target
nodes are notified to reload their routing configuration when per-rule
routes are added, modified, or removed.

Also populate ForwardRuleRoutes in NodeConfigData via the shared
mergeForwardRuleRoutesCore helper, enabling the WS hub sync path to
include per-forward-rule routing in node config pushes.
v0.2.0
2026-04-01 13:57:28 +08:00
orris-inc
9af0cd7299 fix: allow weight=0 for backup agents in forward rule load balancing
ExitAgentRequest.Weight was uint16, causing weight=0 to be treated as
"unset" and replaced with default (50). Changed to *uint16 so nil means
default and explicit 0 is preserved as backup agent designation.
2026-04-01 11:58:54 +08:00
orris-inc
2466d8fa8f fix: add address_preference to forward rule repository Update map
The Updates map in ForwardRuleRepositoryImpl.Update was missing the
address_preference field, causing address preference changes to be
silently dropped during persistence despite being correctly applied
in the domain layer.
v0.1.100
2026-03-17 15:00:06 +08:00
orris-inc
c70ba898de feat: reset subscription usage when plan traffic reset mode changes
When a plan's traffic reset mode changes (e.g. calendar_month to
billing_cycle), reset usage for all active/trialing/suspended
subscriptions to avoid unfair traffic accumulation under the new mode.
v0.1.99
2026-03-17 09:48:47 +08:00
orris-inc
a164a85df2 fix: add AddressPreference to RuleSyncData for WS hub sync path
RuleSyncData was missing the AddressPreference field, causing the WS hub
full/incremental sync path to always send an empty value. This made
ruleConfigChanged comparison ineffective when only the address preference
changed but the resolved NextHopAddress remained the same.
2026-03-17 09:46:29 +08:00
orris-inc
b349fef8aa feat: push subscription sync on forward rule changes and optimize heavyweight queries
Forward rule mutations (create/update/delete/enable/disable) now trigger
async subscription sync to affected nodes, ensuring nodes pick up rule
changes immediately without waiting for the next polling cycle.

Replace full-entity loading with lightweight database queries across
multiple domains: node/agent offline detection and counting for telegram
summaries, notification unread filtering and bulk mark-as-read, and
active user ID retrieval. Fix subscription pricing IsActive field to use
*bool for proper nil/false distinction.
v0.1.98
2026-03-16 17:25:21 +08:00
orris-inc
f3b8118d58 feat: add address preference support for forward rules
Allow forward rules to specify how the next-hop agent address is
resolved (auto/public/tunnel). This gives users control over whether
chain and entry rules connect via public or tunnel addresses instead
of always using the default auto-detection order.

Adds AddressPreference value object, integrates it across domain,
application, infrastructure, and interface layers with migration.
2026-03-16 15:59:28 +08:00
orris-inc
c5dff3e26b fix: enforce traffic period filtering in all limit check paths
Traffic reset was not taking effect because multiple enforcement paths
ignored the subscription's currentPeriodStart when calculating usage:

- ResolveTrafficPeriod now uses currentPeriodStart as a floor for
  calendar_month mode, so manual resets exclude pre-reset traffic
- Node and forward enforcement services now query traffic within the
  resolved period instead of from time zero
- NodeSubscriptionUsageReaderAdapter Redis query respects periodStart

Also refactors node subscription generation and token validation into
infrastructure layer, adds include_counts support for admin subscription
list endpoint, and extracts shared nodeutil package.
v0.1.97
2026-03-11 11:57:14 +08:00
orris-inc
82cb5bb20f feat: add per-forward-rule routing and extract shared routing package
- Extract routing value objects (RouteConfig, RouteRule, CustomOutbound,
  OutboundType, RuleSetEntry) from node/valueobjects to shared/routing
  package for reuse across node and forward domains
- Add RouteConfig field to ForwardRule domain model with persistence
  (JSON column), validation, and mutation support
- Merge per-forward-rule routes into NodeConfigResponse with inbound
  filtering, namespaced custom outbounds, and rule_set deduplication
- Add migration 057 for forward_rule route_config column
- Update agent SDK types with ForwardRuleRoute, RuleSetEntry, and
  RouteRule.Inbound field
v0.1.96
2026-03-07 21:49:32 +08:00
orris-inc
e21b6d3446 refactor: unify telegram messaging to HTML format with security and quality improvements
- Switch all telegram notifications from MarkdownV1 to HTML format
  with consistent html.EscapeString on all dynamic content including
  timeStr and amountStr for defense-in-depth
- Add silent message support (SendMessageSilent) for info-type
  notifications while keeping offline alerts audible
- Add /lang command for user language preference management
- Add SendMessageDraft support for typing-bubble UX feedback
- Deduplicate TelegramMessageSender interface using type alias in
  admin/serviceddd.go referencing canonical definition in usecases
- Fix error handling in GetBindingLanguageByTelegramID to distinguish
  ErrBindingNotFound from infrastructure errors (DB timeout etc.)
- Add ErrBindingNotFound sentinel in infrastructure/telegram with
  domain-to-local error translation in ServiceAdapter
- Normalize logger injection: rename shadowed param to log, move
  logger to last constructor parameter per project conventions
- Add debug logging for SendMessageDraft nil-check paths
- Remove empty messages.go, consolidate EscapeHTML into escape.go
- Replace blockquote formatting for improved Telegram rendering
2026-03-05 12:02:08 +08:00
orris-inc
aa04d3e680 feat: apply subscription traffic overrides in subscription generation
Pass TrafficLimitOverride and TrafficUsedAdjustment from the
subscription model through to the subscription generation use case,
so per-subscription traffic quota overrides are reflected in the
Subscription-Userinfo response header.

Add overflow guard for uint64 -> int64 conversion when applying
traffic used adjustment.
v0.1.95
2026-03-04 15:04:59 +08:00
orris-inc
53482ab6ad fix: populate dataUsedBytes in subscription list endpoints
The list subscription endpoints (user and admin) were returning
dataUsedBytes as 0 because ListUserSubscriptionsUseCase lacked
QuotaService integration. Added GetSubscriptionQuotaPreloaded to
the QuotaService interface to avoid redundant DB lookups when
subscription and plan are already fetched, and wired it into the
list use case to populate traffic usage data in DTOs.
2026-03-02 14:22:41 +08:00
orris-inc
68030af644 fix: patch remaining security gaps from audit review
- Fix command injection in forward agent install script (generateinstallscript.go)
  by adding ValidateAPIURL + ShellQuote for ServerURL parameter
- Align GetSecuritySettings display defaults with actual password policy
  (min_length 8→12, require flags false→true) to prevent admin confusion
- Add rate limiting to /auth/refresh endpoint
v0.1.94
2026-03-02 10:49:21 +08:00
orris-inc
8b5f8076a6 fix: comprehensive security hardening across authentication, input validation, and template rendering
- Add JWT signing key strength validation at startup (reject default key in non-debug mode)
- Fix stored XSS in announcements/notifications by switching to ToHTMLSanitized() and restricting URL schemes to http/https/mailto
- Fix admin role persistence after demotion by reading fresh role from database in auth middleware and token refresh
- Add SSRF protection for SMTP host configuration (reject private/reserved IPs)
- Fix command injection in install script generation with URL validation and shell quoting
- Strengthen password policy to 12+ chars with uppercase/lowercase/number/special requirements and common password blacklist
- Add rate limiting to verify-email and reset-password endpoints
- Fix SSTI by switching notification templates from text/template to html/template
- Add node status field to hub config sync data
2026-03-02 10:40:03 +08:00
orris-inc
5c91928c48 feat: add subscription traffic overrides and admin update endpoint
Add per-subscription traffic limit override and usage adjustment fields,
allowing admins to override plan-level traffic limits and adjust displayed
usage for individual subscriptions. Includes PATCH /admin/subscriptions/:id
endpoint, migration, and domain/infrastructure/application layer changes.

Also switch protocol config and plan repositories from soft delete to hard
delete, and add HardDelete for external forward rules.
2026-03-02 09:22:13 +08:00
orris-inc
a50e130b8b feat: add online device tracking and subscription count per node
- Implement Redis-based online device tracking using sorted sets with
  IP-level granularity and automatic stale entry cleanup
- Add online subscription count per node to dashboard, node list, node
  detail, and traffic stats APIs
- Propagate plan device limits to node agents during subscription sync,
  full sync, and plan feature changes
- Add OnlineDeviceCounter and NodeOnlineSubscriptionCounter interfaces
  to decouple application layer from infrastructure
- Populate onlineDeviceCount and deviceLimit in subscription API responses
  (get, list, create, reset-link)
- Handle multi-IP per subscription in online subscription reports with
  IP validation and deduplication
- Add plan change notification to re-sync affected nodes when plan
  features (e.g. device_limit) are updated
v0.1.93
2026-02-26 18:22:40 +08:00
orris-inc
dfbf0207a2 feat: add rule-set entries support, improve OAuth flow and nginx WebSocket config
- Add RuleSetEntry value object for remote rule-set sources in sing-box
  route configuration, replacing inline geoip/geosite with rule_set references
- Add rule-set entry serialization in DTO and persistence mapper layers
- Add username/version fields to OutboundDTO for SOCKS/HTTP auth support
- Update nginx reverse proxy examples with WebSocket upgrade headers
- Fix GitHub OAuth to fall back to login when display name is empty
- Redesign OAuth success/error HTML pages with dark mode support,
  cookie-based auth flow, and auto-close with manual fallback
2026-02-26 11:18:10 +08:00
orris-inc
daf70184e1 feat: add DNS configuration support for node DNS-based unlocking
Add DnsConfig value object with servers, rules, and strategy options
compatible with sing-box DNS configuration format. Implement full
CRUD support across all layers: domain aggregate, persistence mapper
with JSON serialization, application use cases (create/update/get),
config sync service, and HTTP handler endpoints. Include database
migration for the dns_config column and comprehensive domain tests.
v0.1.92
2026-02-17 20:23:48 +08:00
orris-inc
b64969c3dc feat: add custom outbound support for route configuration
Allow users to define custom sing-box outbound configurations (custom_xxx)
in route rules, in addition to existing preset types and node references.

- Add CustomOutbound value object with validation (tag, protocol, server, port, settings)
- Extend OutboundType to support custom_xxx references
- Add custom outbounds to RouteConfig with referential integrity validation
- Add CustomOutboundDTO and DTO conversion functions
- Flatten custom outbounds into agent outbounds list for sing-box consumption
- Agent responses only include custom outbounds in the outbounds array, not in route
- Add persistence support via RouteConfigJSON/CustomOutboundJSON in mapper
2026-02-12 15:53:37 +08:00
orris-inc
1bed713a96 refactor: split large domain, repository, and service files by responsibility
Split oversized files across multiple layers into smaller, focused files:
- domain/forward: extract chain, mutations, traffic, and validation logic
- domain/node: extract lifecycle, mutations, and status logic
- infrastructure/repository: extract list, ops, and query methods
- application/telegram/admin: extract notification methods to serviceddd_notify.go
- infrastructure/telegram: extract adapter and handler from pollingservice

No behavioral changes; pure structural refactoring for maintainability.
2026-02-12 14:09:40 +08:00
orris-inc
622b61e7c9 fix: add missing AnyTLS support in WebSocket config_sync and node forwarding
The AnyTLS protocol branch was missing from ToNodeConfigData() in
hubdto.go, causing empty Protocol field in WebSocket config_sync
messages. Also add AnyTLS to node-to-node forwarding password
generation in both GetNodeSubscriptions and SubscriptionSyncService,
which would have caused forwarding auth failures for AnyTLS targets.
v0.1.91
2026-02-11 18:42:56 +08:00
orris-inc
e33acff06a feat: add AnyTLS protocol support across all layers
Implement end-to-end AnyTLS protocol support including domain value
objects, repository persistence, use case handling, subscription
formatting (Base64/Clash/Surge), and HTTP handler bindings. Add
migration script for the anytls_configs table and wire protocol-specific
config loading in parallel with existing protocols.

Also add PlanType filter to plan repository list query.
2026-02-11 18:30:46 +08:00
orris-inc
cacc3a265b feat: add admin dashboard endpoint, CSRF protection, and log level optimization
- Add admin dashboard API (GET /admin/dashboard) with concurrent errgroup
  queries aggregating users, subscriptions, nodes, forward agents, and
  today's traffic metrics
- Implement Double Submit Cookie CSRF middleware with token generation,
  cookie lifecycle management, and path-based exemptions for public and
  machine-to-machine endpoints
- Downgrade routine Info logs to Debug and validation Error logs to Warn
  across ~60 use cases to reduce production log noise
- Replace logger.NewLogger() calls with injected logger.Interface in
  migration, middleware (logging, recovery, nodeowner, nodequota), and
  CLI commands for consistent DI
- Simplify TrafficOverviewResponse to traffic-only fields (counts moved
  to new admin dashboard)
- Restrict forward rule bindIP to exit-role agents only
- Default cookie Secure to true, fix SameSite call ordering, redact
  Cookie header in panic recovery
- Add CountByLastSeenAfter to node and forward agent repositories,
  CreatedAfter filter to user ListFilter
- Fix logger.Error to logger.Errorw in SystemSettingRepository
2026-02-11 16:15:30 +08:00
orris-inc
8a5aaa9ac7 chore: promote directly imported dependencies and clean up go.mod
Move mimetype, gocron/v2, and gobreaker/v2 from indirect to direct
dependencies to reflect actual import usage. Remove unused indirect
dependency check.v1.
2026-02-10 16:02:03 +08:00
orris-inc
657dbbbe85 fix: restart orris after migrations to ensure admin user seeding
seedAdminUser runs on server startup but fails on first install because
the users table does not exist yet (migrations are applied separately
via docker exec). Adding a container restart after migrations ensures
the admin credentials configured during installation take effect.
2026-02-10 15:40:07 +08:00
orris-inc
2c687b828d feat: add remember me support for session persistence
Add remember_me flag to sessions to control cookie persistence and
session duration. Password login respects user preference (session
cookie vs persistent cookie), while passkey and OAuth default to
persistent sessions as trusted authentication methods.

- Add RememberMe field to Session domain model and persistence layer
- Use session cookies (cleared on browser close) when rememberMe=false
- Use persistent cookies with RememberExpDays when rememberMe=true
- Inject SessionConfig into auth and passkey handlers for cookie control
- Extend session duration on refresh based on remember me preference
- Add migration 053 to add remember_me column to sessions table
v0.1.90
2026-02-10 15:31:04 +08:00
orris-inc
1847ae2293 refactor: comprehensive code review fixes across architecture, security, performance, and API design
89 review issues resolved across 6 dimensions (architecture, security, error handling,
performance, code quality, API design) with 14 rounds of iterative improvements.

Architecture:
- Remove GORM dependencies from Domain layer (OAuthAccount TableName)
- Extract Model/Mapper for 5 entities (OAuthAccount, Session, TelegramBinding, AdminTelegramBinding, Ticket)
- Split Router from 1647 to 296 lines with DI Container (container.go + wire_*.go)
- Migrate adapters from infrastructure/ to interfaces/ to fix reverse dependency
- Split forward.Repository into 4 ISP-compliant sub-interfaces (RuleReader/Querier/Writer/GroupManager)
- Extract domain/shared helpers (expiration, groupids, online) with aggregate delegation
- Add domain/setting/SettingProvider interface for infrastructure decoupling

Security & Error Handling:
- Add nil checks for subscription/plan/user after repository GetByID calls
- Fix unsafe type assertions with comma-ok pattern in WebSocket handlers
- Introduce shared/goroutine/SafeGo for panic recovery in background goroutines
- Fix fmt.Errorf wrapping that masked AppError semantics across 32 UseCase files
- Add transaction protection for ticket comment creation
- Migrate rate limiter from in-memory to Redis for multi-instance safety
- Add email masking utility, fix AuthError errors.As compatibility

Performance:
- Fix Ticket N+1 query (list queries from 1+N to 2 DB calls)
- Batch UPDATE with CASE WHEN SQL (50 round-trips to 1)
- Redis Pipeline for traffic flush (100 round-trips to 1)
- TCP connection semaphore (1024/rule limit with 80% warning)
- Cache penetration protection (null marker, 2min TTL)
- Cache stampede protection (TTL jitter 60-80min)
- Add ConnMaxIdleTime, scheduler SingletonMode + context timeout
- UDP buffer sync.Pool reuse, slice pre-allocation
- Add multi-valued indexes for JSON columns and composite index for usage stats

API Design:
- Unify DELETE responses to 204 No Content, POST creation to 201 Created
- Migrate 6 inline route methods to routes/ package
- Add API versioning middleware (X-API-Version + Accept vendor media type)
- Extract Response DTO layer for API contract decoupling
- Add DTO co-location (interfaces/dto -> handlers/)
- Remove internal ID exposure from PaymentHandler

Code Quality:
- Unify Mapper naming to interface + Impl pattern
- Deduplicate ForwardRule validation (320 -> 80 lines in constructor)
- Unify time handling with biztime.NowUTC across Domain layer
- Fix filename typo (admintelegrambbinding -> admintelegrambinding)
- Add 450+ Domain layer tests (user, subscription, node, payment, notification, ticket)
- Add 276 Handler layer tests (auth, subscription, plan, forward rule, node, ticket, notification)
- Add Hub multi-instance support via Redis PubSub (HubEventBus)
- Add cursor-based pagination infrastructure
2026-02-10 14:31:39 +08:00
orris-inc
fdf0c76a8e feat: sync subscriptions to affected nodes on resource group changes
When resource group membership, forward rules, status, or deletion
changes occur, push subscription updates to all affected node agents.
This ensures nodes promptly reflect the latest subscription state
without waiting for the next periodic sync.

- Add NodeSubscriptionSyncer interface with shared collect/sync helpers
- Add GetIDsByGroupID to NodeRepository for efficient node lookup
- Add SyncSubscriptionsToNode adapter on SubscriptionSyncService
- Wire syncer into 4 resource group use cases via setter injection
v0.1.89
2026-02-06 15:03:47 +08:00
orris-inc
91c04ff325 fix: make migration 050 idempotent to handle partially applied state
Use stored procedure with IF NOT EXISTS checks to avoid duplicate column
errors when the migration was partially applied but not recorded by goose.
v0.1.88
2026-02-06 11:05:36 +08:00
orris-inc
8e3e65d387 feat: add i18n support for telegram notifications and improve bot service resilience
- Extract all telegram notification messages into i18n package with ZH/EN support
- Auto-detect user language from Telegram client and persist per-binding preference
- Add language column to telegram_bindings and admin_telegram_bindings tables
- Add circuit breaker (gobreaker) and retry logic for Telegram Bot API calls
- Handle 429 rate limiting with retry_after, skip 403 bot-blocked errors gracefully
- Add message splitting for messages exceeding Telegram's 4096 char limit
- Add deep link support (t.me/bot?start=bind_<code>) for one-click binding
- Add concurrent worker pool for polling update processing with user affinity
- Persist polling offset to Redis for crash-resilient restart
- Add traffic_reset_mode plan feature (calendar_month/billing_cycle) for flexible
  traffic period calculation via ResolveTrafficPeriod domain function
- Add SendChatAction ("typing") indicator before long operations
- Add admin /adminunbind and /adminstatus commands in polling mode
- Fix error handling: use errors.Is for sentinel errors, return error on dual
  data source failure in quota service
- Fix PlanFeatures.Clone to deep-copy slices, use reflect.DeepEqual in Equals
- Fix NormalizeLimits to prioritize standard keys over legacy aliases
- Fix CanNotifyResourceExpiring to use business timezone for date comparison
- Remove unused SubscriptionUsageRepository dependency from ProcessReminderUseCase
v0.1.87
2026-02-06 10:54:22 +08:00
orris-inc
2c5cc9a0db feat: add per-binding schedule configuration for admin telegram notifications
Allow each admin telegram binding to configure its own schedule preferences:
- daily_summary_hour: hour to send daily summary (0-23, business timezone)
- weekly_summary_hour: hour to send weekly summary (0-23, business timezone)
- weekly_summary_weekday: weekday to send weekly summary (0=Sunday..6=Saturday)
- offline_check_interval_minutes: repeat notification interval for offline resources (1-30 min)

Scheduler cron jobs now trigger hourly and delegate filtering to the use case
layer, which matches bindings by their configured hour/weekday. Summary dedup
switches from elapsed-time to calendar-based comparison to avoid timing races.
Offline check now supports repeat notifications using per-binding intervals.
2026-02-05 16:40:05 +08:00
orris-inc
41ba0f5ec9 fix: align traffic calculation with calendar month and day-aligned Lambda boundary
Two fixes for traffic statistics consistency:

1. Use calendar month boundaries (in business timezone) instead of
   per-subscription billing period for dashboard and subscription
   config traffic display, matching checkTrafficLimit enforcement logic.

2. Replace sliding 24h window with day-aligned boundary for the
   MySQL/Redis Lambda architecture split. MySQL now covers complete
   days before yesterday, Redis covers yesterday + today. This aligns
   with the daily batch aggregation schedule and the 48h Redis TTL.

Also fix lifetime subscription end date to avoid year overflow when
converting to eastern timezones (9999-12-31 23:59:59 -> 9999-01-01).
2026-02-05 15:36:24 +08:00
orris-inc
edd4afcbda fix: include forward rule target nodes in subscription delivery
Nodes referenced as target_node_id in system forward rules now also
receive subscriptions from the corresponding resource groups. This
fixes cases where a resource group contains only forward rules but
the target nodes were not getting subscriptions delivered.
2026-02-05 15:36:11 +08:00
orris-inc
75c9b56525 refactor: extract common handler utilities to shared utils package
Consolidate duplicated handler code into reusable utils functions:
- ParseSIDParam for Stripe-style ID parsing
- GetUserIDFromContext/GetSubscriptionIDFromContext for safe context extraction
- ParsePagination/ParsePaginationWithLimits for query parameter parsing
- ListSuccessResponse for paginated list responses
- Move pagination utilities from trafficstatsutil to shared/utils
2026-02-05 15:36:00 +08:00
orris-inc
8695197973 feat: add batch operations for resource group management and improve subscription handling
- Add batch update methods for resource group membership changes (nodes, agents, rules)
  to reduce database round-trips during bulk operations
- Add billing_cycle field to SubscriptionDTO to expose subscription's billing cycle
- Support all billing cycles (weekly, monthly, quarterly, semi_annual, yearly, lifetime)
  in subscription creation and renewal
- Return empty subscription instead of error when no nodes are available
- Default to monthly billing cycle for legacy subscriptions without billing_cycle set
- Optimize protocol config queries with explicit column selection
v0.1.86
2026-02-05 09:32:42 +08:00
orris-inc
9c394a63c9 fix: allow forward rules to be delivered when target nodes are outside resource groups
Previously, forward rules required both the rule itself and its target_node
to be in the subscription plan's resource groups. This change relaxes this
constraint - rules are now delivered based solely on their own resource group
membership, regardless of where the target node resides.

Changes:
- Add ListSystemRulesByGroupIDs repository method to query rules by group membership
- Modify getForwardedNodes to query rules first, then fetch target nodes separately
- Fix GetBySubscriptionToken and getHybridPlanNodes to handle cases where
  resource groups contain only forward rules without any nodes
- Add target_node_id IS NOT NULL filter for query optimization
2026-02-04 18:49:17 +08:00
orris-inc
5e4d674712 fix: support interactive input when running install script via pipe
Redirect all read commands to /dev/tty to allow user input when the
script is executed via curl pipe (curl ... | bash). Without this fix,
read commands fail because stdin is consumed by the piped script content.
2026-02-04 16:27:57 +08:00
orris-inc
b06e4c452e feat: add handshake obfuscation and expiring notification support
- Add XOR-based handshake obfuscation to reduce DPI fingerprint in tunnel_ping
- Change WebSocket tunnel URL from /tunnel to /ws
- Switch handshake message format from TextMessage to BinaryMessage
- Replace renewal_amount with cost_label for flexible pricing display
- Add expiring notification preferences with configurable advance days
- Implement scheduled expiring check for forward agents and nodes
- Add Telegram alerts for expiring resources with user preferences
v0.1.85
2026-02-04 13:44:51 +08:00
orris-inc
c059067261 feat: add expiration and renewal tracking for forward agents and nodes
Add expires_at, renewal_amount, and is_expired fields to forward agents
and nodes to support expiration tracking and renewal management.

Changes:
- Add expires_at (datetime), renewal_amount (decimal), is_expired (computed)
  fields to ForwardAgent and Node domain entities
- Add handler validation for expires_at (ISO8601 format, must be future time)
  and renewal_amount (non-negative, 0 clears the value)
- Update DTOs, mappers, models, and repositories for both entities
- Rename Node's group_ids JSON field to group_sids for consistency
- Add database migration 048_add_agent_expiry_and_renewal.sql
v0.1.84
2026-02-03 16:31:43 +08:00
orris-inc
c4dc968301 refactor: change forward agent group association from single to multiple
- Change ForwardAgent.GroupID (single) to GroupIDs (array) to support
  multi-group membership
- Add migration script 047 to convert group_id column to group_ids array
- Update repository layer with array-based queries using ANY operator
- Update ResourceGroupRepository to handle array-based forward agent
  group associations
- Update all related use cases and DTOs to work with group arrays
- Fix payment repository to use explicit column selection
- Update handlers and tests to reflect new multi-group structure
v0.1.83
2026-02-03 14:01:26 +08:00
orris-inc
a645917430 feat: add resource group association on creation for forward agents and nodes
Add GroupSID field to CreateForwardAgentRequest and GroupSIDs field to
CreateNodeRequest, allowing resource group assignment during entity creation.
This eliminates the need for a separate update call after creation.

- Forward agent: accepts single group_sid (optional)
- Node: accepts array of group_sids (optional, supports multiple groups)
- Both use cases now inject resourceGroupRepo to resolve SIDs to internal IDs
- Duplicate and empty SIDs are handled gracefully for nodes
2026-02-03 10:04:57 +08:00
orris-inc
94b3850f9d feat: add load balance strategy for multi-exit forward rules
Add LoadBalanceStrategy field to support two load balancing modes for
entry rules with multiple exit agents:

- failover: Priority-based selection by weight (highest first), with
  weight=0 agents serving as backup only when all others unavailable
- weighted: Traffic distribution based on weight ratios

Changes:
- Add LoadBalanceStrategy value object with validation
- Add load_balance_strategy column to forward_rules table (default: failover)
- Update ForwardRule domain entity with strategy field and validation
- Add validation: weighted strategy requires at least one non-backup agent
- Update DTOs, handlers, and usecases to support the new field
- Sync SDK with LoadBalanceStrategy type and fields
- Update all test files to include the new parameter
v0.1.82
2026-02-02 18:37:09 +08:00
orris-inc
b15a432eff feat: add exit agents load balancing support for forward rules
- Add ExitAgents field to ForwardRule for multiple exit agent configuration
- Implement AgentWeight value object for weighted load balancing
- Add load balance mode support (random/round_robin/weighted)
- Update repository, mappers, and models to persist exit agents config
- Add database migration for exit_agents and load_balance_mode columns
- Extend DTOs and converters to handle multi-exit agent scenarios
- Add tunnel health handler for managing agent health status
- Update all usecases to work with new exit agents structure
- Modify affected agents finder to include all exit agents
2026-02-02 18:03:37 +08:00
orris-inc
f0f4f451f9 refactor: replace alert deduplication with state-based alert management
- Add AlertStateManager with Normal/Firing state machine for proper alert lifecycle
- Implement recovery notifications when nodes/agents transition from Firing to Normal
- Clear alert state on resource deletion to prevent stale recovery notifications
- Use batch fetching for plans, users, and subscriptions to reduce N+1 queries
- Add GetTotalBySubscriptionIDsGrouped for efficient per-subscription usage retrieval
- Remove real-time offline notifications; use scheduled check for threshold-based alerting
2026-02-02 10:38:32 +08:00