diff --git a/.env b/.env new file mode 100644 index 0000000..701bb39 --- /dev/null +++ b/.env @@ -0,0 +1,3 @@ +# 数据库连接字符串 +# 请根据您的实际环境修改此处的数据库用户名、密码、地址、端口和数据库名 +DATABASE_DSN="mysql://root:password@tcp(127.0.0.1:3306)/ppanel?charset=utf8mb4&parseTime=true&multiStatements=true" \ No newline at end of file diff --git a/.gitignore b/.gitignore index 6b012fc..9cc96eb 100644 --- a/.gitignore +++ b/.gitignore @@ -14,6 +14,7 @@ logs/ # Local config overrides etc/*.local.yaml apps/*/etc/*.local.yaml +deploy/.env # IDE .idea/ @@ -34,4 +35,4 @@ tmp/ # Claude CLAUDE.md .claude/ -.claude.json \ No newline at end of file +.claude.json diff --git a/Makefile b/Makefile index 35d360e..e2dada3 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ .PHONY: build-all build-api build-admin build-node build-queue build-scheduler build-rpc-core \ gen-api gen-model docker-up docker-down docker-env-up docker-env-down lint clean \ - run-api run-admin run-node run-queue run-scheduler run-rpc-core + run-api run-admin run-node run-queue run-scheduler run-rpc-core migrate migrate-up migrate-down migrate-create migrate-version migrate-force migrate-goto # Environment: dev | test | prod (default: dev) ENV ?= dev @@ -81,3 +81,36 @@ lint: clean: rm -rf bin/ + +# Database migrations (using go-migrate) +migrate: + @echo "Usage: make migrate [args...]" + @echo "Commands: up, down [version], create , version, force , goto " + +migrate-up: + @echo "Running database migration UP..." + go run pkg/migrate/main.go up + +migrate-down: + @echo "Running database migration DOWN..." +ifeq ($(ARGS),) + go run pkg/migrate/main.go down +else + go run pkg/migrate/main.go down $(ARGS) +endif + +migrate-create: + @echo "Creating new migration files..." + go run pkg/migrate/main.go create $(NAME) + +migrate-version: + @echo "Getting current database migration version..." + go run pkg/migrate/main.go version + +migrate-force: + @echo "Forcing database migration version..." + go run pkg/migrate/main.go force $(VERSION) + +migrate-goto: + @echo "Going to specific database migration version..." + go run pkg/migrate/main.go goto $(VERSION) diff --git a/apps/api/etc/api-prod.yaml b/apps/api/etc/api-prod.yaml index 5e04a3b..cc9e77d 100644 --- a/apps/api/etc/api-prod.yaml +++ b/apps/api/etc/api-prod.yaml @@ -57,3 +57,6 @@ Security: Asynq: Addr: "${REDIS_HOST}" Pass: "${REDIS_PASS}" + +CoreRpc: + Target: "${CORE_RPC_TARGET}" diff --git a/deploy/.env.example b/deploy/.env.example new file mode 100644 index 0000000..afeea7e --- /dev/null +++ b/deploy/.env.example @@ -0,0 +1,14 @@ +PPANEL_REPO=your-registry/zero-ppanel +PPANEL_TAG=latest + +MYSQL_DSN=root:password@tcp(127.0.0.1:3306)/ppanel?charset=utf8mb4&parseTime=true +REDIS_HOST=127.0.0.1:6379 +REDIS_PASS= + +JWT_SECRET=replace-with-strong-secret +JWT_ADMIN_SECRET=replace-with-strong-secret +APP_SECRET=replace-with-strong-secret +SECURITY_SECRET=replace-with-strong-secret +NODE_SECRET=replace-with-strong-secret + +CORE_RPC_TARGET=127.0.0.1:8083 diff --git a/deploy/docker-compose.cloud.yml b/deploy/docker-compose.cloud.yml index 43a834e..ded36ef 100644 --- a/deploy/docker-compose.cloud.yml +++ b/deploy/docker-compose.cloud.yml @@ -8,6 +8,8 @@ services: ppanel-api: image: ${PPANEL_REPO}/ppanel-api:${PPANEL_TAG:-latest} restart: unless-stopped + env_file: + - ./.env ports: - "8080:8080" volumes: @@ -21,6 +23,8 @@ services: ppanel-admin: image: ${PPANEL_REPO}/ppanel-admin:${PPANEL_TAG:-latest} restart: unless-stopped + env_file: + - ./.env ports: - "8081:8081" volumes: @@ -34,6 +38,8 @@ services: ppanel-node: image: ${PPANEL_REPO}/ppanel-node:${PPANEL_TAG:-latest} restart: unless-stopped + env_file: + - ./.env ports: - "8082:8082" volumes: @@ -47,6 +53,8 @@ services: ppanel-queue: image: ${PPANEL_REPO}/ppanel-queue:${PPANEL_TAG:-latest} restart: unless-stopped + env_file: + - ./.env volumes: - ./etc/queue:/app/etc logging: @@ -58,6 +66,8 @@ services: ppanel-scheduler: image: ${PPANEL_REPO}/ppanel-scheduler:${PPANEL_TAG:-latest} restart: unless-stopped + env_file: + - ./.env volumes: - ./etc/scheduler:/app/etc logging: diff --git a/deploy/docker-compose.yml b/deploy/docker-compose.yml index 939dfed..b591698 100644 --- a/deploy/docker-compose.yml +++ b/deploy/docker-compose.yml @@ -63,7 +63,7 @@ services: ports: - "3306:3306" environment: - MYSQL_ROOT_PASSWORD: password + MYSQL_ROOT_PASSWORD: pavR2$mX7*tQ MYSQL_DATABASE: ppanel volumes: - mysql_data:/var/lib/mysql diff --git a/deploy/etc/admin/admin.yaml b/deploy/etc/admin/admin.yaml new file mode 100644 index 0000000..fa783d6 --- /dev/null +++ b/deploy/etc/admin/admin.yaml @@ -0,0 +1,51 @@ +Name: zero-ppanel-admin +Host: 0.0.0.0 +Port: 8081 +Mode: pro + +Log: + Mode: file + Encoding: json + Level: info + Path: /var/log/zero-ppanel/admin + KeepDays: 15 + Rotation: daily + +Telemetry: + Name: zero-ppanel-admin + Endpoint: http://jaeger:4318/v1/traces + Sampler: 0.1 + Batcher: otlphttp + +DevServer: + Enabled: true + Port: 6161 + EnableMetrics: true + EnablePprof: false + +JwtAuth: + AccessSecret: "${JWT_ADMIN_SECRET}" + AccessExpire: 28800 + +MySQL: + DataSource: "${MYSQL_DSN}" + +Redis: + Host: "${REDIS_HOST}" + Type: node + Pass: "${REDIS_PASS}" + +CacheRedis: + Host: "${REDIS_HOST}" + Type: node + Pass: "${REDIS_PASS}" + +AppSignature: + AppSecrets: + android-client: "${APP_SECRET}" + web-client: "${APP_SECRET}" + ios-client: "${APP_SECRET}" + mac-client: "${APP_SECRET}" + ValidWindowSeconds: 300 + SkipPrefixes: + - /api/v1/admin/health diff --git a/deploy/etc/api/api.yaml b/deploy/etc/api/api.yaml new file mode 100644 index 0000000..cc9e77d --- /dev/null +++ b/deploy/etc/api/api.yaml @@ -0,0 +1,62 @@ +Name: zero-ppanel-api +Host: 0.0.0.0 +Port: 8080 +Mode: pro + +Log: + Mode: file + Encoding: json + Level: info + Path: /var/log/zero-ppanel/api + KeepDays: 15 + Rotation: daily + +Telemetry: + Name: zero-ppanel-api + Endpoint: http://jaeger:4318/v1/traces + Sampler: 0.1 + Batcher: otlphttp + +DevServer: + Enabled: true + Port: 6160 + EnableMetrics: true + EnablePprof: false + +JwtAuth: + AccessSecret: "${JWT_SECRET}" + AccessExpire: 86400 + +MySQL: + DataSource: "${MYSQL_DSN}" + +Redis: + Host: "${REDIS_HOST}" + Type: node + Pass: "${REDIS_PASS}" + +CacheRedis: + Host: "${REDIS_HOST}" + Type: node + Pass: "${REDIS_PASS}" + +AppSignature: + AppSecrets: + android-client: "${APP_SECRET}" + web-client: "${APP_SECRET}" + ios-client: "${APP_SECRET}" + mac-client: "${APP_SECRET}" + ValidWindowSeconds: 300 + SkipPrefixes: + - /api/v1/health + +Security: + Enable: true + SecuritySecret: "${SECURITY_SECRET}" + +Asynq: + Addr: "${REDIS_HOST}" + Pass: "${REDIS_PASS}" + +CoreRpc: + Target: "${CORE_RPC_TARGET}" diff --git a/deploy/etc/node/node.yaml b/deploy/etc/node/node.yaml new file mode 100644 index 0000000..d55f914 --- /dev/null +++ b/deploy/etc/node/node.yaml @@ -0,0 +1,49 @@ +Name: zero-ppanel-node +Host: 0.0.0.0 +Port: 8082 +Mode: pro + +Log: + Mode: file + Encoding: json + Level: info + Path: /var/log/zero-ppanel/node + KeepDays: 15 + Rotation: daily + +Telemetry: + Name: zero-ppanel-node + Endpoint: http://jaeger:4318/v1/traces + Sampler: 0.1 + Batcher: otlphttp + +DevServer: + Enabled: true + Port: 6162 + EnableMetrics: true + EnablePprof: false + +NodeSecret: "${NODE_SECRET}" + +MySQL: + DataSource: "${MYSQL_DSN}" + +Redis: + Host: "${REDIS_HOST}" + Type: node + Pass: "${REDIS_PASS}" + +CacheRedis: + Host: "${REDIS_HOST}" + Type: node + Pass: "${REDIS_PASS}" + +AppSignature: + AppSecrets: + android-client: "${APP_SECRET}" + web-client: "${APP_SECRET}" + ios-client: "${APP_SECRET}" + mac-client: "${APP_SECRET}" + ValidWindowSeconds: 300 + SkipPrefixes: + - /api/v1/node/health diff --git a/deploy/etc/queue/queue.yaml b/deploy/etc/queue/queue.yaml new file mode 100644 index 0000000..79f0fc8 --- /dev/null +++ b/deploy/etc/queue/queue.yaml @@ -0,0 +1,28 @@ +Name: zero-ppanel-queue +Mode: pro + +Log: + Mode: file + Encoding: json + Level: info + Path: /var/log/zero-ppanel/queue + KeepDays: 15 + Rotation: daily + +Telemetry: + Name: zero-ppanel-queue + Endpoint: http://jaeger:4318/v1/traces + Sampler: 0.1 + Batcher: otlphttp + +MySQL: + DataSource: "${MYSQL_DSN}" + +Redis: + Host: "${REDIS_HOST}" + Type: node + Pass: "${REDIS_PASS}" + +Asynq: + Addr: "${REDIS_HOST}" + Pass: "${REDIS_PASS}" diff --git a/deploy/etc/scheduler/scheduler.yaml b/deploy/etc/scheduler/scheduler.yaml new file mode 100644 index 0000000..89c4407 --- /dev/null +++ b/deploy/etc/scheduler/scheduler.yaml @@ -0,0 +1,28 @@ +Name: zero-ppanel-scheduler +Mode: pro + +Log: + Mode: file + Encoding: json + Level: info + Path: /var/log/zero-ppanel/scheduler + KeepDays: 15 + Rotation: daily + +Telemetry: + Name: zero-ppanel-scheduler + Endpoint: http://jaeger:4318/v1/traces + Sampler: 0.1 + Batcher: otlphttp + +MySQL: + DataSource: "${MYSQL_DSN}" + +Redis: + Host: "${REDIS_HOST}" + Type: node + Pass: "${REDIS_PASS}" + +Asynq: + Addr: "${REDIS_HOST}" + Pass: "${REDIS_PASS}" diff --git a/go.mod b/go.mod index 6324ce1..3eae089 100644 --- a/go.mod +++ b/go.mod @@ -8,34 +8,38 @@ require ( github.com/pkg/errors v0.9.1 github.com/zeromicro/go-zero v1.7.6 golang.org/x/crypto v0.48.0 - google.golang.org/grpc v1.65.0 - google.golang.org/protobuf v1.36.1 + google.golang.org/grpc v1.74.2 + google.golang.org/protobuf v1.36.7 ) require ( + filippo.io/edwards25519 v1.1.0 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/cenkalti/backoff/v4 v4.3.0 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/coreos/go-semver v0.3.1 // indirect github.com/coreos/go-systemd/v22 v22.5.0 // indirect - github.com/davecgh/go-spew v1.1.1 // indirect + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect github.com/emicklei/go-restful/v3 v3.11.0 // indirect github.com/fatih/color v1.18.0 // indirect - github.com/go-logr/logr v1.4.2 // indirect + github.com/go-logr/logr v1.4.3 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-openapi/jsonpointer v0.19.6 // indirect github.com/go-openapi/jsonreference v0.20.2 // indirect github.com/go-openapi/swag v0.22.4 // indirect + github.com/go-sql-driver/mysql v1.9.3 // indirect github.com/gogo/protobuf v1.3.2 // indirect - github.com/golang-jwt/jwt/v4 v4.5.1 // indirect + github.com/golang-jwt/jwt/v4 v4.5.2 // indirect + github.com/golang-migrate/migrate/v4 v4.19.1 // indirect github.com/golang/mock v1.6.0 // indirect github.com/golang/protobuf v1.5.4 // indirect github.com/google/gnostic-models v0.6.8 // indirect - github.com/google/go-cmp v0.6.0 // indirect + github.com/google/go-cmp v0.7.0 // indirect github.com/google/gofuzz v1.2.0 // indirect github.com/google/uuid v1.6.0 // indirect github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 // indirect + github.com/joho/godotenv v1.5.1 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/klauspost/compress v1.17.9 // indirect @@ -58,29 +62,29 @@ require ( go.etcd.io/etcd/api/v3 v3.5.15 // indirect go.etcd.io/etcd/client/pkg/v3 v3.5.15 // indirect go.etcd.io/etcd/client/v3 v3.5.15 // indirect - go.opentelemetry.io/otel v1.24.0 // indirect + go.opentelemetry.io/otel v1.37.0 // indirect go.opentelemetry.io/otel/exporters/jaeger v1.17.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.24.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.29.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.24.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.24.0 // indirect go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.24.0 // indirect go.opentelemetry.io/otel/exporters/zipkin v1.24.0 // indirect - go.opentelemetry.io/otel/metric v1.24.0 // indirect - go.opentelemetry.io/otel/sdk v1.24.0 // indirect - go.opentelemetry.io/otel/trace v1.24.0 // indirect + go.opentelemetry.io/otel/metric v1.37.0 // indirect + go.opentelemetry.io/otel/sdk v1.36.0 // indirect + go.opentelemetry.io/otel/trace v1.37.0 // indirect go.opentelemetry.io/proto/otlp v1.3.1 // indirect go.uber.org/atomic v1.10.0 // indirect go.uber.org/automaxprocs v1.6.0 // indirect go.uber.org/multierr v1.9.0 // indirect go.uber.org/zap v1.24.0 // indirect golang.org/x/net v0.49.0 // indirect - golang.org/x/oauth2 v0.21.0 // indirect + golang.org/x/oauth2 v0.30.0 // indirect golang.org/x/sys v0.41.0 // indirect golang.org/x/term v0.40.0 // indirect golang.org/x/text v0.34.0 // indirect - golang.org/x/time v0.8.0 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20240711142825-46eb208f015d // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094 // indirect + golang.org/x/time v0.12.0 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20250818200422-3122310a409c // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20250818200422-3122310a409c // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/go.sum b/go.sum index a9bf443..a02eaf8 100644 --- a/go.sum +++ b/go.sum @@ -1,3 +1,5 @@ +filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= +filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= github.com/alicebob/gopher-json v0.0.0-20230218143504-906a9b012302 h1:uvdUDbHQHO85qeSydJtItA4T55Pw6BtAejd0APRJOCE= github.com/alicebob/gopher-json v0.0.0-20230218143504-906a9b012302/go.mod h1:SGnFV6hVsYE877CKEZ6tDNTjaSXYUk6QqoIK6PrAtcc= github.com/alicebob/miniredis/v2 v2.34.0 h1:mBFWMaJSNL9RwdGRyEDoAAv8OQc5UlEhLDQggTglU/0= @@ -22,6 +24,7 @@ github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ3 github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g= @@ -34,6 +37,8 @@ github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbV github.com/go-logr/logr v1.3.0/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= +github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE= @@ -43,6 +48,8 @@ github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= github.com/go-openapi/swag v0.22.4 h1:QLMzNJnMGPRNDCbySlcj1x01tzU8/9LTTL9hZZZogBU= github.com/go-openapi/swag v0.22.4/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= +github.com/go-sql-driver/mysql v1.9.3 h1:U/N249h2WzJ3Ukj8SowVFjdtZKfu9vlLZxjPXV1aweo= +github.com/go-sql-driver/mysql v1.9.3/go.mod h1:qn46aNg1333BRMNU69Lq93t8du/dwxI64Gl8i5p1WMU= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= @@ -50,8 +57,12 @@ github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang-jwt/jwt/v4 v4.5.1 h1:JdqV9zKUdtaa9gdPlywC3aeoEsR681PlKC+4F5gQgeo= github.com/golang-jwt/jwt/v4 v4.5.1/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= +github.com/golang-jwt/jwt/v4 v4.5.2 h1:YtQM7lnr8iZ+j5q71MGKkNw9Mn7AjHM68uc9g5fXeUI= +github.com/golang-jwt/jwt/v4 v4.5.2/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= github.com/golang-jwt/jwt/v5 v5.2.1 h1:OuVbFODueb089Lh128TAcimifWaLhJwVflnrgM17wHk= github.com/golang-jwt/jwt/v5 v5.2.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= +github.com/golang-migrate/migrate/v4 v4.19.1 h1:OCyb44lFuQfYXYLx1SCxPZQGU7mcaZ7gH9yH4jSFbBA= +github.com/golang-migrate/migrate/v4 v4.19.1/go.mod h1:CTcgfjxhaUtsLipnLoQRWCrjYXycRz/g5+RWDuYgPrE= github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc= github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= @@ -61,6 +72,8 @@ github.com/google/gnostic-models v0.6.8/go.mod h1:5n7qKqH0f5wFt+aWF8CW6pZLLNOfYu github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= +github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= @@ -74,6 +87,8 @@ github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542 h1:2VTzZjLZBgl62/EtslC github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542/go.mod h1:Ow0tF8D4Kplbc8s8sSb3V2oUCygFHVp8gC3Dn6U4MNI= github.com/hibiken/asynq v0.25.1 h1:phj028N0nm15n8O2ims+IvJ2gz4k2auvermngh9JhTw= github.com/hibiken/asynq v0.25.1/go.mod h1:pazWNOLBu0FEynQRBvHA26qdIKRSmfdIfUm4HdsLmXg= +github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= +github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= @@ -133,6 +148,7 @@ github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs= github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro= github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= +github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI= github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spf13/cast v1.7.0 h1:ntdiHjuueXFgm5nzDRdOS4yfT43P5Fnud6DH50rz/7w= @@ -167,10 +183,13 @@ go.etcd.io/etcd/client/v3 v3.5.15 h1:23M0eY4Fd/inNv1ZfU3AxrbbOdW79r9V9Rl62Nm6ip4 go.etcd.io/etcd/client/v3 v3.5.15/go.mod h1:CLSJxrYjvLtHsrPKsy7LmZEE+DK2ktfd2bN4RhBMwlU= go.opentelemetry.io/otel v1.24.0 h1:0LAOdjNmQeSTzGBzduGe/rU4tZhMwL5rWgtp9Ku5Jfo= go.opentelemetry.io/otel v1.24.0/go.mod h1:W7b9Ozg4nkF5tWI5zsXkaKKDjdVjpD4oAt9Qi/MArHo= +go.opentelemetry.io/otel v1.37.0 h1:9zhNfelUvx0KBfu/gb+ZgeAfAgtWrfHJZcAqFC228wQ= +go.opentelemetry.io/otel v1.37.0/go.mod h1:ehE/umFRLnuLa/vSccNq9oS1ErUlkkK71gMcN34UG8I= go.opentelemetry.io/otel/exporters/jaeger v1.17.0 h1:D7UpUy2Xc2wsi1Ras6V40q806WM07rqoCWzXu7Sqy+4= go.opentelemetry.io/otel/exporters/jaeger v1.17.0/go.mod h1:nPCqOnEH9rNLKqH/+rrUjiMzHJdV1BlpKcTwRTyKkKI= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.24.0 h1:t6wl9SPayj+c7lEIFgm4ooDBZVb01IhLB4InpomhRw8= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.24.0/go.mod h1:iSDOcsnSA5INXzZtwaBPrKp/lWu/V14Dd+llD0oI2EA= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.29.0/go.mod h1:jlRVBe7+Z1wyxFSUs48L6OBQZ5JwH2Hg/Vbl+t9rAgI= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.24.0 h1:Mw5xcxMwlqoJd97vwPxA8isEaIoxsta9/Q51+TTJLGE= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.24.0/go.mod h1:CQNu9bj7o7mC6U7+CA/schKEYakYXWr79ucDHTMGhCM= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.24.0 h1:Xw8U6u2f8DK2XAkGRFV7BBLENgnTGX9i4rQRxJf+/vs= @@ -181,10 +200,16 @@ go.opentelemetry.io/otel/exporters/zipkin v1.24.0 h1:3evrL5poBuh1KF51D9gO/S+N/1m go.opentelemetry.io/otel/exporters/zipkin v1.24.0/go.mod h1:0EHgD8R0+8yRhUYJOGR8Hfg2dpiJQxDOszd5smVO9wM= go.opentelemetry.io/otel/metric v1.24.0 h1:6EhoGWWK28x1fbpA4tYTOWBkPefTDQnb8WSGXlc88kI= go.opentelemetry.io/otel/metric v1.24.0/go.mod h1:VYhLe1rFfxuTXLgj4CBiyz+9WYBA8pNGJgDcSFRKBco= +go.opentelemetry.io/otel/metric v1.37.0 h1:mvwbQS5m0tbmqML4NqK+e3aDiO02vsf/WgbsdpcPoZE= +go.opentelemetry.io/otel/metric v1.37.0/go.mod h1:04wGrZurHYKOc+RKeye86GwKiTb9FKm1WHtO+4EVr2E= go.opentelemetry.io/otel/sdk v1.24.0 h1:YMPPDNymmQN3ZgczicBY3B6sf9n62Dlj9pWD3ucgoDw= go.opentelemetry.io/otel/sdk v1.24.0/go.mod h1:KVrIYw6tEubO9E96HQpcmpTKDVn9gdv35HoYiQWGDFg= +go.opentelemetry.io/otel/sdk v1.36.0 h1:b6SYIuLRs88ztox4EyrvRti80uXIFy+Sqzoh9kFULbs= +go.opentelemetry.io/otel/sdk v1.36.0/go.mod h1:+lC+mTgD+MUWfjJubi2vvXWcVxyr9rmlshZni72pXeY= go.opentelemetry.io/otel/trace v1.24.0 h1:CsKnnL4dUAr/0llH9FKuc698G04IrpWV0MQA/Y1YELI= go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU= +go.opentelemetry.io/otel/trace v1.37.0 h1:HLdcFNbRQBE2imdSEgm/kwqmQj1Or1l/7bW6mxVK7z4= +go.opentelemetry.io/otel/trace v1.37.0/go.mod h1:TlgrlQ+PtQO5XFerSPUYG0JSgGyryXewPGyayAWSBS0= go.opentelemetry.io/proto/otlp v1.3.1 h1:TrMUixzpM0yuc/znrFTP9MMRh8trP93mkCiDVeXrui0= go.opentelemetry.io/proto/otlp v1.3.1/go.mod h1:0X1WI4de4ZsLrrJNLAQbFeLCm3T7yBkR0XqQ7niQU+8= go.uber.org/atomic v1.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ= @@ -214,6 +239,8 @@ golang.org/x/net v0.49.0 h1:eeHFmOGUTtaaPSGNmjBKpbng9MulQsJURQUAfUwY++o= golang.org/x/net v0.49.0/go.mod h1:/ysNB2EvaqvesRkuLAyjI1ycPZlQHM3q01F02UY/MV8= golang.org/x/oauth2 v0.21.0 h1:tsimM75w1tF/uws5rbeHzIWxEqElMehnc+iW793zsZs= golang.org/x/oauth2 v0.21.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= +golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI= +golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -237,6 +264,8 @@ golang.org/x/text v0.34.0 h1:oL/Qq0Kdaqxa1KbNeMKwQq0reLCCaFtqu2eNuSeNHbk= golang.org/x/text v0.34.0/go.mod h1:homfLqTYRFyVYemLBFl5GgL/DWEiH5wcsQ5gSh1yziA= golang.org/x/time v0.8.0 h1:9i3RxcPv3PZnitoVGMPDKZSq1xW1gK1Xy3ArNOGZfEg= golang.org/x/time v0.8.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= +golang.org/x/time v0.12.0 h1:ScB/8o8olJvc+CQPWrK3fPZNfh7qgwCrY0zJmoEQLSE= +golang.org/x/time v0.12.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= @@ -250,12 +279,20 @@ golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/genproto/googleapis/api v0.0.0-20240711142825-46eb208f015d h1:kHjw/5UfflP/L5EbledDrcG4C2597RtymmGRZvHiCuY= google.golang.org/genproto/googleapis/api v0.0.0-20240711142825-46eb208f015d/go.mod h1:mw8MG/Qz5wfgYr6VqVCiZcHe/GJEfI+oGGDCohaVgB0= +google.golang.org/genproto/googleapis/api v0.0.0-20250818200422-3122310a409c h1:AtEkQdl5b6zsybXcbz00j1LwNodDuH6hVifIaNqk7NQ= +google.golang.org/genproto/googleapis/api v0.0.0-20250818200422-3122310a409c/go.mod h1:ea2MjsO70ssTfCjiwHgI0ZFqcw45Ksuk2ckf9G468GA= google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094 h1:BwIjyKYGsK9dMCBOorzRri8MQwmi7mT9rGHsCEinZkA= google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094/go.mod h1:Ue6ibwXGpU+dqIcODieyLOcgj7z8+IcskoNIgZxtrFY= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250818200422-3122310a409c h1:qXWI/sQtv5UKboZ/zUk7h+mrf/lXORyI+n9DKDAusdg= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250818200422-3122310a409c/go.mod h1:gw1tLEfykwDz2ET4a12jcXt4couGAm7IwsVaTy0Sflo= google.golang.org/grpc v1.65.0 h1:bs/cUb4lp1G5iImFFd3u5ixQzweKizoZJAwBNLR42lc= google.golang.org/grpc v1.65.0/go.mod h1:WgYC2ypjlB0EiQi6wdKixMqukr6lBc0Vo+oOgjrM5ZQ= +google.golang.org/grpc v1.74.2 h1:WoosgB65DlWVC9FqI82dGsZhWFNBSLjQ84bjROOpMu4= +google.golang.org/grpc v1.74.2/go.mod h1:CtQ+BGjaAIXHs/5YS3i473GqwBBa1zGQNevxdeBEXrM= google.golang.org/protobuf v1.36.1 h1:yBPeRvTftaleIgM3PZ/WBIZ7XM/eEYAaEyCwvyjq/gk= google.golang.org/protobuf v1.36.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= +google.golang.org/protobuf v1.36.7 h1:IgrO7UwFQGJdRNXH/sQux4R1Dj1WAKcLElzeeRaXV2A= +google.golang.org/protobuf v1.36.7/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= diff --git a/pkg/migrate/main.go b/pkg/migrate/main.go new file mode 100644 index 0000000..4f05b1e --- /dev/null +++ b/pkg/migrate/main.go @@ -0,0 +1,156 @@ +package main + +import ( + "context" + "database/sql" + "fmt" + "log" + "os" + "strconv" + "time" + + "github.com/golang-migrate/migrate/v4" + _ "github.com/golang-migrate/migrate/v4/database/mysql" + _ "github.com/golang-migrate/migrate/v4/source/file" + "github.com/joho/godotenv" + _ "github.com/go-sql-driver/mysql" +) + +func main() { + // 加载 .env 文件 + err := godotenv.Load(".env") + if err != nil { + log.Println("未能加载 .env 文件,可能使用环境变量。") + } + + if len(os.Args) < 2 { + log.Fatalf("使用方法: go run main.go [args...]") + } + + command := os.Args[1] + if command == "create" { + if len(os.Args) < 3 { + log.Fatalf("使用方法: go run main.go create ") + } + createMigration(os.Args[2]) + return + } + + databaseUrl := os.Getenv("DATABASE_DSN") + if databaseUrl == "" { + log.Fatalf("DATABASE_DSN 环境变量未设置") + } + + m, err := migrate.New( + "file://sql", // 迁移文件路径 + databaseUrl, + ) + if err != nil { + log.Fatalf("初始化迁移工具失败: %v", err) + } + + defer func() { + if sourceErr, databaseErr := m.Close(); sourceErr != nil || databaseErr != nil { + log.Printf("关闭迁移工具时出错: sourceErr=%v, databaseErr=%v", sourceErr, databaseErr) + } + }() + + + switch command { + case "up": + if err := m.Up(); err != nil && err != migrate.ErrNoChange { + log.Fatalf("执行迁移 Up 失败: %v", err) + } + log.Println("迁移 Up 成功") + case "down": + if len(os.Args) < 3 { // 不带版本号时回滚最新一个版本 + if err := m.Down(); err != nil && err != migrate.ErrNoChange { + log.Fatalf("执行迁移 Down 失败: %v", err) + } + log.Println("迁移 Down 成功 (回滚一个版本)") + } else { // 带版本号时回滚到指定版本 + version, err := strconv.Atoi(os.Args[2]) + if err != nil { + log.Fatalf("版本号错误: %v", err) + } + if err := m.Migrate(uint(version)); err != nil && err != migrate.ErrNoChange { + log.Fatalf("执行迁移 Migrate 到版本 %d 失败: %v", version, err) + } + log.Printf("迁移 Down 成功 (回滚到版本 %d)", version) + } + case "goto": + if len(os.Args) < 3 { + log.Fatalf("使用方法: go run main.go goto ") + } + version, err := strconv.Atoi(os.Args[2]) + if err != nil { + log.Fatalf("版本号错误: %v", err) + } + if err := m.Migrate(uint(version)); err != nil && err != migrate.ErrNoChange { + log.Fatalf("执行迁移 Goto 版本 %d 失败: %v", version, err) + } + log.Printf("迁移 Goto 成功 (到版本 %d)", version) + case "force": + if len(os.Args) < 3 { + log.Fatalf("使用方法: go run main.go force ") + } + version, err := strconv.Atoi(os.Args[2]) + if err != nil { + log.Fatalf("版本号错误: %v", err) + } + if err := m.Force(int(version)); err != nil { + log.Fatalf("强制设置版本 %d 失败: %v", version, err) + } + log.Printf("强制设置版本 %d 成功", version) + case "version": + version, dirty, err := m.Version() + if err != nil && err != migrate.ErrNoChange { + log.Fatalf("获取版本失败: %v", err) + } + if dirty { + log.Printf("当前数据库版本: %d (dirty)", version) + } else { + log.Printf("当前数据库版本: %d", version) + } + default: + log.Fatalf("未知命令: %s. 支持的命令: up, down, goto, force, version, create", command) + } +} + +func createMigration(name string) { + timestamp := time.Now().Unix() + upFilename := fmt.Sprintf("sql/%d_%s.up.sql", timestamp, name) + downFilename := fmt.Sprintf("sql/%d_%s.down.sql", timestamp, name) + + if err := os.WriteFile(upFilename, []byte(""), 0644); err != nil { + log.Fatalf("创建 %s 失败: %v", upFilename, err) + } + if err := os.WriteFile(downFilename, []byte(""), 0644); err != nil { + log.Fatalf("创建 %s 失败: %v", downFilename, err) + } + + log.Printf("成功创建迁移文件: %s 和 %s", upFilename, downFilename) +} + +// 辅助函数,用于检查数据库连接是否正常 +func checkDBConnection(dsn string) error { + db, err := sql.Open("mysql", dsn) + if err != nil { + return fmt.Errorf("无法连接数据库: %v", err) + } + defer db.Close() + + db.SetMaxOpenConns(1) + db.SetMaxIdleConns(1) + db.SetConnMaxLifetime(5 * time.Second) + + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + defer cancel() + + err = db.PingContext(ctx) + if err != nil { + return fmt.Errorf("无法 Ping 数据库: %v", err) + } + return nil +} + diff --git a/sql/00001_init_schema.down.sql b/sql/00001_init_schema.down.sql new file mode 100644 index 0000000..d7958bd --- /dev/null +++ b/sql/00001_init_schema.down.sql @@ -0,0 +1,30 @@ +SET FOREIGN_KEY_CHECKS = 0; + +DROP TABLE IF EXISTS `ads`; +DROP TABLE IF EXISTS `announcement`; +DROP TABLE IF EXISTS `auth_method`; +DROP TABLE IF EXISTS `coupon`; +DROP TABLE IF EXISTS `document`; +DROP TABLE IF EXISTS `nodes`; +DROP TABLE IF EXISTS `order`; +DROP TABLE IF EXISTS `payment`; +DROP TABLE IF EXISTS `redemption_code`; +DROP TABLE IF EXISTS `redemption_record`; +DROP TABLE IF EXISTS `server`; +DROP TABLE IF EXISTS `servers`; +DROP TABLE IF EXISTS `subscribe`; +DROP TABLE IF EXISTS `subscribe_application`; +DROP TABLE IF EXISTS `system`; +DROP TABLE IF EXISTS `system_logs`; +DROP TABLE IF EXISTS `task`; +DROP TABLE IF EXISTS `ticket`; +DROP TABLE IF EXISTS `ticket_follow`; +DROP TABLE IF EXISTS `traffic_log`; +DROP TABLE IF EXISTS `user`; +DROP TABLE IF EXISTS `user_auth_methods`; +DROP TABLE IF EXISTS `user_device`; +DROP TABLE IF EXISTS `user_device_online_record`; +DROP TABLE IF EXISTS `user_subscribe`; +DROP TABLE IF EXISTS `withdrawals`; + +SET FOREIGN_KEY_CHECKS = 1; diff --git a/sql/00001_init_schema.up.sql b/sql/00001_init_schema.up.sql new file mode 100644 index 0000000..f26e4ce --- /dev/null +++ b/sql/00001_init_schema.up.sql @@ -0,0 +1,519 @@ + +/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; +/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; +/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; +/*!50503 SET NAMES utf8mb4 */; +/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */; +/*!40103 SET TIME_ZONE='+00:00' */; +/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; +/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; +/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; +/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `ads` ( + `id` bigint NOT NULL AUTO_INCREMENT, + `title` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT 'Ads title', + `type` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT 'Ads type', + `content` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci COMMENT 'Ads content', + `target_url` varchar(512) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '' COMMENT 'Ads target url', + `start_time` datetime DEFAULT NULL COMMENT 'Ads start time', + `end_time` datetime DEFAULT NULL COMMENT 'Ads end time', + `status` tinyint(1) DEFAULT '0' COMMENT 'Ads status,0 disable,1 enable', + `created_at` datetime(3) DEFAULT NULL COMMENT 'Create Time', + `updated_at` datetime(3) DEFAULT NULL COMMENT 'Update Time', + `description` varchar(255) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT 'Description', + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; +/*!40101 SET character_set_client = @saved_cs_client */; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `announcement` ( + `id` bigint NOT NULL AUTO_INCREMENT, + `title` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT 'Title', + `content` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci COMMENT 'Content', + `show` tinyint(1) NOT NULL DEFAULT '0' COMMENT 'Show', + `pinned` tinyint(1) NOT NULL DEFAULT '0' COMMENT 'Pinned', + `popup` tinyint(1) NOT NULL DEFAULT '0' COMMENT 'Popup', + `created_at` datetime(3) DEFAULT NULL COMMENT 'Create Time', + `updated_at` datetime(3) DEFAULT NULL COMMENT 'Update Time', + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; +/*!40101 SET character_set_client = @saved_cs_client */; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `auth_method` ( + `id` bigint NOT NULL AUTO_INCREMENT, + `method` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT 'method', + `config` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT 'OAuth Configuration', + `enabled` tinyint(1) NOT NULL DEFAULT '0' COMMENT 'Is Enabled', + `created_at` datetime(3) DEFAULT NULL COMMENT 'Create Time', + `updated_at` datetime(3) DEFAULT NULL COMMENT 'Update Time', + PRIMARY KEY (`id`), + UNIQUE KEY `uni_auth_method` (`method`) +) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; +/*!40101 SET character_set_client = @saved_cs_client */; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `coupon` ( + `id` bigint NOT NULL AUTO_INCREMENT, + `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT 'Coupon Name', + `code` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT 'Coupon Code', + `count` bigint NOT NULL DEFAULT '0' COMMENT 'Count Limit', + `type` tinyint(1) NOT NULL DEFAULT '1' COMMENT 'Coupon Type: 1: Percentage 2: Fixed Amount', + `discount` bigint NOT NULL DEFAULT '0' COMMENT 'Coupon Discount', + `start_time` bigint NOT NULL DEFAULT '0' COMMENT 'Start Time', + `expire_time` bigint NOT NULL DEFAULT '0' COMMENT 'Expire Time', + `user_limit` bigint NOT NULL DEFAULT '0' COMMENT 'User Limit', + `subscribe` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT 'Subscribe Limit', + `used_count` bigint NOT NULL DEFAULT '0' COMMENT 'Used Count', + `enable` tinyint(1) NOT NULL DEFAULT '1' COMMENT 'Enable', + `created_at` datetime(3) DEFAULT NULL COMMENT 'Create Time', + `updated_at` datetime(3) DEFAULT NULL COMMENT 'Update Time', + PRIMARY KEY (`id`), + UNIQUE KEY `uni_coupon_code` (`code`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; +/*!40101 SET character_set_client = @saved_cs_client */; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `document` ( + `id` bigint NOT NULL AUTO_INCREMENT, + `title` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT 'Document Title', + `content` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci COMMENT 'Document Content', + `tags` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT 'Document Tags', + `show` tinyint(1) NOT NULL DEFAULT '1' COMMENT 'Show', + `created_at` datetime(3) DEFAULT NULL COMMENT 'Create Time', + `updated_at` datetime(3) DEFAULT NULL COMMENT 'Update Time', + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; +/*!40101 SET character_set_client = @saved_cs_client */; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `nodes` ( + `id` bigint NOT NULL AUTO_INCREMENT, + `name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT 'Node Name', + `tags` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT 'Tags', + `port` smallint unsigned NOT NULL DEFAULT '0' COMMENT 'Connect Port', + `address` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT 'Connect Address', + `server_id` bigint NOT NULL DEFAULT '0' COMMENT 'Server ID', + `protocol` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT 'Protocol', + `enabled` tinyint(1) NOT NULL DEFAULT '1' COMMENT 'Enabled', + `sort` int unsigned NOT NULL DEFAULT '0' COMMENT 'Sort', + `created_at` datetime(3) DEFAULT NULL COMMENT 'Creation Time', + `updated_at` datetime(3) DEFAULT NULL COMMENT 'Update Time', + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; +/*!40101 SET character_set_client = @saved_cs_client */; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `order` ( + `id` bigint NOT NULL AUTO_INCREMENT, + `parent_id` bigint DEFAULT NULL COMMENT 'Parent Order Id', + `user_id` bigint NOT NULL DEFAULT '0' COMMENT 'User Id', + `order_no` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT 'Order No', + `type` tinyint(1) NOT NULL DEFAULT '1' COMMENT 'Order Type: 1: Subscribe, 2: Renewal, 3: ResetTraffic, 4: Recharge', + `quantity` bigint NOT NULL DEFAULT '1' COMMENT 'Quantity', + `price` bigint NOT NULL DEFAULT '0' COMMENT 'Original price', + `amount` bigint NOT NULL DEFAULT '0' COMMENT 'Order Amount', + `gift_amount` bigint NOT NULL DEFAULT '0' COMMENT 'User Gift Amount', + `discount` bigint NOT NULL DEFAULT '0' COMMENT 'Discount Amount', + `coupon` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT 'Coupon', + `coupon_discount` bigint NOT NULL DEFAULT '0' COMMENT 'Coupon Discount Amount', + `commission` bigint NOT NULL DEFAULT '0' COMMENT 'Order Commission', + `payment_id` bigint NOT NULL DEFAULT '-1' COMMENT 'Payment Id', + `method` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT 'Payment Method', + `fee_amount` bigint NOT NULL DEFAULT '0' COMMENT 'Fee Amount', + `trade_no` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT 'Trade No', + `status` tinyint(1) NOT NULL DEFAULT '1' COMMENT 'Order Status: 1: Pending, 2: Paid, 3:Close, 4: Failed, 5:Finished', + `subscribe_id` bigint NOT NULL DEFAULT '0' COMMENT 'Subscribe Id', + `subscribe_token` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT 'Renewal Subscribe Token', + `is_new` tinyint(1) NOT NULL DEFAULT '0' COMMENT 'Is New Order', + `created_at` datetime(3) DEFAULT NULL COMMENT 'Create Time', + `updated_at` datetime(3) DEFAULT NULL COMMENT 'Update Time', + PRIMARY KEY (`id`), + UNIQUE KEY `uni_order_order_no` (`order_no`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; +/*!40101 SET character_set_client = @saved_cs_client */; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `payment` ( + `id` bigint NOT NULL AUTO_INCREMENT, + `name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT 'Payment Name', + `platform` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT 'Payment Platform', + `description` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci COMMENT 'Payment Description', + `token` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT 'Payment Token', + `icon` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '' COMMENT 'Payment Icon', + `domain` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '' COMMENT 'Notification Domain', + `config` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT 'Payment Configuration', + `fee_mode` tinyint(1) NOT NULL DEFAULT '0' COMMENT 'Fee Mode: 0: No Fee 1: Percentage 2: Fixed Amount 3: Percentage + Fixed Amount', + `fee_percent` bigint DEFAULT '0' COMMENT 'Fee Percentage', + `fee_amount` bigint DEFAULT '0' COMMENT 'Fixed Fee Amount', + `enable` tinyint(1) NOT NULL DEFAULT '0' COMMENT 'Is Enabled', + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; +/*!40101 SET character_set_client = @saved_cs_client */; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `redemption_code` ( + `id` bigint NOT NULL AUTO_INCREMENT COMMENT 'Primary Key', + `code` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT 'Redemption Code', + `total_count` bigint NOT NULL DEFAULT '0' COMMENT 'Total Redemption Count', + `used_count` bigint NOT NULL DEFAULT '0' COMMENT 'Used Redemption Count', + `subscribe_plan` bigint NOT NULL DEFAULT '0' COMMENT 'Subscribe Plan', + `unit_time` varchar(50) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT 'month' COMMENT 'Unit Time: day, month, quarter, half_year, year', + `quantity` bigint NOT NULL DEFAULT '1' COMMENT 'Quantity', + `status` tinyint NOT NULL DEFAULT '1' COMMENT 'Status: 1=enabled, 0=disabled', + `created_at` datetime NOT NULL COMMENT 'Creation Time', + `updated_at` datetime NOT NULL COMMENT 'Update Time', + `deleted_at` datetime DEFAULT NULL COMMENT 'Deletion Time', + PRIMARY KEY (`id`), + UNIQUE KEY `uk_code` (`code`), + KEY `idx_deleted_at` (`deleted_at`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='Redemption Code Table'; +/*!40101 SET character_set_client = @saved_cs_client */; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `redemption_record` ( + `id` bigint NOT NULL AUTO_INCREMENT COMMENT 'Primary Key', + `redemption_code_id` bigint NOT NULL DEFAULT '0' COMMENT 'Redemption Code Id', + `user_id` bigint NOT NULL DEFAULT '0' COMMENT 'User Id', + `subscribe_id` bigint NOT NULL DEFAULT '0' COMMENT 'Subscribe Id', + `unit_time` varchar(50) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT 'month' COMMENT 'Unit Time', + `quantity` bigint NOT NULL DEFAULT '1' COMMENT 'Quantity', + `redeemed_at` datetime NOT NULL COMMENT 'Redeemed Time', + `created_at` datetime NOT NULL COMMENT 'Creation Time', + PRIMARY KEY (`id`), + KEY `idx_redemption_code_id` (`redemption_code_id`), + KEY `idx_user_id` (`user_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='Redemption Record Table'; +/*!40101 SET character_set_client = @saved_cs_client */; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `schema_migrations` ( + `version` bigint NOT NULL, + `dirty` tinyint(1) NOT NULL, + PRIMARY KEY (`version`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; +/*!40101 SET character_set_client = @saved_cs_client */; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `server` ( + `id` bigint NOT NULL AUTO_INCREMENT, + `name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT 'Node Name', + `tags` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT 'Tags', + `country` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT 'Country', + `city` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT 'City', + `latitude` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT 'latitude', + `longitude` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT 'longitude', + `server_addr` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT 'Server Address', + `relay_mode` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT 'none' COMMENT 'Relay Mode', + `relay_node` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci COMMENT 'Relay Node', + `speed_limit` bigint NOT NULL DEFAULT '0' COMMENT 'Speed Limit', + `traffic_ratio` decimal(4,2) NOT NULL DEFAULT '0.00' COMMENT 'Traffic Ratio', + `group_id` bigint DEFAULT NULL COMMENT 'Group ID', + `protocol` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT 'Protocol', + `config` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci COMMENT 'Config', + `enable` tinyint(1) NOT NULL DEFAULT '1' COMMENT 'Enabled', + `sort` bigint NOT NULL DEFAULT '0' COMMENT 'Sort', + `last_reported_at` datetime(3) DEFAULT NULL COMMENT 'Last Reported Time', + `created_at` datetime(3) DEFAULT NULL COMMENT 'Creation Time', + `updated_at` datetime(3) DEFAULT NULL COMMENT 'Update Time', + PRIMARY KEY (`id`), + KEY `idx_group_id` (`group_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; +/*!40101 SET character_set_client = @saved_cs_client */; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `servers` ( + `id` bigint NOT NULL AUTO_INCREMENT, + `name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT 'Server Name', + `country` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT 'Country', + `city` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT 'City', + `ratio` decimal(4,2) NOT NULL DEFAULT '0.00' COMMENT 'Traffic Ratio', + `address` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT 'Server Address', + `sort` bigint NOT NULL DEFAULT '0' COMMENT 'Sort', + `protocols` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci COMMENT 'Protocol', + `last_reported_at` datetime(3) DEFAULT NULL COMMENT 'Last Reported Time', + `created_at` datetime(3) DEFAULT NULL COMMENT 'Creation Time', + `updated_at` datetime(3) DEFAULT NULL COMMENT 'Update Time', + `longitude` varchar(255) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT 'longitude', + `latitude` varchar(255) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT 'latitude', + `longitude_center` varchar(255) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT 'longitude center', + `latitude_center` varchar(255) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT 'latitude center', + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; +/*!40101 SET character_set_client = @saved_cs_client */; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `subscribe` ( + `id` bigint NOT NULL AUTO_INCREMENT, + `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT 'Subscribe Name', + `language` varchar(255) COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT 'Language', + `description` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci COMMENT 'Subscribe Description', + `unit_price` bigint NOT NULL DEFAULT '0' COMMENT 'Unit Price', + `unit_time` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT 'Unit Time', + `discount` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci COMMENT 'Discount', + `replacement` bigint NOT NULL DEFAULT '0' COMMENT 'Replacement', + `inventory` bigint NOT NULL DEFAULT '0' COMMENT 'Inventory', + `traffic` bigint NOT NULL DEFAULT '0' COMMENT 'Traffic', + `speed_limit` bigint NOT NULL DEFAULT '0' COMMENT 'Speed Limit', + `device_limit` bigint NOT NULL DEFAULT '0' COMMENT 'Device Limit', + `quota` bigint NOT NULL DEFAULT '0' COMMENT 'Quota', + `show` tinyint(1) NOT NULL DEFAULT '0' COMMENT 'Show portal page', + `sell` tinyint(1) NOT NULL DEFAULT '0' COMMENT 'Sell', + `sort` bigint NOT NULL DEFAULT '0' COMMENT 'Sort', + `deduction_ratio` bigint DEFAULT '0' COMMENT 'Deduction Ratio', + `allow_deduction` tinyint(1) DEFAULT '1' COMMENT 'Allow deduction', + `reset_cycle` bigint DEFAULT '0' COMMENT 'Reset Cycle: 0: No Reset, 1: 1st, 2: Monthly, 3: Yearly', + `renewal_reset` tinyint(1) DEFAULT '0' COMMENT 'Renew Reset', + `created_at` datetime(3) DEFAULT NULL COMMENT 'Create Time', + `show_original_price` tinyint(1) NOT NULL DEFAULT '0' COMMENT 'display the original price: 0 not display, 1 display', + `updated_at` datetime(3) DEFAULT NULL COMMENT 'Update Time', + `nodes` varchar(255) COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT 'Node IDs', + `node_tags` varchar(255) COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT 'Node Tags', + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; +/*!40101 SET character_set_client = @saved_cs_client */; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `subscribe_application` ( + `id` bigint NOT NULL AUTO_INCREMENT, + `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT 'Application Name', + `icon` mediumtext CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci COMMENT 'Application Icon', + `description` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT 'Application Description', + `scheme` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT 'Application Scheme', + `user_agent` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT 'User Agent', + `is_default` tinyint(1) NOT NULL DEFAULT '0' COMMENT 'Is Default Application', + `subscribe_template` mediumtext CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci COMMENT 'Subscribe Template', + `output_format` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT 'yaml' COMMENT 'Output Format', + `download_link` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT 'Download Link', + `created_at` datetime(3) DEFAULT NULL COMMENT 'Create Time', + `updated_at` datetime(3) DEFAULT NULL COMMENT 'Update Time', + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; +/*!40101 SET character_set_client = @saved_cs_client */; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `system` ( + `id` bigint NOT NULL AUTO_INCREMENT, + `category` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT 'Category', + `key` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT 'Key Name', + `value` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT 'Key Value', + `type` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT 'Type', + `desc` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT 'Description', + `created_at` datetime(3) DEFAULT NULL COMMENT 'Creation Time', + `updated_at` datetime(3) DEFAULT NULL COMMENT 'Update Time', + PRIMARY KEY (`id`), + UNIQUE KEY `uni_system_key` (`key`), + KEY `index_key` (`key`) +) ENGINE=InnoDB AUTO_INCREMENT=53 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; +/*!40101 SET character_set_client = @saved_cs_client */; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `system_logs` ( + `id` bigint NOT NULL AUTO_INCREMENT, + `type` tinyint(1) NOT NULL DEFAULT '0' COMMENT 'Log Type: 1: Email Message 2: Mobile Message 3: Subscribe 4: Subscribe Traffic 5: Server Traffic 6: Login 7: Register 8: Balance 9: Commission 10: Reset Subscribe 11: Gift', + `date` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT 'Log Date', + `object_id` bigint NOT NULL DEFAULT '0' COMMENT 'Object ID', + `content` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT 'Log Content', + `created_at` datetime(3) DEFAULT NULL COMMENT 'Create Time', + PRIMARY KEY (`id`), + KEY `idx_type` (`type`), + KEY `idx_object_id` (`object_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; +/*!40101 SET character_set_client = @saved_cs_client */; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `task` ( + `id` bigint NOT NULL AUTO_INCREMENT COMMENT 'ID', + `type` tinyint NOT NULL COMMENT 'Task Type', + `scope` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci COMMENT 'Task Scope', + `content` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci COMMENT 'Task Content', + `status` tinyint NOT NULL DEFAULT '0' COMMENT 'Task Status: 0: Pending, 1: In Progress, 2: Completed, 3: Failed', + `errors` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci COMMENT 'Task Errors', + `total` bigint unsigned NOT NULL DEFAULT '0' COMMENT 'Total Number', + `current` bigint unsigned NOT NULL DEFAULT '0' COMMENT 'Current Number', + `created_at` datetime(3) DEFAULT NULL COMMENT 'Creation Time', + `updated_at` datetime(3) DEFAULT NULL COMMENT 'Update Time', + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; +/*!40101 SET character_set_client = @saved_cs_client */; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `ticket` ( + `id` bigint NOT NULL AUTO_INCREMENT, + `title` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT 'Title', + `description` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci COMMENT 'Description', + `user_id` bigint NOT NULL DEFAULT '0' COMMENT 'UserId', + `status` tinyint(1) NOT NULL DEFAULT '1' COMMENT 'Status', + `created_at` datetime(3) DEFAULT NULL COMMENT 'Create Time', + `updated_at` datetime(3) DEFAULT NULL COMMENT 'Update Time', + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; +/*!40101 SET character_set_client = @saved_cs_client */; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `ticket_follow` ( + `id` bigint NOT NULL AUTO_INCREMENT, + `ticket_id` bigint NOT NULL DEFAULT '0' COMMENT 'TicketId', + `from` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT 'From', + `type` tinyint(1) NOT NULL DEFAULT '1' COMMENT 'Type: 1 text, 2 image', + `content` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci COMMENT 'Content', + `created_at` datetime(3) DEFAULT NULL COMMENT 'Create Time', + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; +/*!40101 SET character_set_client = @saved_cs_client */; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `traffic_log` ( + `id` bigint NOT NULL AUTO_INCREMENT, + `server_id` bigint NOT NULL COMMENT 'Server ID', + `user_id` bigint NOT NULL COMMENT 'User ID', + `subscribe_id` bigint NOT NULL COMMENT 'Subscription ID', + `download` bigint DEFAULT '0' COMMENT 'Download Traffic', + `upload` bigint DEFAULT '0' COMMENT 'Upload Traffic', + `timestamp` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT 'Traffic Log Time', + PRIMARY KEY (`id`), + KEY `idx_subscribe_id` (`subscribe_id`), + KEY `idx_server_id` (`server_id`), + KEY `idx_user_id` (`user_id`), + KEY `idx_traffic_log_time_user_sub` (`timestamp`,`user_id`,`subscribe_id`), + KEY `idx_timestamp` (`timestamp`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; +/*!40101 SET character_set_client = @saved_cs_client */; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `user` ( + `id` bigint NOT NULL AUTO_INCREMENT, + `password` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT 'User Password', + `algo` varchar(20) COLLATE utf8mb4_general_ci NOT NULL DEFAULT 'default' COMMENT 'Encryption Algorithm', + `salt` varchar(20) COLLATE utf8mb4_general_ci NOT NULL DEFAULT 'default' COMMENT 'Password Salt', + `avatar` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci COMMENT 'User Avatar', + `balance` bigint DEFAULT '0' COMMENT 'User Balance', + `telegram` bigint DEFAULT NULL COMMENT 'Telegram Account', + `refer_code` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '' COMMENT 'Referral Code', + `referer_id` bigint DEFAULT NULL COMMENT 'Referrer ID', + `commission` bigint DEFAULT '0' COMMENT 'Commission', + `referral_percentage` tinyint unsigned NOT NULL DEFAULT '0' COMMENT 'Referral Percentage', + `only_first_purchase` tinyint(1) NOT NULL DEFAULT '1' COMMENT 'Only First Purchase', + `gift_amount` bigint DEFAULT '0' COMMENT 'User Gift Amount', + `enable` tinyint(1) NOT NULL DEFAULT '1' COMMENT 'Is Account Enabled', + `is_admin` tinyint(1) NOT NULL DEFAULT '0' COMMENT 'Is Admin', + `valid_email` tinyint(1) NOT NULL DEFAULT '0' COMMENT 'Is Email Verified', + `enable_email_notify` tinyint(1) NOT NULL DEFAULT '0' COMMENT 'Enable Email Notifications', + `enable_telegram_notify` tinyint(1) NOT NULL DEFAULT '0' COMMENT 'Enable Telegram Notifications', + `enable_balance_notify` tinyint(1) NOT NULL DEFAULT '0' COMMENT 'Enable Balance Change Notifications', + `enable_login_notify` tinyint(1) NOT NULL DEFAULT '0' COMMENT 'Enable Login Notifications', + `enable_subscribe_notify` tinyint(1) NOT NULL DEFAULT '0' COMMENT 'Enable Subscription Notifications', + `enable_trade_notify` tinyint(1) NOT NULL DEFAULT '0' COMMENT 'Enable Trade Notifications', + `created_at` datetime(3) DEFAULT NULL COMMENT 'Creation Time', + `rules` text COLLATE utf8mb4_general_ci COMMENT 'User rules for subscription', + `updated_at` datetime(3) DEFAULT NULL COMMENT 'Update Time', + `deleted_at` datetime(3) DEFAULT NULL COMMENT 'Deletion Time', + `is_del` bigint unsigned DEFAULT NULL COMMENT '1: Normal 0: Deleted', + PRIMARY KEY (`id`), + KEY `idx_referer` (`referer_id`), + KEY `idx_refer_code` (`refer_code`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; +/*!40101 SET character_set_client = @saved_cs_client */; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `user_auth_methods` ( + `id` bigint NOT NULL AUTO_INCREMENT, + `user_id` bigint NOT NULL COMMENT 'User ID', + `auth_type` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT 'Auth Type 1: apple 2: google 3: github 4: facebook 5: telegram 6: email 7: phone', + `auth_identifier` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT 'Auth Identifier', + `verified` tinyint(1) NOT NULL DEFAULT '0' COMMENT 'Is Verified', + `created_at` datetime(3) DEFAULT NULL COMMENT 'Creation Time', + `updated_at` datetime(3) DEFAULT NULL COMMENT 'Update Time', + PRIMARY KEY (`id`), + UNIQUE KEY `idx_auth_identifier` (`auth_identifier`), + KEY `idx_user_id` (`user_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; +/*!40101 SET character_set_client = @saved_cs_client */; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `user_device` ( + `id` bigint NOT NULL AUTO_INCREMENT, + `user_id` bigint NOT NULL COMMENT 'User ID', + `subscribe_id` bigint DEFAULT NULL COMMENT 'Subscribe ID', + `ip` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT 'Device Ip.', + `Identifier` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT 'Device Identifier.', + `short_code` varchar(255) COLLATE utf8mb4_general_ci DEFAULT '' COMMENT 'Short Code', + `user_agent` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT 'Device User Agent.', + `online` tinyint(1) NOT NULL DEFAULT '0' COMMENT 'Online', + `enabled` tinyint(1) NOT NULL DEFAULT '1' COMMENT 'EnableDeviceNumber', + `created_at` datetime(3) DEFAULT NULL COMMENT 'Creation Time', + `updated_at` datetime(3) DEFAULT NULL COMMENT 'Update Time', + PRIMARY KEY (`id`), + KEY `idx_user_id` (`user_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; +/*!40101 SET character_set_client = @saved_cs_client */; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `user_device_online_record` ( + `id` bigint NOT NULL AUTO_INCREMENT, + `user_id` bigint NOT NULL COMMENT 'User ID', + `identifier` varchar(255) COLLATE utf8mb4_general_ci NOT NULL COMMENT 'Device Identifier', + `online_time` datetime DEFAULT NULL COMMENT 'Online Time', + `offline_time` datetime DEFAULT NULL COMMENT 'Offline Time', + `online_seconds` bigint DEFAULT NULL COMMENT 'Offline Seconds', + `duration_days` bigint DEFAULT NULL COMMENT 'Duration Days', + `created_at` datetime DEFAULT NULL COMMENT 'Creation Time', + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; +/*!40101 SET character_set_client = @saved_cs_client */; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `user_subscribe` ( + `id` bigint NOT NULL AUTO_INCREMENT, + `user_id` bigint NOT NULL COMMENT 'User ID', + `order_id` bigint NOT NULL COMMENT 'Order ID', + `subscribe_id` bigint NOT NULL COMMENT 'Subscription ID', + `start_time` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT 'Subscription Start Time', + `expire_time` datetime(3) DEFAULT NULL COMMENT 'Subscription Expire Time', + `finished_at` datetime DEFAULT NULL COMMENT 'Subscribe Finished Time', + `traffic` bigint DEFAULT '0' COMMENT 'Traffic', + `download` bigint DEFAULT '0' COMMENT 'Download Traffic', + `upload` bigint DEFAULT '0' COMMENT 'Upload Traffic', + `token` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '' COMMENT 'Token', + `uuid` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '' COMMENT 'UUID', + `status` tinyint(1) DEFAULT '0' COMMENT 'Subscription Status: 0: Pending 1: Active 2: Finished 3: Expired 4: Deducted', + `note` varchar(500) COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT 'User note for subscription', + `created_at` datetime(3) DEFAULT NULL COMMENT 'Creation Time', + `updated_at` datetime(3) DEFAULT NULL COMMENT 'Update Time', + PRIMARY KEY (`id`), + UNIQUE KEY `uni_user_subscribe_token` (`token`), + UNIQUE KEY `uni_user_subscribe_uuid` (`uuid`), + KEY `idx_user_id` (`user_id`), + KEY `idx_order_id` (`order_id`), + KEY `idx_subscribe_id` (`subscribe_id`), + KEY `idx_token` (`token`), + KEY `idx_uuid` (`uuid`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; +/*!40101 SET character_set_client = @saved_cs_client */; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!50503 SET character_set_client = utf8mb4 */; +CREATE TABLE `withdrawals` ( + `id` bigint NOT NULL AUTO_INCREMENT COMMENT 'Primary Key', + `user_id` bigint NOT NULL COMMENT 'User ID', + `amount` bigint NOT NULL COMMENT 'Withdrawal Amount', + `content` text COMMENT 'Withdrawal Content', + `status` tinyint(1) NOT NULL DEFAULT '0' COMMENT 'Withdrawal Status', + `reason` varchar(500) NOT NULL DEFAULT '' COMMENT 'Rejection Reason', + `created_at` datetime NOT NULL COMMENT 'Creation Time', + `updated_at` datetime NOT NULL COMMENT 'Update Time', + PRIMARY KEY (`id`), + KEY `idx_user_id` (`user_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; +/*!40101 SET character_set_client = @saved_cs_client */; +/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */; + +/*!40101 SET SQL_MODE=@OLD_SQL_MODE */; +/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; +/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */; +/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; +/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; +/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; +/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; + diff --git a/sql/00002_init_basic_data.down.sql b/sql/00002_init_basic_data.down.sql new file mode 100644 index 0000000..b1f6218 --- /dev/null +++ b/sql/00002_init_basic_data.down.sql @@ -0,0 +1,30 @@ +SET FOREIGN_KEY_CHECKS = 0; + +TRUNCATE TABLE `ads`; +TRUNCATE TABLE `announcement`; +TRUNCATE TABLE `auth_method`; +TRUNCATE TABLE `coupon`; +TRUNCATE TABLE `document`; +TRUNCATE TABLE `nodes`; +TRUNCATE TABLE `order`; +TRUNCATE TABLE `payment`; +TRUNCATE TABLE `redemption_code`; +TRUNCATE TABLE `redemption_record`; +TRUNCATE TABLE `server`; +TRUNCATE TABLE `servers`; +TRUNCATE TABLE `subscribe`; +TRUNCATE TABLE `subscribe_application`; +TRUNCATE TABLE `system`; +TRUNCATE TABLE `system_logs`; +TRUNCATE TABLE `task`; +TRUNCATE TABLE `ticket`; +TRUNCATE TABLE `ticket_follow`; +TRUNCATE TABLE `traffic_log`; +TRUNCATE TABLE `user`; +TRUNCATE TABLE `user_auth_methods`; +TRUNCATE TABLE `user_device`; +TRUNCATE TABLE `user_device_online_record`; +TRUNCATE TABLE `user_subscribe`; +TRUNCATE TABLE `withdrawals`; + +SET FOREIGN_KEY_CHECKS = 1; diff --git a/sql/00002_init_basic_data.up.sql b/sql/00002_init_basic_data.up.sql new file mode 100644 index 0000000..049ded5 --- /dev/null +++ b/sql/00002_init_basic_data.up.sql @@ -0,0 +1,155 @@ + +/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; +/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; +/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; +/*!50503 SET NAMES utf8mb4 */; +/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */; +/*!40103 SET TIME_ZONE='+00:00' */; +/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; +/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; +/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; +/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; + +LOCK TABLES `ads` WRITE; +/*!40000 ALTER TABLE `ads` DISABLE KEYS */; +/*!40000 ALTER TABLE `ads` ENABLE KEYS */; +UNLOCK TABLES; + +LOCK TABLES `announcement` WRITE; +/*!40000 ALTER TABLE `announcement` DISABLE KEYS */; +/*!40000 ALTER TABLE `announcement` ENABLE KEYS */; +UNLOCK TABLES; + +LOCK TABLES `auth_method` WRITE; +/*!40000 ALTER TABLE `auth_method` DISABLE KEYS */; +INSERT INTO `auth_method` VALUES (1,'email','{\"platform\":\"smtp\",\"platform_config\":{\"host\":\"\",\"port\":0,\"user\":\"\",\"pass\":\"\",\"from\":\"\",\"ssl\":false},\"enable_verify\":false,\"enable_notify\":false,\"enable_domain_suffix\":false,\"domain_suffix_list\":\"\",\"verify_email_template\":\"\",\"expiration_email_template\":\"\",\"maintenance_email_template\":\"\",\"traffic_exceed_email_template\":\"\"}',1,'2025-04-22 14:25:16.642','2025-04-22 14:25:16.642'),(2,'mobile','{\"platform\":\"AlibabaCloud\",\"platform_config\":{\"access\":\"\",\"secret\":\"\",\"sign_name\":\"\",\"endpoint\":\"\",\"template_code\":\"\"},\"enable_whitelist\":false,\"whitelist\":[]}',0,'2025-04-22 14:25:16.642','2025-04-22 14:25:16.642'),(3,'apple','{\"team_id\":\"\",\"key_id\":\"\",\"client_id\":\"\",\"client_secret\":\"\",\"redirect_url\":\"\"}',0,'2025-04-22 14:25:16.642','2025-04-22 14:25:16.642'),(4,'google','{\"client_id\":\"\",\"client_secret\":\"\",\"redirect_url\":\"\"}',0,'2025-04-22 14:25:16.642','2025-04-22 14:25:16.642'),(5,'github','{\"client_id\":\"\",\"client_secret\":\"\",\"redirect_url\":\"\"}',0,'2025-04-22 14:25:16.642','2025-04-22 14:25:16.642'),(6,'facebook','{\"client_id\":\"\",\"client_secret\":\"\",\"redirect_url\":\"\"}',0,'2025-04-22 14:25:16.642','2025-04-22 14:25:16.642'),(7,'telegram','{\"bot_token\":\"\",\"enable_notify\":false,\"webhook_domain\":\"\"}',0,'2025-04-22 14:25:16.642','2025-04-22 14:25:16.642'),(8,'device','{\"show_ads\":false,\"only_real_device\":false,\"enable_security\":false,\"security_secret\":\"\"}',0,'2025-04-22 14:25:16.642','2025-04-22 14:25:16.642'); +/*!40000 ALTER TABLE `auth_method` ENABLE KEYS */; +UNLOCK TABLES; + +LOCK TABLES `coupon` WRITE; +/*!40000 ALTER TABLE `coupon` DISABLE KEYS */; +/*!40000 ALTER TABLE `coupon` ENABLE KEYS */; +UNLOCK TABLES; + +LOCK TABLES `document` WRITE; +/*!40000 ALTER TABLE `document` DISABLE KEYS */; +/*!40000 ALTER TABLE `document` ENABLE KEYS */; +UNLOCK TABLES; + +LOCK TABLES `nodes` WRITE; +/*!40000 ALTER TABLE `nodes` DISABLE KEYS */; +/*!40000 ALTER TABLE `nodes` ENABLE KEYS */; +UNLOCK TABLES; + +LOCK TABLES `order` WRITE; +/*!40000 ALTER TABLE `order` DISABLE KEYS */; +/*!40000 ALTER TABLE `order` ENABLE KEYS */; +UNLOCK TABLES; + +LOCK TABLES `payment` WRITE; +/*!40000 ALTER TABLE `payment` DISABLE KEYS */; +INSERT INTO `payment` VALUES (-1,'Balance','',NULL,NULL,'','','',0,0,0,1); +/*!40000 ALTER TABLE `payment` ENABLE KEYS */; +UNLOCK TABLES; + +LOCK TABLES `redemption_code` WRITE; +/*!40000 ALTER TABLE `redemption_code` DISABLE KEYS */; +/*!40000 ALTER TABLE `redemption_code` ENABLE KEYS */; +UNLOCK TABLES; + +LOCK TABLES `redemption_record` WRITE; +/*!40000 ALTER TABLE `redemption_record` DISABLE KEYS */; +/*!40000 ALTER TABLE `redemption_record` ENABLE KEYS */; +UNLOCK TABLES; + +LOCK TABLES `server` WRITE; +/*!40000 ALTER TABLE `server` DISABLE KEYS */; +/*!40000 ALTER TABLE `server` ENABLE KEYS */; +UNLOCK TABLES; + +LOCK TABLES `servers` WRITE; +/*!40000 ALTER TABLE `servers` DISABLE KEYS */; +/*!40000 ALTER TABLE `servers` ENABLE KEYS */; +UNLOCK TABLES; + +LOCK TABLES `subscribe` WRITE; +/*!40000 ALTER TABLE `subscribe` DISABLE KEYS */; +/*!40000 ALTER TABLE `subscribe` ENABLE KEYS */; +UNLOCK TABLES; + +LOCK TABLES `subscribe_application` WRITE; +/*!40000 ALTER TABLE `subscribe_application` DISABLE KEYS */; +INSERT INTO `subscribe_application` VALUES (1,'Default','','','','default',1,'{{- $GiB := 1073741824.0 -}}\n{{- $used := printf \"%.2f\" (divf (add (.UserInfo.Download | default 0 | float64) (.UserInfo.Upload | default 0 | float64)) $GiB) -}}\n{{- $traffic := (.UserInfo.Traffic | default 0 | float64) -}}\n{{- $total := printf \"%.2f\" (divf $traffic $GiB) -}}\n\n{{- $exp := \"\" -}}\n{{- $expStr := printf \"%v\" .UserInfo.ExpiredAt -}}\n{{- if regexMatch `^[0-9]+$` $expStr -}}\n {{- $ts := $expStr | float64 -}}\n {{- $sec := ternary (divf $ts 1000.0) $ts (ge (len $expStr) 13) -}}\n {{- $exp = (date \"2006-01-02 15:04:05\" (unixEpoch ($sec | int64))) -}}\n{{- else -}}\n {{- $exp = $expStr -}}\n{{- end -}}\n\nREMARKS={{ .SiteName }}-{{ .SubscribeName }}\nSTATUS=Traffic: {{ $used }} GiB/{{ $total }} GiB | Expires: {{ $exp }}\n\n{{- range $proxy := .Proxies }}\n {{- $server := $proxy.Server -}}\n {{- if and (contains $proxy.Server \":\") (not (hasPrefix \"[\" $proxy.Server)) -}}\n {{- $server = printf \"[%s]\" $proxy.Server -}}\n {{- end -}}\n\n {{- $sni := default \"\" $proxy.SNI -}}\n {{- if eq $sni \"\" -}}\n {{- $sni = default \"\" $proxy.Host -}}\n {{- end -}}\n {{- if and (eq $sni \"\") (not (or (regexMatch \"^[0-9]+\\\\.[0-9]+\\\\.[0-9]+\\\\.[0-9]+$\" $proxy.Server) (contains $proxy.Server \":\"))) -}}\n {{- $sni = $proxy.Server -}}\n {{- end -}}\n\n {{- $common := \"udp=1&tfo=1\" -}}\n\n {{- $password := $.UserInfo.Password -}}\n {{- if and (eq $proxy.Type \"shadowsocks\") (ne (default \"\" $proxy.ServerKey) \"\") -}}\n {{- $method := $proxy.Method -}}\n {{- if or (hasPrefix \"2022-blake3-\" $method) (eq $method \"2022-blake3-aes-128-gcm\") (eq $method \"2022-blake3-aes-256-gcm\") -}}\n {{- $userKeyLen := ternary 16 32 (hasSuffix \"128-gcm\" $method) -}}\n {{- $pwdStr := printf \"%s\" $password -}}\n {{- $userKey := ternary $pwdStr (trunc $userKeyLen $pwdStr) (le (len $pwdStr) $userKeyLen) -}}\n {{- $serverB64 := b64enc $proxy.ServerKey -}}\n {{- $userB64 := b64enc $userKey -}}\n {{- $password = printf \"%s:%s\" $serverB64 $userB64 -}}\n {{- end -}}\n {{- end -}}\n\n {{- if eq $proxy.Type \"shadowsocks\" }}\nss://{{ printf \"%s:%s\" $proxy.Method $password | b64enc }}@{{ $server }}:{{ $proxy.Port }}?{{ $common }}#{{ $proxy.Name }}\n {{- else if eq $proxy.Type \"vmess\" }}\nvmess://{{ (dict \"v\" \"2\" \"ps\" $proxy.Name \"add\" $proxy.Server \"port\" (printf \"%d\" $proxy.Port) \"id\" $password \"aid\" \"0\" \"net\" (default \"tcp\" $proxy.Transport) \"type\" \"none\" \"host\" (default \"\" $proxy.Host) \"path\" (default \"\" $proxy.Path) \"tls\" (ternary \"tls\" \"\" (or (eq $proxy.Security \"tls\") (eq $proxy.Security \"reality\"))) \"sni\" $sni) | toJson | b64enc }}\n {{- else if eq $proxy.Type \"vless\" }}\nvless://{{ $password }}@{{ $server }}:{{ $proxy.Port }}?encryption=none{{- if ne (default \"\" $proxy.Flow) \"\" }}&flow={{ $proxy.Flow }}{{- end }}{{- if ne $proxy.Transport \"\" }}&type={{ $proxy.Transport }}{{- end }}{{- if and (eq $proxy.Transport \"ws\") (ne (default \"\" $proxy.Host) \"\") }}&host={{ $proxy.Host }}{{- end }}{{- if and (eq $proxy.Transport \"ws\") (ne (default \"\" $proxy.Path) \"\") }}&path={{ $proxy.Path | urlquery }}{{- end }}{{- if and (eq $proxy.Transport \"grpc\") (ne (default \"\" $proxy.ServiceName) \"\") }}&serviceName={{ $proxy.ServiceName }}{{- end }}{{- if or (eq $proxy.Security \"tls\") (eq $proxy.Security \"reality\") }}&security={{ $proxy.Security }}{{- end }}{{- if ne $sni \"\" }}&sni={{ $sni }}{{- end }}{{- if $proxy.AllowInsecure }}&allowInsecure=1{{- end }}{{- if ne (default \"\" $proxy.Fingerprint) \"\" }}&fp={{ $proxy.Fingerprint }}{{- end }}{{- if and (eq $proxy.Security \"reality\") (ne (default \"\" $proxy.RealityPublicKey) \"\") }}&pbk={{ $proxy.RealityPublicKey }}{{- end }}{{- if and (eq $proxy.Security \"reality\") (ne (default \"\" $proxy.RealityShortId) \"\") }}&sid={{ $proxy.RealityShortId }}{{- end }}&{{ $common }}#{{ $proxy.Name }}\n {{- else if eq $proxy.Type \"trojan\" }}\ntrojan://{{ $password }}@{{ $server }}:{{ $proxy.Port }}{{- if or (and (or (eq $proxy.Security \"tls\") (eq $proxy.Security \"reality\")) (ne $sni \"\")) (and (or (eq $proxy.Security \"tls\") (eq $proxy.Security \"reality\")) $proxy.AllowInsecure) (ne $proxy.Transport \"\") }}?{{- end }}{{- if and (or (eq $proxy.Security \"tls\") (eq $proxy.Security \"reality\")) (ne $sni \"\") }}sni={{ $sni }}{{- end }}{{- if and (or (eq $proxy.Security \"tls\") (eq $proxy.Security \"reality\")) $proxy.AllowInsecure }}{{- if and (or (eq $proxy.Security \"tls\") (eq $proxy.Security \"reality\")) (ne $sni \"\") }}&{{- end }}allowInsecure=1{{- end }}{{- if ne $proxy.Transport \"\" }}{{- if or (and (or (eq $proxy.Security \"tls\") (eq $proxy.Security \"reality\")) (ne $sni \"\")) (and (or (eq $proxy.Security \"tls\") (eq $proxy.Security \"reality\")) $proxy.AllowInsecure) }}&{{- end }}type={{ $proxy.Transport }}{{- end }}{{- if and (eq $proxy.Transport \"ws\") (ne (default \"\" $proxy.Host) \"\") }}{{- if or (and (or (eq $proxy.Security \"tls\") (eq $proxy.Security \"reality\")) (ne $sni \"\")) (and (or (eq $proxy.Security \"tls\") (eq $proxy.Security \"reality\")) $proxy.AllowInsecure) (ne $proxy.Transport \"\") }}&{{- end }}host={{ $proxy.Host }}{{- end }}{{- if and (eq $proxy.Transport \"ws\") (ne (default \"\" $proxy.Path) \"\") }}{{- if or (and (or (eq $proxy.Security \"tls\") (eq $proxy.Security \"reality\")) (ne $sni \"\")) (and (or (eq $proxy.Security \"tls\") (eq $proxy.Security \"reality\")) $proxy.AllowInsecure) (ne $proxy.Transport \"\") (and (eq $proxy.Transport \"ws\") (ne (default \"\" $proxy.Host) \"\")) }}&{{- end }}path={{ $proxy.Path | urlquery }}{{- end }}{{- if or (and (or (eq $proxy.Security \"tls\") (eq $proxy.Security \"reality\")) (ne $sni \"\")) (and (or (eq $proxy.Security \"tls\") (eq $proxy.Security \"reality\")) $proxy.AllowInsecure) (ne $proxy.Transport \"\") }}&{{ $common }}{{- else }}?{{ $common }}{{- end }}#{{ $proxy.Name }}\n {{- else if eq $proxy.Type \"hysteria2\" }}\nhysteria2://{{ $server }}:{{ $proxy.Port }}{{- if or (ne $password \"\") (ne $sni \"\") $proxy.AllowInsecure (ne (default \"\" $proxy.ObfsPassword) \"\") (ne (default \"\" $proxy.HopPorts) \"\") }}?{{- end }}{{- if ne $password \"\" }}auth={{ $password }}{{- end }}{{- if ne $sni \"\" }}{{- if ne $password \"\" }}&{{- end }}sni={{ $sni }}{{- end }}{{- if $proxy.AllowInsecure }}{{- if or (ne $password \"\") (ne $sni \"\") }}&{{- end }}insecure=1{{- end }}{{- if ne (default \"\" $proxy.ObfsPassword) \"\" }}{{- if or (ne $password \"\") (ne $sni \"\") $proxy.AllowInsecure }}&{{- end }}obfs=salamander&obfs-password={{ $proxy.ObfsPassword }}{{- end }}{{- if ne (default \"\" $proxy.HopPorts) \"\" }}{{- if or (ne $password \"\") (ne $sni \"\") $proxy.AllowInsecure (ne (default \"\" $proxy.ObfsPassword) \"\") }}&{{- end }}mport={{ $proxy.HopPorts }}{{- end }}{{- if or (ne $password \"\") (ne $sni \"\") $proxy.AllowInsecure (ne (default \"\" $proxy.ObfsPassword) \"\") (ne (default \"\" $proxy.HopPorts) \"\") }}&{{ $common }}{{- else }}?{{ $common }}{{- end }}#{{ $proxy.Name }}\n {{- else if eq $proxy.Type \"tuic\" }}\ntuic://{{ $password }}:{{ $password }}@{{ $server }}:{{ $proxy.Port }}{{- if or (ne (default \"\" $proxy.CongestionController) \"\") (ne (default \"\" $proxy.UDPRelayMode) \"\") $proxy.ReduceRtt $proxy.DisableSNI (ne $sni \"\") $proxy.AllowInsecure }}?{{- end }}{{- if ne (default \"\" $proxy.CongestionController) \"\" }}congestion_controller={{ $proxy.CongestionController }}{{- end }}{{- if ne (default \"\" $proxy.UDPRelayMode) \"\" }}{{- if ne (default \"\" $proxy.CongestionController) \"\" }}&{{- end }}udp_relay_mode={{ $proxy.UDPRelayMode }}{{- end }}{{- if $proxy.ReduceRtt }}{{- if or (ne (default \"\" $proxy.CongestionController) \"\") (ne (default \"\" $proxy.UDPRelayMode) \"\") }}&{{- end }}reduce_rtt=1{{- end }}{{- if $proxy.DisableSNI }}{{- if or (ne (default \"\" $proxy.CongestionController) \"\") (ne (default \"\" $proxy.UDPRelayMode) \"\") $proxy.ReduceRtt }}&{{- end }}disable_sni=1{{- end }}{{- if ne $sni \"\" }}{{- if or (ne (default \"\" $proxy.CongestionController) \"\") (ne (default \"\" $proxy.UDPRelayMode) \"\") $proxy.ReduceRtt $proxy.DisableSNI }}&{{- end }}sni={{ $sni }}{{- end }}{{- if $proxy.AllowInsecure }}{{- if or (ne (default \"\" $proxy.CongestionController) \"\") (ne (default \"\" $proxy.UDPRelayMode) \"\") $proxy.ReduceRtt $proxy.DisableSNI (ne $sni \"\") }}&{{- end }}allow_insecure=1{{- end }}{{- if or (ne (default \"\" $proxy.CongestionController) \"\") (ne (default \"\" $proxy.UDPRelayMode) \"\") $proxy.ReduceRtt $proxy.DisableSNI (ne $sni \"\") $proxy.AllowInsecure }}&{{ $common }}{{- else }}?{{ $common }}{{- end }}#{{ $proxy.Name }}\n {{- else if eq $proxy.Type \"anytls\" }}\nanytls://{{ $password }}@{{ $server }}:{{ $proxy.Port }}{{- if ne $sni \"\" }}?sni={{ $sni }}&{{ $common }}{{- else }}?{{ $common }}{{- end }}#{{ $proxy.Name }}\n {{- end }}\n{{- end }}\n\n{{- range $proxy := .Proxies }}\n {{- if not (or (eq $proxy.Type \"shadowsocks\") (eq $proxy.Type \"vmess\") (eq $proxy.Type \"vless\") (eq $proxy.Type \"trojan\") (eq $proxy.Type \"hysteria2\") (eq $proxy.Type \"tuic\") (eq $proxy.Type \"anytls\")) }}\n# Skipped (unsupported protocol): {{ $proxy.Name }} ({{ $proxy.Type }})\n {{- end }}\n{{- end }}\n','base64','{}','2025-08-12 22:57:56.711','2025-08-15 21:45:20.181'),(2,'Shadowrocket','','','shadowrocket://add/sub://${window.btoa(url)}?remark=${encodeURIComponent(name)}','Shadowrocket',0,'{{- $GiB := 1073741824.0 -}}\n{{- $used := printf \"%.2f\" (divf (add (.UserInfo.Download | default 0 | float64) (.UserInfo.Upload | default 0 | float64)) $GiB) -}}\n{{- $traffic := (.UserInfo.Traffic | default 0 | float64) -}}\n{{- $total := printf \"%.2f\" (divf $traffic $GiB) -}}\n\n{{- $exp := \"\" -}}\n{{- $expStr := printf \"%v\" .UserInfo.ExpiredAt -}}\n{{- if regexMatch `^[0-9]+$` $expStr -}}\n {{- $ts := $expStr | float64 -}}\n {{- $sec := ternary (divf $ts 1000.0) $ts (ge (len $expStr) 13) -}}\n {{- $exp = (date \"2006-01-02 15:04:05\" (unixEpoch ($sec | int64))) -}}\n{{- else -}}\n {{- $exp = $expStr -}}\n{{- end -}}\n\nREMARKS={{ .SiteName }}-{{ .SubscribeName }}\nSTATUS=Traffic: {{ $used }} GiB/{{ $total }} GiB | Expires: {{ $exp }}\n\n{{- range $proxy := .Proxies }}\n {{- $server := $proxy.Server -}}\n {{- if and (contains $proxy.Server \":\") (not (hasPrefix \"[\" $proxy.Server)) -}}\n {{- $server = printf \"[%s]\" $proxy.Server -}}\n {{- end -}}\n\n {{- $sni := default \"\" $proxy.SNI -}}\n {{- if eq $sni \"\" -}}\n {{- $sni = default \"\" $proxy.Host -}}\n {{- end -}}\n {{- if and (eq $sni \"\") (not (or (regexMatch \"^[0-9]+\\\\.[0-9]+\\\\.[0-9]+\\\\.[0-9]+$\" $proxy.Server) (contains $proxy.Server \":\"))) -}}\n {{- $sni = $proxy.Server -}}\n {{- end -}}\n\n {{- $common := \"udp=1&tfo=1\" -}}\n\n {{- $password := $.UserInfo.Password -}}\n {{- if and (eq $proxy.Type \"shadowsocks\") (ne (default \"\" $proxy.ServerKey) \"\") -}}\n {{- $method := $proxy.Method -}}\n {{- if or (hasPrefix \"2022-blake3-\" $method) (eq $method \"2022-blake3-aes-128-gcm\") (eq $method \"2022-blake3-aes-256-gcm\") -}}\n {{- $userKeyLen := ternary 16 32 (hasSuffix \"128-gcm\" $method) -}}\n {{- $pwdStr := printf \"%s\" $password -}}\n {{- $userKey := ternary $pwdStr (trunc $userKeyLen $pwdStr) (le (len $pwdStr) $userKeyLen) -}}\n {{- $serverB64 := b64enc $proxy.ServerKey -}}\n {{- $userB64 := b64enc $userKey -}}\n {{- $password = printf \"%s:%s\" $serverB64 $userB64 -}}\n {{- end -}}\n {{- end -}}\n\n {{- if eq $proxy.Type \"shadowsocks\" }}\nss://{{ printf \"%s:%s\" (default \"aes-128-gcm\" $proxy.Method) $password | b64enc }}@{{ $server }}:{{ $proxy.Port }}?{{ $common }}#{{ $proxy.Name }}\n {{- else if eq $proxy.Type \"vmess\" }}\nvmess://{{ (dict \"v\" \"2\" \"ps\" $proxy.Name \"add\" $proxy.Server \"port\" (printf \"%d\" $proxy.Port) \"id\" $password \"aid\" \"0\" \"net\" (default \"tcp\" $proxy.Transport) \"type\" \"none\" \"host\" (default \"\" $proxy.Host) \"path\" (default \"\" $proxy.Path) \"tls\" (ternary \"tls\" \"\" (or (eq $proxy.Security \"tls\") (eq $proxy.Security \"reality\"))) \"sni\" $sni) | toJson | b64enc }}\n {{- else if eq $proxy.Type \"vless\" }}\nvless://{{ $password }}@{{ $server }}:{{ $proxy.Port }}?encryption=none{{- if ne (default \"\" $proxy.Flow) \"\" }}&flow={{ $proxy.Flow }}{{- end }}{{- if ne $proxy.Transport \"\" }}&type={{ $proxy.Transport }}{{- end }}{{- if and (eq $proxy.Transport \"ws\") (ne (default \"\" $proxy.Host) \"\") }}&host={{ $proxy.Host }}{{- end }}{{- if and (eq $proxy.Transport \"ws\") (ne (default \"\" $proxy.Path) \"\") }}&path={{ $proxy.Path | urlquery }}{{- end }}{{- if and (eq $proxy.Transport \"grpc\") (ne (default \"\" $proxy.ServiceName) \"\") }}&serviceName={{ $proxy.ServiceName }}{{- end }}{{- if or (eq $proxy.Security \"tls\") (eq $proxy.Security \"reality\") }}&security={{ $proxy.Security }}{{- end }}{{- if ne $sni \"\" }}&sni={{ $sni }}{{- end }}{{- if $proxy.AllowInsecure }}&allowInsecure=1{{- end }}{{- if ne (default \"\" $proxy.Fingerprint) \"\" }}&fp={{ $proxy.Fingerprint }}{{- end }}{{- if and (eq $proxy.Security \"reality\") (ne (default \"\" $proxy.RealityPublicKey) \"\") }}&pbk={{ $proxy.RealityPublicKey }}{{- end }}{{- if and (eq $proxy.Security \"reality\") (ne (default \"\" $proxy.RealityShortId) \"\") }}&sid={{ $proxy.RealityShortId }}{{- end }}&{{ $common }}#{{ $proxy.Name }}\n {{- else if eq $proxy.Type \"trojan\" }}\ntrojan://{{ $password }}@{{ $server }}:{{ $proxy.Port }}{{- if or (and (or (eq $proxy.Security \"tls\") (eq $proxy.Security \"reality\")) (ne $sni \"\")) (and (or (eq $proxy.Security \"tls\") (eq $proxy.Security \"reality\")) $proxy.AllowInsecure) (ne $proxy.Transport \"\") }}?{{- end }}{{- if and (or (eq $proxy.Security \"tls\") (eq $proxy.Security \"reality\")) (ne $sni \"\") }}sni={{ $sni }}{{- end }}{{- if and (or (eq $proxy.Security \"tls\") (eq $proxy.Security \"reality\")) $proxy.AllowInsecure }}{{- if and (or (eq $proxy.Security \"tls\") (eq $proxy.Security \"reality\")) (ne $sni \"\") }}&{{- end }}allowInsecure=1{{- end }}{{- if ne $proxy.Transport \"\" }}{{- if or (and (or (eq $proxy.Security \"tls\") (eq $proxy.Security \"reality\")) (ne $sni \"\")) (and (or (eq $proxy.Security \"tls\") (eq $proxy.Security \"reality\")) $proxy.AllowInsecure) }}&{{- end }}type={{ $proxy.Transport }}{{- end }}{{- if and (eq $proxy.Transport \"ws\") (ne (default \"\" $proxy.Host) \"\") }}{{- if or (and (or (eq $proxy.Security \"tls\") (eq $proxy.Security \"reality\")) (ne $sni \"\")) (and (or (eq $proxy.Security \"tls\") (eq $proxy.Security \"reality\")) $proxy.AllowInsecure) (ne $proxy.Transport \"\") }}&{{- end }}host={{ $proxy.Host }}{{- end }}{{- if and (eq $proxy.Transport \"ws\") (ne (default \"\" $proxy.Path) \"\") }}{{- if or (and (or (eq $proxy.Security \"tls\") (eq $proxy.Security \"reality\")) (ne $sni \"\")) (and (or (eq $proxy.Security \"tls\") (eq $proxy.Security \"reality\")) $proxy.AllowInsecure) (ne $proxy.Transport \"\") (and (eq $proxy.Transport \"ws\") (ne (default \"\" $proxy.Host) \"\")) }}&{{- end }}path={{ $proxy.Path | urlquery }}{{- end }}{{- if or (and (or (eq $proxy.Security \"tls\") (eq $proxy.Security \"reality\")) (ne $sni \"\")) (and (or (eq $proxy.Security \"tls\") (eq $proxy.Security \"reality\")) $proxy.AllowInsecure) (ne $proxy.Transport \"\") }}&{{ $common }}{{- else }}?{{ $common }}{{- end }}#{{ $proxy.Name }}\n {{- else if eq $proxy.Type \"hysteria2\" }}\nhysteria2://{{ $server }}:{{ $proxy.Port }}{{- if or (ne $password \"\") (ne $sni \"\") $proxy.AllowInsecure (ne (default \"\" $proxy.ObfsPassword) \"\") (ne (default \"\" $proxy.HopPorts) \"\") }}?{{- end }}{{- if ne $password \"\" }}auth={{ $password }}{{- end }}{{- if ne $sni \"\" }}{{- if ne $password \"\" }}&{{- end }}sni={{ $sni }}{{- end }}{{- if $proxy.AllowInsecure }}{{- if or (ne $password \"\") (ne $sni \"\") }}&{{- end }}insecure=1{{- end }}{{- if ne (default \"\" $proxy.ObfsPassword) \"\" }}{{- if or (ne $password \"\") (ne $sni \"\") $proxy.AllowInsecure }}&{{- end }}obfs=salamander&obfs-password={{ $proxy.ObfsPassword }}{{- end }}{{- if ne (default \"\" $proxy.HopPorts) \"\" }}{{- if or (ne $password \"\") (ne $sni \"\") $proxy.AllowInsecure (ne (default \"\" $proxy.ObfsPassword) \"\") }}&{{- end }}mport={{ $proxy.HopPorts }}{{- end }}{{- if or (ne $password \"\") (ne $sni \"\") $proxy.AllowInsecure (ne (default \"\" $proxy.ObfsPassword) \"\") (ne (default \"\" $proxy.HopPorts) \"\") }}&{{ $common }}{{- else }}?{{ $common }}{{- end }}#{{ $proxy.Name }}\n {{- else if eq $proxy.Type \"tuic\" }}\ntuic://{{ $password }}:{{ $password }}@{{ $server }}:{{ $proxy.Port }}{{- if or (ne (default \"\" $proxy.CongestionController) \"\") (ne (default \"\" $proxy.UDPRelayMode) \"\") $proxy.ReduceRtt $proxy.DisableSNI (ne $sni \"\") $proxy.AllowInsecure }}?{{- end }}{{- if ne (default \"\" $proxy.CongestionController) \"\" }}congestion_controller={{ $proxy.CongestionController }}{{- end }}{{- if ne (default \"\" $proxy.UDPRelayMode) \"\" }}{{- if ne (default \"\" $proxy.CongestionController) \"\" }}&{{- end }}udp_relay_mode={{ $proxy.UDPRelayMode }}{{- end }}{{- if $proxy.ReduceRtt }}{{- if or (ne (default \"\" $proxy.CongestionController) \"\") (ne (default \"\" $proxy.UDPRelayMode) \"\") }}&{{- end }}reduce_rtt=1{{- end }}{{- if $proxy.DisableSNI }}{{- if or (ne (default \"\" $proxy.CongestionController) \"\") (ne (default \"\" $proxy.UDPRelayMode) \"\") $proxy.ReduceRtt }}&{{- end }}disable_sni=1{{- end }}{{- if ne $sni \"\" }}{{- if or (ne (default \"\" $proxy.CongestionController) \"\") (ne (default \"\" $proxy.UDPRelayMode) \"\") $proxy.ReduceRtt $proxy.DisableSNI }}&{{- end }}sni={{ $sni }}{{- end }}{{- if $proxy.AllowInsecure }}{{- if or (ne (default \"\" $proxy.CongestionController) \"\") (ne (default \"\" $proxy.UDPRelayMode) \"\") $proxy.ReduceRtt $proxy.DisableSNI (ne $sni \"\") }}&{{- end }}allow_insecure=1{{- end }}{{- if or (ne (default \"\" $proxy.CongestionController) \"\") (ne (default \"\" $proxy.UDPRelayMode) \"\") $proxy.ReduceRtt $proxy.DisableSNI (ne $sni \"\") $proxy.AllowInsecure }}&{{ $common }}{{- else }}?{{ $common }}{{- end }}#{{ $proxy.Name }}\n {{- else if eq $proxy.Type \"anytls\" }}\nanytls://{{ $password }}@{{ $server }}:{{ $proxy.Port }}{{- if ne $sni \"\" }}?sni={{ $sni }}&{{ $common }}{{- else }}?{{ $common }}{{- end }}#{{ $proxy.Name }}\n {{- else }}\n# Unsupported protocol: {{ $proxy.Type }} - {{ $proxy.Name }}\n {{- end }}\n{{- end }}','base64','{}','2025-08-12 23:03:50.004','2025-08-15 22:01:39.221'),(3,'Clash','','','clash://install-config?url=${url}&name=${name}','Clash',0,'{{- $GiB := 1073741824.0 -}}\n{{- $used := printf \"%.2f\" (divf (add (.UserInfo.Download | default 0 | float64) (.UserInfo.Upload | default 0 | float64)) $GiB) -}}\n{{- $traffic := (.UserInfo.Traffic | default 0 | float64) -}}\n{{- $total := printf \"%.2f\" (divf $traffic $GiB) -}}\n\n{{- $exp := \"\" -}}\n{{- $expStr := printf \"%v\" .UserInfo.ExpiredAt -}}\n{{- if regexMatch `^[0-9]+$` $expStr -}}\n {{- $ts := $expStr | float64 -}}\n {{- $sec := ternary (divf $ts 1000.0) $ts (ge (len $expStr) 13) -}}\n {{- $exp = (date \"2006-01-02 15:04:05\" (unixEpoch ($sec | int64))) -}}\n{{- else -}}\n {{- $exp = $expStr -}}\n{{- end -}}\n\n{{- $supportedProxies := list -}}\n{{- range $proxy := .Proxies -}}\n {{- if or (eq $proxy.Type \"shadowsocks\") (eq $proxy.Type \"vmess\") (eq $proxy.Type \"vless\") (eq $proxy.Type \"trojan\") (eq $proxy.Type \"hysteria2\") (eq $proxy.Type \"tuic\") -}}\n {{- $supportedProxies = append $supportedProxies $proxy -}}\n {{- end -}}\n{{- end -}}\n\n{{- $proxyNames := \"\" -}}\n{{- range $proxy := $supportedProxies -}}\n {{- if eq $proxyNames \"\" -}}\n {{- $proxyNames = $proxy.Name -}}\n {{- else -}}\n {{- $proxyNames = printf \"%s, %s\" $proxyNames $proxy.Name -}}\n {{- end -}}\n{{- end -}}\n\n# {{ .SiteName }}-{{ .SubscribeName }}\n# Traffic: {{ $used }} GiB/{{ $total }} GiB | Expires: {{ $exp }}\n\nmode: rule\nipv6: true\nallow-lan: true\nbind-address: \'*\'\nmixed-port: 6088\nlog-level: error\nunified-delay: true\ntcp-concurrent: true\nexternal-controller: \'0.0.0.0:9090\'\ntun:\n enable: true\n stack: system\n auto-route: true\ndns:\n enable: true\n cache-algorithm: arc\n listen: \'0.0.0.0:1053\'\n ipv6: true\n enhanced-mode: fake-ip\n fake-ip-range: 198.18.0.1/16\n fake-ip-filter: [\'*.lan\', lens.l.google.com, \'*.srv.nintendo.net\', \'*.stun.playstation.net\', \'xbox.*.*.microsoft.com\', \'*.xboxlive.com\', \'*.msftncsi.com\', \'*.msftconnecttest.com\']\n default-nameserver: [119.29.29.29, 223.5.5.5]\n nameserver: [system, 119.29.29.29, 223.5.5.5]\n fallback: [8.8.8.8, 1.1.1.1]\n fallback-filter: { geoip: true, geoip-code: CN }\n\nproxies:\n{{- range $proxy := $supportedProxies }}\n {{- $server := $proxy.Server -}}\n {{- if and (contains $proxy.Server \":\") (not (hasPrefix \"[\" $proxy.Server)) -}}\n {{- $server = printf \"[%s]\" $proxy.Server -}}\n {{- end -}}\n\n {{- $sni := default \"\" $proxy.SNI -}}\n {{- if eq $sni \"\" -}}\n {{- $sni = default \"\" $proxy.Host -}}\n {{- end -}}\n {{- if and (eq $sni \"\") (not (or (regexMatch \"^[0-9]+\\\\.[0-9]+\\\\.[0-9]+\\\\.[0-9]+$\" $proxy.Server) (contains $proxy.Server \":\"))) -}}\n {{- $sni = $proxy.Server -}}\n {{- end -}}\n\n {{- $password := $.UserInfo.Password -}}\n {{- if and (eq $proxy.Type \"shadowsocks\") (ne (default \"\" $proxy.ServerKey) \"\") -}}\n {{- $method := $proxy.Method -}}\n {{- if or (hasPrefix \"2022-blake3-\" $method) (eq $method \"2022-blake3-aes-128-gcm\") (eq $method \"2022-blake3-aes-256-gcm\") -}}\n {{- $userKeyLen := ternary 16 32 (hasSuffix \"128-gcm\" $method) -}}\n {{- $pwdStr := printf \"%s\" $password -}}\n {{- $userKey := ternary $pwdStr (trunc $userKeyLen $pwdStr) (le (len $pwdStr) $userKeyLen) -}}\n {{- $serverB64 := b64enc $proxy.ServerKey -}}\n {{- $userB64 := b64enc $userKey -}}\n {{- $password = printf \"%s:%s\" $serverB64 $userB64 -}}\n {{- end -}}\n {{- end -}}\n\n {{- $common := \"udp: true, tfo: true\" -}}\n\n {{- if eq $proxy.Type \"shadowsocks\" }}\n - { name: {{ $proxy.Name | quote }}, type: ss, server: {{ $server }}, port: {{ $proxy.Port }}, cipher: {{ default \"aes-128-gcm\" $proxy.Method }}, password: {{ $password }}, {{ $common }}{{- if ne (default \"\" $proxy.Transport) \"\" }}, plugin: obfs, plugin-opts: { mode: http, host: {{ $sni }} }{{- end }} }\n {{- else if eq $proxy.Type \"vmess\" }}\n - { name: {{ $proxy.Name | quote }}, type: vmess, server: {{ $server }}, port: {{ $proxy.Port }}, uuid: {{ $password }}, alterId: 0, cipher: auto, {{ $common }}{{- if or (eq $proxy.Transport \"websocket\") (eq $proxy.Transport \"ws\") }}, network: ws, ws-opts: { path: {{ default \"/\" $proxy.Path }}{{- if ne (default \"\" $proxy.Host) \"\" }}, headers: { Host: {{ $proxy.Host }} }{{- end }} }{{- else if eq $proxy.Transport \"http\" }}, network: http, http-opts: { method: GET, path: [{{ default \"/\" $proxy.Path | quote }}]{{- if ne (default \"\" $proxy.Host) \"\" }}, headers: { Host: [{{ $proxy.Host | quote }}] }{{- end }} }{{- else if eq $proxy.Transport \"grpc\" }}, network: grpc, grpc-opts: { grpc-service-name: {{ default \"grpc\" $proxy.ServiceName }} }{{- end }}{{- if or (eq $proxy.Security \"tls\") (eq $proxy.Security \"reality\") }}, tls: true{{- end }}{{- if ne $sni \"\" }}, servername: {{ $sni }}{{- end }}{{- if $proxy.AllowInsecure }}, skip-cert-verify: true{{- end }}{{- if ne (default \"\" $proxy.Fingerprint) \"\" }}, fingerprint: {{ $proxy.Fingerprint }}{{- end }} }\n {{- else if eq $proxy.Type \"vless\" }}\n - { name: {{ $proxy.Name | quote }}, type: vless, server: {{ $server }}, port: {{ $proxy.Port }}, uuid: {{ $password }}, {{ $common }}{{- if or (eq $proxy.Transport \"ws\") (eq $proxy.Transport \"websocket\") }}, network: ws, ws-opts: { path: {{ default \"/\" $proxy.Path }}{{- if ne (default \"\" $proxy.Host) \"\" }}, headers: { Host: {{ $proxy.Host }} }{{- end }} }{{- else if eq $proxy.Transport \"http\" }}, network: http, http-opts: { method: GET, path: [{{ default \"/\" $proxy.Path | quote }}]{{- if ne (default \"\" $proxy.Host) \"\" }}, headers: { Host: [{{ $proxy.Host | quote }}] }{{- end }} }{{- else if eq $proxy.Transport \"grpc\" }}, network: grpc, grpc-opts: { grpc-service-name: {{ default \"grpc\" $proxy.ServiceName }} }{{- end }}{{- if ne $sni \"\" }}, servername: {{ $sni }}{{- end }}{{- if $proxy.AllowInsecure }}, skip-cert-verify: true{{- end }}{{- if ne (default \"\" $proxy.Fingerprint) \"\" }}, fingerprint: {{ $proxy.Fingerprint }}{{- end }}{{- if and (eq $proxy.Security \"reality\") (ne (default \"\" $proxy.RealityPublicKey) \"\") }}, reality-opts: { public-key: {{ $proxy.RealityPublicKey }}{{- if ne (default \"\" $proxy.RealityShortId) \"\" }}, short-id: {{ $proxy.RealityShortId }}{{- end }} }{{- end }}{{- if ne (default \"\" $proxy.Flow) \"\" }}, flow: {{ $proxy.Flow }}{{- end }} }\n {{- else if eq $proxy.Type \"trojan\" }}\n - { name: {{ $proxy.Name | quote }}, type: trojan, server: {{ $server }}, port: {{ $proxy.Port }}, password: {{ $password }}, {{ $common }}{{- if ne $sni \"\" }}, sni: {{ $sni }}{{- end }}{{- if $proxy.AllowInsecure }}, skip-cert-verify: true{{- end }}{{- if ne (default \"\" $proxy.Fingerprint) \"\" }}, fingerprint: {{ $proxy.Fingerprint }}{{- end }}{{- if or (eq $proxy.Transport \"ws\") (eq $proxy.Transport \"websocket\") }}, network: ws, ws-opts: { path: {{ default \"/\" $proxy.Path }}{{- if ne (default \"\" $proxy.Host) \"\" }}, headers: { Host: {{ $proxy.Host }} }{{- end }} }{{- else if eq $proxy.Transport \"http\" }}, network: http, http-opts: { method: GET, path: [{{ default \"/\" $proxy.Path | quote }}]{{- if ne (default \"\" $proxy.Host) \"\" }}, headers: { Host: [{{ $proxy.Host | quote }}] }{{- end }} }{{- else if eq $proxy.Transport \"grpc\" }}, network: grpc, grpc-opts: { grpc-service-name: {{ default \"grpc\" $proxy.ServiceName }} }{{- end }} }\n {{- else if or (eq $proxy.Type \"hysteria2\") (eq $proxy.Type \"hy2\") }}\n - { name: {{ $proxy.Name | quote }}, type: hysteria2, server: {{ $server }}, port: {{ $proxy.Port }}, password: {{ $password }}, {{ $common }}{{- if ne $sni \"\" }}, sni: {{ $sni }}{{- end }}{{- if $proxy.AllowInsecure }}, skip-cert-verify: true{{- end }}{{- if ne (default \"\" $proxy.ObfsPassword) \"\" }}, obfs: salamander, obfs-password: {{ $proxy.ObfsPassword }}{{- end }}{{- if ne (default \"\" $proxy.HopPorts) \"\" }}, ports: {{ $proxy.HopPorts }}{{- end }}{{- if ne (default 0 $proxy.HopInterval) 0 }}, hop-interval: {{ $proxy.HopInterval }}{{- end }} }\n {{- else if eq $proxy.Type \"tuic\" }}\n - { name: {{ $proxy.Name | quote }}, type: tuic, server: {{ $server }}, port: {{ $proxy.Port }}, uuid: {{ default \"\" $proxy.ServerKey }}, password: {{ $password }}, {{ $common }}{{- if ne $sni \"\" }}, sni: {{ $sni }}{{- end }}{{- if $proxy.AllowInsecure }}, skip-cert-verify: true{{- end }}{{- if $proxy.DisableSNI }}, disable-sni: true{{- end }}{{- if $proxy.ReduceRtt }}, reduce-rtt: true{{- end }}{{- if ne (default \"\" $proxy.UDPRelayMode) \"\" }}, udp-relay-mode: {{ $proxy.UDPRelayMode }}{{- end }}{{- if ne (default \"\" $proxy.CongestionController) \"\" }}, congestion-controller: {{ $proxy.CongestionController }}{{- end }} }\n {{- else if eq $proxy.Type \"wireguard\" }}\n - { name: {{ $proxy.Name | quote }}, type: wireguard, server: {{ $server }}, port: {{ $proxy.Port }}, private-key: {{ default \"\" $proxy.ServerKey }}, public-key: {{ default \"\" $proxy.RealityPublicKey }}, {{ $common }}{{- if ne (default \"\" $proxy.Path) \"\" }}, preshared-key: {{ $proxy.Path }}{{- end }}{{- if ne (default \"\" $proxy.RealityServerAddr) \"\" }}, ip: {{ $proxy.RealityServerAddr }}{{- end }}{{- if ne (default 0 $proxy.RealityServerPort) 0 }}, ipv6: {{ $proxy.RealityServerPort }}{{- end }} }\n {{- else if eq $proxy.Type \"anytls\" }}\n - { name: {{ $proxy.Name | quote }}, type: anytls, server: {{ $server }}, port: {{ $proxy.Port }}, password: {{ $password }}, {{ $common }} }\n {{- else }}\n - { name: {{ $proxy.Name | quote }}, type: {{ $proxy.Type }}, server: {{ $server }}, port: {{ $proxy.Port }}, {{ $common }} }\n {{- end }}\n{{- end }}\n\n{{- range $proxy := .Proxies }}\n {{- if not (or (eq $proxy.Type \"shadowsocks\") (eq $proxy.Type \"vmess\") (eq $proxy.Type \"vless\") (eq $proxy.Type \"trojan\") (eq $proxy.Type \"hysteria2\") (eq $proxy.Type \"tuic\")) }}\n# Skipped (unsupported by Clash): {{ $proxy.Name }} ({{ $proxy.Type }})\n {{- end }}\n{{- end }}\n\nproxy-groups:\n - { name: 🚀 Proxy, type: select, proxies: [🌏 Auto, 🎯 Direct, {{ $proxyNames }}] }\n - { name: 🍎 Apple, type: select, proxies: [🚀 Proxy, 🎯 Direct, {{ $proxyNames }}] }\n - { name: 🔍 Google, type: select, proxies: [🚀 Proxy, 🎯 Direct, {{ $proxyNames }}] }\n - { name: 🪟 Microsoft, type: select, proxies: [🚀 Proxy, 🎯 Direct, {{ $proxyNames }}] }\n - { name: 📺 GlobalMedia, type: select, proxies: [🚀 Proxy, 🎯 Direct, {{ $proxyNames }}] }\n - { name: 📟 Telegram, type: select, proxies: [🚀 Proxy, 🎯 Direct, {{ $proxyNames }}] }\n - { name: 🤖 AI, type: select, proxies: [🚀 Proxy, 🎯 Direct, {{ $proxyNames }}] }\n - { name: 🪙 Crypto, type: select, proxies: [🚀 Proxy, 🎯 Direct, {{ $proxyNames }}] }\n - { name: 🎮 Game, type: select, proxies: [🚀 Proxy, 🎯 Direct, {{ $proxyNames }}] }\n - { name: 🇨🇳 China, type: select, proxies: [🎯 Direct, 🚀 Proxy, {{ $proxyNames }}] }\n - { name: 🎯 Direct, type: select, proxies: [DIRECT], hidden: true }\n - { name: 🐠 Final, type: select, proxies: [🚀 Proxy, 🎯 Direct, {{ $proxyNames }}] }\n - { name: 🌏 Auto, type: url-test, proxies: [{{ $proxyNames }}] }\n\nrules:\n - RULE-SET, Apple, 🍎 Apple\n - RULE-SET, Google, 🔍 Google\n - RULE-SET, Microsoft, 🪟 Microsoft\n - RULE-SET, Github, 🪟 Microsoft\n - RULE-SET, HBO, 📺 GlobalMedia\n - RULE-SET, Disney, 📺 GlobalMedia\n - RULE-SET, TikTok, 📺 GlobalMedia\n - RULE-SET, Netflix, 📺 GlobalMedia\n - RULE-SET, GlobalMedia, 📺 GlobalMedia\n - RULE-SET, Telegram, 📟 Telegram\n - RULE-SET, OpenAI, 🤖 AI\n - RULE-SET, Gemini, 🤖 AI\n - RULE-SET, Copilot, 🤖 AI\n - RULE-SET, Claude, 🤖 AI\n - RULE-SET, Crypto, 🪙 Crypto\n - RULE-SET, Cryptocurrency, 🪙 Crypto\n - RULE-SET, Game, 🎮 Game\n - RULE-SET, Global, 🚀 Proxy\n - RULE-SET, ChinaMax, 🇨🇳 China\n - RULE-SET, Lan, 🎯 Direct\n - GEOIP, CN, 🇨🇳 China\n - MATCH, 🐠 Final\n\nrule-providers:\n Apple:\n type: http\n behavior: classical\n format: yaml\n url: https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/refs/heads/master/rule/Clash/Apple/Apple_Classical_No_Resolve.yaml\n interval: 86400\n Google:\n type: http\n behavior: classical\n format: yaml\n url: https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/refs/heads/master/rule/Clash/Google/Google_No_Resolve.yaml\n interval: 86400\n Microsoft:\n type: http\n behavior: classical\n format: yaml\n url: https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/refs/heads/master/rule/Clash/Microsoft/Microsoft.yaml\n interval: 86400\n Github:\n type: http\n behavior: classical\n format: yaml\n url: https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/refs/heads/master/rule/Clash/GitHub/GitHub.yaml\n interval: 86400\n HBO:\n type: http\n behavior: classical\n format: yaml\n url: https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/refs/heads/master/rule/Clash/HBO/HBO.yaml\n interval: 86400\n Disney:\n type: http\n behavior: classical\n format: yaml\n url: https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/refs/heads/master/rule/Clash/Disney/Disney.yaml\n interval: 86400\n TikTok:\n type: http\n behavior: classical\n format: yaml\n url: https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/refs/heads/master/rule/Clash/TikTok/TikTok.yaml\n interval: 86400\n Netflix:\n type: http\n behavior: classical\n format: yaml\n url: https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/refs/heads/master/rule/Clash/Netflix/Netflix.yaml\n interval: 86400\n GlobalMedia:\n type: http\n behavior: classical\n format: yaml\n url: https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/refs/heads/master/rule/Clash/GlobalMedia/GlobalMedia_Classical_No_Resolve.yaml\n interval: 86400\n Telegram:\n type: http\n behavior: classical\n format: yaml\n url: https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/refs/heads/master/rule/Clash/Telegram/Telegram_No_Resolve.yaml\n interval: 86400\n OpenAI:\n type: http\n behavior: classical\n format: yaml\n url: https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/refs/heads/master/rule/Clash/OpenAI/OpenAI.yaml\n interval: 86400\n Gemini:\n type: http\n behavior: classical\n format: yaml\n url: https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/refs/heads/master/rule/Clash/Gemini/Gemini.yaml\n interval: 86400\n Copilot:\n type: http\n behavior: classical\n format: yaml\n url: https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/refs/heads/master/rule/Clash/Copilot/Copilot.yaml\n interval: 86400\n Claude:\n type: http\n behavior: classical\n format: yaml\n url: https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/refs/heads/master/rule/Clash/Claude/Claude.yaml\n interval: 86400\n Crypto:\n type: http\n behavior: classical\n format: yaml\n url: https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/refs/heads/master/rule/Clash/Crypto/Crypto.yaml\n interval: 86400\n Cryptocurrency:\n type: http\n behavior: classical\n format: yaml\n url: https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/refs/heads/master/rule/Clash/Cryptocurrency/Cryptocurrency.yaml\n interval: 86400\n Game:\n type: http\n behavior: classical\n format: yaml\n url: https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/refs/heads/master/rule/Clash/Game/Game.yaml\n interval: 86400\n Global:\n type: http\n behavior: classical\n format: yaml\n url: https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/refs/heads/master/rule/Clash/Global/Global_Classical_No_Resolve.yaml\n interval: 86400\n ChinaMax:\n type: http\n behavior: classical\n format: yaml\n url: https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/refs/heads/master/rule/Clash/ChinaMax/ChinaMax_Classical_No_Resolve.yaml\n interval: 86400\n Lan:\n type: http\n behavior: classical\n format: yaml\n url: https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/refs/heads/master/rule/Clash/Lan/Lan.yaml\n interval: 86400\n\nurl-rewrite:\n - ^https?:\\/\\/(www.)?g\\.cn https://www.google.com 302\n - ^https?:\\/\\/(www.)?google\\.cn https://www.google.com 302\n','yaml','{}','2025-08-12 23:10:00.487','2025-08-15 22:01:27.031'),(4,'SingBox','','','sing-box://import-remote-profile?url=${encodeURIComponent(url)}#${name}','sing-box',0,'{{- $GiB := 1073741824.0 -}}\n{{- $used := printf \"%.2f\" (divf (add (.UserInfo.Download | default 0 | float64) (.UserInfo.Upload | default 0 | float64)) $GiB) -}}\n{{- $traffic := (.UserInfo.Traffic | default 0 | float64) -}}\n{{- $total := printf \"%.2f\" (divf $traffic $GiB) -}}\n\n{{- $exp := \"\" -}}\n{{- $expStr := printf \"%v\" .UserInfo.ExpiredAt -}}\n{{- if regexMatch `^[0-9]+$` $expStr -}}\n {{- $ts := $expStr | float64 -}}\n {{- $sec := ternary (divf $ts 1000.0) $ts (ge (len $expStr) 13) -}}\n {{- $exp = (date \"2006-01-02 15:04:05\" (unixEpoch ($sec | int64))) -}}\n{{- else -}}\n {{- $exp = $expStr -}}\n{{- end -}}\n\n{{- $supportedProxies := list -}}\n{{- range $proxy := .Proxies -}}\n {{- if or (eq $proxy.Type \"shadowsocks\") (eq $proxy.Type \"vmess\") (eq $proxy.Type \"vless\") (eq $proxy.Type \"trojan\") (eq $proxy.Type \"hysteria2\") (eq $proxy.Type \"hy2\") (eq $proxy.Type \"tuic\") -}}\n {{- $supportedProxies = append $supportedProxies $proxy -}}\n {{- end -}}\n{{- end -}}\n\n{{- $proxyNames := \"\" -}}\n{{- if gt (len $supportedProxies) 0 -}}\n {{- range $proxy := $supportedProxies -}}\n {{- if eq $proxyNames \"\" -}}\n {{- $proxyNames = printf \"\\\"%s\\\"\" $proxy.Name -}}\n {{- else -}}\n {{- $proxyNames = printf \"%s, \\\"%s\\\"\" $proxyNames $proxy.Name -}}\n {{- end -}}\n {{- end -}}\n {{- $proxyNames = printf \", %s\" $proxyNames -}}\n{{- end -}}\n\n\n{\n \"log\": {\"level\": \"info\", \"timestamp\": true},\n \"experimental\": {\n \"cache_file\": {\"enabled\": true, \"path\": \"cache.db\", \"cache_id\": \"my_profile\", \"store_fakeip\": false},\n \"clash_api\": {\"external_controller\": \"127.0.0.1:9090\", \"external_ui\": \"ui\", \"secret\": \"\", \"external_ui_download_url\": \"https://mirror.ghproxy.com/https://github.com/MetaCubeX/Yacd-meta/archive/gh-pages.zip\", \"external_ui_download_detour\": \"direct\", \"default_mode\": \"rule\"}\n },\n \"dns\": {\n \"servers\": [\n {\"tag\": \"dns_proxy\",\"address\": \"tls://8.8.8.8\",\"detour\": \"Proxy\"},\n {\"tag\": \"dns_direct\",\"address\": \"https://223.5.5.5/dns-query\",\"detour\": \"direct\"}\n ],\n \"rules\": [\n {\"rule_set\": \"geosite-cn\", \"server\": \"dns_direct\"},\n {\"clash_mode\": \"direct\", \"server\": \"dns_direct\"},\n {\"clash_mode\": \"global\", \"server\": \"dns_proxy\"},\n {\"rule_set\": \"geosite-geolocation-!cn\", \"server\": \"dns_proxy\"}\n ],\n \"final\": \"dns_direct\",\n \"strategy\": \"ipv4_only\"\n },\n \"inbounds\": [\n {\"tag\": \"tun-in\", \"type\": \"tun\", \"address\": [\"172.18.0.1/30\",\"fdfe:dcba:9876::1/126\"], \"auto_route\": true, \"strict_route\": true, \"stack\": \"system\",\n \"platform\": {\"http_proxy\": {\"enabled\": true, \"server\": \"127.0.0.1\", \"server_port\": 7890}}},\n {\"tag\": \"mixed-in\", \"type\": \"mixed\", \"listen\": \"127.0.0.1\", \"listen_port\": 7890}\n ],\n \"outbounds\": [\n {\"tag\": \"Proxy\", \"type\": \"selector\", \"outbounds\": [\"Auto - UrlTest\", \"direct\"{{ $proxyNames }}]},\n {\"tag\": \"Domestic\", \"type\": \"selector\", \"outbounds\": [\"direct\", \"Proxy\"{{ $proxyNames }}]},\n {\"tag\": \"Others\", \"type\": \"selector\", \"outbounds\": [\"Proxy\", \"direct\"{{ $proxyNames }}]},\n {\"tag\": \"AI Suite\", \"type\": \"selector\", \"outbounds\": [\"Proxy\", \"direct\"{{ $proxyNames }}]},\n {\"tag\": \"Netflix\", \"type\": \"selector\", \"outbounds\": [\"Proxy\", \"direct\"{{ $proxyNames }}]},\n {\"tag\": \"Disney Plus\", \"type\": \"selector\", \"outbounds\": [\"Proxy\", \"direct\"{{ $proxyNames }}]},\n {\"tag\": \"YouTube\", \"type\": \"selector\", \"outbounds\": [\"Proxy\", \"direct\"{{ $proxyNames }}]},\n {\"tag\": \"Max\", \"type\": \"selector\", \"outbounds\": [\"Proxy\", \"direct\"{{ $proxyNames }}]},\n {\"tag\": \"Spotify\", \"type\": \"selector\", \"outbounds\": [\"Proxy\", \"direct\"{{ $proxyNames }}]},\n {\"tag\": \"Apple\", \"type\": \"selector\", \"outbounds\": [\"direct\", \"Proxy\"{{ $proxyNames }}]},\n {\"tag\": \"Telegram\", \"type\": \"selector\", \"outbounds\": [\"Proxy\", \"direct\"{{ $proxyNames }}]},\n {\"tag\": \"Microsoft\", \"type\": \"selector\", \"outbounds\": [\"Proxy\", \"direct\"{{ $proxyNames }}]},\n {\"tag\": \"Tiktok\", \"type\": \"selector\", \"outbounds\": [\"Proxy\", \"direct\"{{ $proxyNames }}]},\n {\"tag\": \"AdBlock\", \"type\": \"selector\", \"outbounds\": [\"block\", \"direct\", \"Proxy\"]},\n {{- if gt (len $supportedProxies) 0 }}\n {\"tag\": \"Auto - UrlTest\", \"type\": \"urltest\", \"outbounds\": [{{ $proxyNames | trimPrefix \", \" }}], \"url\": \"http://cp.cloudflare.com/\", \"interval\": \"10m\", \"tolerance\": 50}\n {{- range $i, $proxy := $supportedProxies }},\n{{- $server := $proxy.Server -}}\n{{- if and (contains $proxy.Server \":\") (not (hasPrefix \"[\" $proxy.Server)) -}}\n {{- $server = printf \"[%s]\" $proxy.Server -}}\n{{- end -}}\n\n{{- $sni := default \"\" $proxy.SNI -}}\n{{- if eq $sni \"\" -}}\n {{- $sni = default \"\" $proxy.Host -}}\n{{- end -}}\n{{- if and (eq $sni \"\") (not (or (regexMatch \"^[0-9]+\\\\.[0-9]+\\\\.[0-9]+\\\\.[0-9]+$\" $proxy.Server) (contains $proxy.Server \":\"))) -}}\n {{- $sni = $proxy.Server -}}\n{{- end -}}\n\n{{- $password := $.UserInfo.Password -}}\n{{- if and (eq $proxy.Type \"shadowsocks\") (ne (default \"\" $proxy.ServerKey) \"\") -}}\n {{- $method := $proxy.Method -}}\n {{- if or (hasPrefix \"2022-blake3-\" $method) (eq $method \"2022-blake3-aes-128-gcm\") (eq $method \"2022-blake3-aes-256-gcm\") -}}\n {{- $userKeyLen := ternary 16 32 (hasSuffix \"128-gcm\" $method) -}}\n {{- $pwdStr := printf \"%s\" $password -}}\n {{- $userKey := ternary $pwdStr (trunc $userKeyLen $pwdStr) (le (len $pwdStr) $userKeyLen) -}}\n {{- $serverB64 := b64enc $proxy.ServerKey -}}\n {{- $userB64 := b64enc $userKey -}}\n {{- $password = printf \"%s:%s\" $serverB64 $userB64 -}}\n {{- end -}}\n{{- end -}}\n\n{{- $common := `\"tcp_fast_open\": true, \"udp_over_tcp\": false` -}}\n\n{{- if eq $proxy.Type \"shadowsocks\" -}}\n {{- $method := default \"aes-128-gcm\" $proxy.Method -}}\n { \"type\": \"shadowsocks\", \"tag\": {{ $proxy.Name | quote }}, \"server\": {{ $server | quote }}, \"server_port\": {{ $proxy.Port }}, \"method\": {{ $method | quote }}, \"password\": {{ $password | quote }}, {{ $common }} }\n{{- else if eq $proxy.Type \"trojan\" -}}\n { \"type\": \"trojan\", \"tag\": {{ $proxy.Name | quote }}, \"server\": {{ $server | quote }}, \"server_port\": {{ $proxy.Port }}, \"password\": {{ $password | quote }}{{- if or (eq $proxy.Transport \"ws\") (eq $proxy.Transport \"websocket\") }}, \"transport\": {\"type\": \"ws\", \"path\": {{ default \"/\" $proxy.Path | quote }}{{- if ne (default \"\" $proxy.Host) \"\" }}, \"headers\": {\"Host\": {{ $proxy.Host | quote }} }{{- end -}}}{{- else if eq $proxy.Transport \"grpc\" }}, \"transport\": {\"type\": \"grpc\", \"service_name\": {{ default \"grpc\" $proxy.ServiceName | quote }}}{{- end }}, {{ $common }}, \"tls\": {\"enabled\": true{{- if ne $sni \"\" }}, \"server_name\": {{ $sni | quote }}{{- end }}{{- if $proxy.AllowInsecure }}, \"insecure\": true{{- end }}{{- if ne (default \"\" $proxy.Fingerprint) \"\" }}, \"utls\": {\"enabled\": true, \"fingerprint\": {{ $proxy.Fingerprint | quote }} }{{- end }}} }\n{{- else if eq $proxy.Type \"vless\" -}}\n { \"type\": \"vless\", \"tag\": {{ $proxy.Name | quote }}, \"server\": {{ $server | quote }}, \"server_port\": {{ $proxy.Port }}, \"uuid\": {{ $password | quote }}{{- if ne (default \"\" $proxy.Flow) \"\" }}, \"flow\": {{ $proxy.Flow | quote }}{{- end }}{{- if or (eq $proxy.Transport \"ws\") (eq $proxy.Transport \"websocket\") }}, \"transport\": {\"type\": \"ws\", \"path\": {{ default \"/\" $proxy.Path | quote }}{{- if ne (default \"\" $proxy.Host) \"\" }}, \"headers\": {\"Host\": {{ $proxy.Host | quote }} }{{- end -}}}{{- else if eq $proxy.Transport \"grpc\" }}, \"transport\": {\"type\": \"grpc\", \"service_name\": {{ default \"grpc\" $proxy.ServiceName | quote }}}{{- end }}, {{ $common }}{{- if ne (default \"\" $proxy.RealityPublicKey) \"\" }}, \"reality\": { \"enabled\": true, \"public_key\": {{ $proxy.RealityPublicKey | quote }}{{- if ne (default \"\" $proxy.RealityShortId) \"\" }}, \"short_id\": {{ $proxy.RealityShortId | quote }}{{- end }}{{- if ne $sni \"\" }}, \"server_name\": {{ $sni | quote }}{{- end }} }{{- else if or (or (eq $proxy.Security \"tls\") (eq $proxy.Security \"reality\")) (ne $sni \"\") $proxy.AllowInsecure (ne (default \"\" $proxy.Fingerprint) \"\") }}, \"tls\": {\"enabled\": true{{- if ne $sni \"\" }}, \"server_name\": {{ $sni | quote }}{{- end }}{{- if $proxy.AllowInsecure }}, \"insecure\": true{{- end }}{{- if ne (default \"\" $proxy.Fingerprint) \"\" }}, \"utls\": {\"enabled\": true, \"fingerprint\": {{ $proxy.Fingerprint | quote }} }{{- end }}}{{- end }} }\n{{- else if eq $proxy.Type \"vmess\" -}}\n { \"type\": \"vmess\", \"tag\": {{ $proxy.Name | quote }}, \"server\": {{ $server | quote }}, \"server_port\": {{ $proxy.Port }}, \"uuid\": {{ $password | quote }}, \"security\": \"auto\", {{ $common }}{{- if or (eq $proxy.Transport \"ws\") (eq $proxy.Transport \"websocket\") }}, \"transport\": {\"type\": \"ws\", \"path\": {{ default \"/\" $proxy.Path | quote }}{{- if ne (default \"\" $proxy.Host) \"\" }}, \"headers\": {\"Host\": {{ $proxy.Host | quote }} }{{- end -}}}{{- else if eq $proxy.Transport \"grpc\" }}, \"transport\": {\"type\": \"grpc\", \"service_name\": {{ default \"grpc\" $proxy.ServiceName | quote }}}{{- end }}{{- if or (or (eq $proxy.Security \"tls\") (eq $proxy.Security \"reality\")) (ne $sni \"\") $proxy.AllowInsecure (ne (default \"\" $proxy.Fingerprint) \"\") }}, \"tls\": {\"enabled\": true{{- if ne $sni \"\" }}, \"server_name\": {{ $sni | quote }}{{- end }}{{- if $proxy.AllowInsecure }}, \"insecure\": true{{- end }}{{- if ne (default \"\" $proxy.Fingerprint) \"\" }}, \"utls\": {\"enabled\": true, \"fingerprint\": {{ $proxy.Fingerprint | quote }} }{{- end }}}{{- end }} }\n{{- else if or (eq $proxy.Type \"hysteria2\") (eq $proxy.Type \"hy2\") -}}\n { \"type\": \"hysteria2\", \"tag\": {{ $proxy.Name | quote }}, \"server\": {{ $server | quote }}, \"server_port\": {{ $proxy.Port }}, \"password\": {{ $password | quote }}{{- if ne (default \"\" $proxy.ObfsPassword) \"\" }}, \"obfs\": { \"type\": \"salamander\", \"password\": {{ $proxy.ObfsPassword | quote }} }{{- end }}{{- if ne (default \"\" $proxy.HopPorts) \"\" }}, \"ports\": {{ $proxy.HopPorts | quote }}{{- end }}{{- if ne (default 0 $proxy.HopInterval) 0 }}, \"hop_interval\": {{ $proxy.HopInterval }}{{- end }}, {{ $common }}, \"tls\": {\"enabled\": true{{- if ne $sni \"\" }}, \"server_name\": {{ $sni | quote }}{{- end }}{{- if $proxy.AllowInsecure }}, \"insecure\": true{{- end }}{{- if ne (default \"\" $proxy.Fingerprint) \"\" }}, \"utls\": {\"enabled\": true, \"fingerprint\": {{ $proxy.Fingerprint | quote }} }{{- end }}} }\n{{- else if eq $proxy.Type \"tuic\" -}}\n { \"type\": \"tuic\", \"tag\": {{ $proxy.Name | quote }}, \"server\": {{ $server | quote }}, \"server_port\": {{ $proxy.Port }}, \"uuid\": {{ default \"\" $proxy.ServerKey | quote }}, \"password\": {{ $password | quote }}{{- if $proxy.DisableSNI }}, \"disable_sni\": true{{- end }}{{- if $proxy.ReduceRtt }}, \"reduce_rtt\": true{{- end }}{{- if ne (default \"\" $proxy.UDPRelayMode) \"\" }}, \"udp_relay_mode\": {{ $proxy.UDPRelayMode | quote }}{{- end }}{{- if ne (default \"\" $proxy.CongestionController) \"\" }}, \"congestion_control\": {{ $proxy.CongestionController | quote }}{{- end }}, {{ $common }}, \"alpn\": [\"h3\"], \"tls\": {\"enabled\": true{{- if ne $sni \"\" }}, \"server_name\": {{ $sni | quote }}{{- end }}{{- if $proxy.AllowInsecure }}, \"insecure\": true{{- end }}{{- if ne (default \"\" $proxy.Fingerprint) \"\" }}, \"utls\": {\"enabled\": true, \"fingerprint\": {{ $proxy.Fingerprint | quote }} }{{- end }}} }\n{{- else if eq $proxy.Type \"anytls\" -}}\n { \"type\": \"anytls\", \"tag\": {{ $proxy.Name | quote }}, \"server\": {{ $server | quote }}, \"server_port\": {{ $proxy.Port }}, \"password\": {{ $password | quote }}, {{ $common }}, \"tls\": {\"enabled\": true{{- if ne $sni \"\" }}, \"server_name\": {{ $sni | quote }}{{- end }}{{- if $proxy.AllowInsecure }}, \"insecure\": true{{- end }}{{- if ne (default \"\" $proxy.Fingerprint) \"\" }}, \"utls\": {\"enabled\": true, \"fingerprint\": {{ $proxy.Fingerprint | quote }} }{{- end }}} }\n{{- else if eq $proxy.Type \"wireguard\" -}}\n { \"type\": \"wireguard\", \"tag\": {{ $proxy.Name | quote }}, \"server\": {{ $server | quote }}, \"server_port\": {{ $proxy.Port }}, \"private_key\": {{ default \"\" $proxy.ServerKey | quote }}, \"peer_public_key\": {{ default \"\" $proxy.RealityPublicKey | quote }}{{- if ne (default \"\" $proxy.Path) \"\" }}, \"pre_shared_key\": {{ $proxy.Path | quote }}{{- end }}{{- if ne (default \"\" $proxy.RealityServerAddr) \"\" }}, \"local_address\": [{{ $proxy.RealityServerAddr | quote }}]{{- end }}, {{ $common }} }\n{{- else -}}\n { \"type\": \"direct\", \"tag\": {{ $proxy.Name | quote }}, {{ $common }} }\n{{- end }}\n {{- end }},\n {{- end }}\n {\"type\": \"direct\", \"tag\": \"direct\"},\n {\"type\": \"block\", \"tag\": \"block\"}\n ],\n \"route\": {\n \"auto_detect_interface\": true, \"final\": \"Proxy\",\n \"rules\": [\n {\"type\": \"logical\", \"mode\": \"or\", \"rules\": [{\"port\": 53},{\"protocol\": \"dns\"}], \"action\": \"hijack-dns\"},\n {\"rule_set\": \"geosite-category-ads-all\", \"outbound\": \"AdBlock\"},\n {\"clash_mode\": \"direct\", \"outbound\": \"direct\"},\n {\"clash_mode\": \"global\", \"outbound\": \"Proxy\"},\n {\"domain\": [\"clash.razord.top\",\"yacd.metacubex.one\",\"yacd.haishan.me\",\"d.metacubex.one\"], \"outbound\": \"direct\"},\n {\"ip_is_private\": true, \"outbound\": \"direct\"},\n {\"rule_set\": [\"geoip-netflix\",\"geosite-netflix\"], \"outbound\": \"Netflix\"},\n {\"rule_set\": \"geosite-disney\", \"outbound\": \"Disney Plus\"},\n {\"rule_set\": \"geosite-youtube\", \"outbound\": \"YouTube\"},\n {\"rule_set\": \"geosite-max\", \"outbound\": \"Max\"},\n {\"rule_set\": \"geosite-spotify\", \"outbound\": \"Spotify\"},\n {\"rule_set\": [\"geoip-apple\",\"geosite-apple\"], \"outbound\": \"Apple\"},\n {\"rule_set\": [\"geoip-telegram\",\"geosite-telegram\"], \"outbound\": \"Telegram\"},\n {\"rule_set\": \"geosite-openai\", \"outbound\": \"AI Suite\"},\n {\"rule_set\": \"geosite-microsoft\", \"outbound\": \"Microsoft\"},\n {\"rule_set\": \"geosite-tiktok\", \"outbound\": \"Tiktok\"},\n {\"rule_set\": \"geosite-private\", \"outbound\": \"direct\"},\n {\"rule_set\": [\"geoip-cn\",\"geosite-cn\"], \"outbound\": \"Domestic\"},\n {\"rule_set\": \"geosite-geolocation-!cn\", \"outbound\": \"Others\"}\n ],\n \"rule_set\": [\n {\"tag\": \"geoip-cn\",\"type\": \"remote\",\"format\": \"binary\",\"url\": \"https://testingcf.jsdelivr.net/gh/MetaCubeX/meta-rules-dat@sing/geo/geoip/cn.srs\",\"download_detour\": \"direct\"},\n {\"tag\": \"geosite-cn\",\"type\": \"remote\",\"format\": \"binary\",\"url\": \"https://testingcf.jsdelivr.net/gh/MetaCubeX/meta-rules-dat@sing/geo/geosite/cn.srs\",\"download_detour\": \"direct\"},\n {\"tag\": \"geosite-private\",\"type\": \"remote\",\"format\": \"binary\",\"url\": \"https://testingcf.jsdelivr.net/gh/MetaCubeX/meta-rules-dat@sing/geo/geosite/private.srs\",\"download_detour\": \"direct\"},\n {\"tag\": \"geosite-geolocation-!cn\",\"type\": \"remote\",\"format\": \"binary\",\"url\": \"https://testingcf.jsdelivr.net/gh/MetaCubeX/meta-rules-dat@sing/geo/geosite/geolocation-!cn.srs\",\"download_detour\": \"direct\"},\n {\"tag\": \"geosite-category-ads-all\",\"type\": \"remote\",\"format\": \"binary\",\"url\": \"https://testingcf.jsdelivr.net/gh/MetaCubeX/meta-rules-dat@sing/geo/geosite/category-ads-all.srs\",\"download_detour\": \"direct\"},\n {\"tag\": \"geoip-netflix\",\"type\": \"remote\",\"format\": \"binary\",\"url\": \"https://testingcf.jsdelivr.net/gh/MetaCubeX/meta-rules-dat@sing/geo/geoip/netflix.srs\",\"download_detour\": \"direct\"},\n {\"tag\": \"geosite-netflix\",\"type\": \"remote\",\"format\": \"binary\",\"url\": \"https://testingcf.jsdelivr.net/gh/MetaCubeX/meta-rules-dat@sing/geo/geosite/netflix.srs\",\"download_detour\": \"direct\"},\n {\"tag\": \"geosite-disney\",\"type\": \"remote\",\"format\": \"binary\",\"url\": \"https://testingcf.jsdelivr.net/gh/MetaCubeX/meta-rules-dat@sing/geo/geosite/disney.srs\",\"download_detour\": \"direct\"},\n {\"tag\": \"geosite-youtube\",\"type\": \"remote\",\"format\": \"binary\",\"url\": \"https://testingcf.jsdelivr.net/gh/MetaCubeX/meta-rules-dat@sing/geo/geosite/youtube.srs\",\"download_detour\": \"direct\"},\n {\"tag\": \"geosite-max\",\"type\": \"remote\",\"format\": \"binary\",\"url\": \"https://testingcf.jsdelivr.net/gh/MetaCubeX/meta-rules-dat@sing/geo/geosite/hbomax.srs\",\"download_detour\": \"direct\"},\n {\"tag\": \"geosite-spotify\",\"type\": \"remote\",\"format\": \"binary\",\"url\": \"https://testingcf.jsdelivr.net/gh/MetaCubeX/meta-rules-dat@sing/geo/geosite/spotify.srs\",\"download_detour\": \"direct\"},\n {\"tag\": \"geoip-apple\",\"type\": \"remote\",\"format\": \"binary\",\"url\": \"https://testingcf.jsdelivr.net/gh/MetaCubeX/meta-rules-dat@sing/geo-lite/geoip/apple.srs\",\"download_detour\": \"direct\"},\n {\"tag\": \"geosite-apple\",\"type\": \"remote\",\"format\": \"binary\",\"url\": \"https://testingcf.jsdelivr.net/gh/MetaCubeX/meta-rules-dat@sing/geo/geosite/apple.srs\",\"download_detour\": \"direct\"},\n {\"tag\": \"geoip-telegram\",\"type\": \"remote\",\"format\": \"binary\",\"url\": \"https://testingcf.jsdelivr.net/gh/MetaCubeX/meta-rules-dat@sing/geo/geoip/telegram.srs\",\"download_detour\": \"direct\"},\n {\"tag\": \"geosite-telegram\",\"type\": \"remote\",\"format\": \"binary\",\"url\": \"https://testingcf.jsdelivr.net/gh/MetaCubeX/meta-rules-dat@sing/geo/geosite/telegram.srs\",\"download_detour\": \"direct\"},\n {\"tag\": \"geosite-openai\",\"type\": \"remote\",\"format\": \"binary\",\"url\": \"https://testingcf.jsdelivr.net/gh/MetaCubeX/meta-rules-dat@sing/geo/geosite/openai.srs\",\"download_detour\": \"direct\"},\n {\"tag\": \"geosite-microsoft\",\"type\": \"remote\",\"format\": \"binary\",\"url\": \"https://testingcf.jsdelivr.net/gh/MetaCubeX/meta-rules-dat@sing/geo/geosite/microsoft.srs\",\"download_detour\": \"direct\"},\n {\"tag\": \"geosite-tiktok\",\"type\": \"remote\",\"format\": \"binary\",\"url\": \"https://testingcf.jsdelivr.net/gh/MetaCubeX/meta-rules-dat@sing/geo/geosite/tiktok.srs\",\"download_detour\": \"direct\"}\n ]\n }\n}\n','json','{}','2025-08-12 23:30:10.016','2025-08-15 22:01:10.801'),(5,'Surge','','','surge:///install-config?url=${encodeURIComponent(url)}','Surge',0,'{{- $GiB := 1073741824.0 -}}\n{{- $used := printf \"%.2f\" (divf (add (.UserInfo.Download | default 0 | float64) (.UserInfo.Upload | default 0 | float64)) $GiB) -}}\n{{- $traffic := (.UserInfo.Traffic | default 0 | float64) -}}\n{{- $total := printf \"%.2f\" (divf $traffic $GiB) -}}\n\n{{- $exp := \"\" -}}\n{{- $expStr := printf \"%v\" .UserInfo.ExpiredAt -}}\n{{- if regexMatch `^[0-9]+$` $expStr -}}\n {{- $ts := $expStr | float64 -}}\n {{- $sec := ternary (divf $ts 1000.0) $ts (ge (len $expStr) 13) -}}\n {{- $exp = (date \"2006-01-02 15:04:05\" (unixEpoch ($sec | int64))) -}}\n{{- else -}}\n {{- $exp = $expStr -}}\n{{- end -}}\n\n{{- $supportedProxies := list -}}\n{{- range $proxy := .Proxies -}}\n {{- if or (eq $proxy.Type \"shadowsocks\") (eq $proxy.Type \"vmess\") (eq $proxy.Type \"trojan\") (eq $proxy.Type \"hysteria2\") (eq $proxy.Type \"tuic\") -}}\n {{- $supportedProxies = append $supportedProxies $proxy -}}\n {{- end -}}\n{{- end -}}\n\n{{- $proxyNames := \"\" -}}\n{{- range $proxy := $supportedProxies -}}\n {{- if eq $proxyNames \"\" -}}\n {{- $proxyNames = $proxy.Name -}}\n {{- else -}}\n {{- $proxyNames = printf \"%s, %s\" $proxyNames $proxy.Name -}}\n {{- end -}}\n{{- end -}}\n\n#!MANAGED-CONFIG {{ .UserInfo.SubscribeURL }} interval=86400\n\n[General]\nloglevel = notify\nexternal-controller-access = perlnk@0.0.0.0:6170\nexclude-simple-hostnames = true\nshow-error-page-for-reject = true\nudp-priority = true\nudp-policy-not-supported-behaviour = reject\nipv6 = true\nipv6-vif = auto\nproxy-test-url = http://www.gstatic.com/generate_204\ninternet-test-url = http://connectivitycheck.platform.hicloud.com/generate_204\ntest-timeout = 5\ndns-server = system, 119.29.29.29, 223.5.5.5\nencrypted-dns-server = https://dns.alidns.com/dns-query\nhijack-dns = 8.8.8.8:53, 8.8.4.4:53, 1.1.1.1:53, 1.0.0.1:53\nskip-proxy = 192.168.0.0/16, 10.0.0.0/8, 172.16.0.0/12, 127.0.0.0/8, localhost, *.local\nalways-real-ip = *.lan, lens.l.google.com, *.srv.nintendo.net, *.stun.playstation.net, *.xboxlive.com, xbox.*.*.microsoft.com, *.msftncsi.com, *.msftconnecttest.com\n\n# > Surge Mac Parameters\nhttp-listen = 0.0.0.0:6088\nsocks5-listen = 0.0.0.0:6089\n\n# > Surge iOS Parameters\nallow-wifi-access = true\nallow-hotspot-access = true\nwifi-access-http-port = 6088\nwifi-access-socks5-port = 6089\n\n[Panel]\nSubscribeInfo = title={{ .SiteName }} - {{ .SubscribeName }}, content=官方网站: perlnk.com \\n已用流量: {{ $used }} GiB/{{ $total }} GiB \\n到期时间: {{ $exp }}, style=info\n\n[Proxy]\n{{- range $proxy := $supportedProxies }}\n {{- $server := $proxy.Server -}}\n {{- if and (contains $proxy.Server \":\") (not (hasPrefix \"[\" $proxy.Server)) -}}\n {{- $server = printf \"[%s]\" $proxy.Server -}}\n {{- end -}}\n\n {{- $sni := default \"\" $proxy.SNI -}}\n {{- if eq $sni \"\" -}}\n {{- $sni = default \"\" $proxy.Host -}}\n {{- end -}}\n {{- if and (eq $sni \"\") (not (or (regexMatch \"^[0-9]+\\\\.[0-9]+\\\\.[0-9]+\\\\.[0-9]+$\" $proxy.Server) (contains $proxy.Server \":\"))) -}}\n {{- $sni = $proxy.Server -}}\n {{- end -}}\n\n {{- $password := $.UserInfo.Password -}}\n {{- if and (eq $proxy.Type \"shadowsocks\") (ne (default \"\" $proxy.ServerKey) \"\") -}}\n {{- $method := $proxy.Method -}}\n {{- if or (hasPrefix \"2022-blake3-\" $method) (eq $method \"2022-blake3-aes-128-gcm\") (eq $method \"2022-blake3-aes-256-gcm\") -}}\n {{- $userKeyLen := ternary 16 32 (hasSuffix \"128-gcm\" $method) -}}\n {{- $pwdStr := printf \"%s\" $password -}}\n {{- $userKey := ternary $pwdStr (trunc $userKeyLen $pwdStr) (le (len $pwdStr) $userKeyLen) -}}\n {{- $serverB64 := b64enc $proxy.ServerKey -}}\n {{- $userB64 := b64enc $userKey -}}\n {{- $password = printf \"%s:%s\" $serverB64 $userB64 -}}\n {{- end -}}\n {{- end -}}\n\n {{- $common := \"udp-relay=true, tfo=true\" -}}\n\n {{- if eq $proxy.Type \"shadowsocks\" }}\n{{ $proxy.Name }} = ss, {{ $server }}, {{ $proxy.Port }}, encrypt-method={{ default \"aes-128-gcm\" $proxy.Method }}, password={{ $password }}{{- if ne (default \"\" $proxy.Transport) \"\" }}, obfs={{ $proxy.Transport }}, obfs-host={{ $sni }}{{- end }}, {{ $common }}\n {{- else if eq $proxy.Type \"vmess\" }}\n{{ $proxy.Name }} = vmess, {{ $server }}, {{ $proxy.Port }}, username={{ $password }}{{- if or (eq $proxy.Transport \"ws\") (eq $proxy.Transport \"websocket\") }}, ws=true{{- if ne (default \"\" $proxy.Path) \"\" }}, ws-path={{ $proxy.Path }}{{- end }}{{- if ne (default \"\" $proxy.Host) \"\" }}, ws-headers=\"Host:{{ $proxy.Host }}\"{{- end }}{{- else if eq $proxy.Transport \"grpc\" }}, grpc=true{{- if ne (default \"\" $proxy.ServiceName) \"\" }}, grpc-service-name={{ $proxy.ServiceName }}{{- end }}{{- end }}{{- if or (eq $proxy.Security \"tls\") (eq $proxy.Security \"reality\") }}, tls=true{{- end }}{{- if ne $sni \"\" }}, sni={{ $sni }}{{- end }}{{- if $proxy.AllowInsecure }}, skip-cert-verify=true{{- end }}{{- if ne (default \"\" $proxy.Fingerprint) \"\" }}, fingerprint={{ $proxy.Fingerprint }}{{- end }}, {{ $common }}\n {{- else if eq $proxy.Type \"vless\" }}\n{{ $proxy.Name }} = vless, {{ $server }}, {{ $proxy.Port }}, username={{ $password }}{{- if or (eq $proxy.Transport \"ws\") (eq $proxy.Transport \"websocket\") }}, ws=true{{- if ne (default \"\" $proxy.Path) \"\" }}, ws-path={{ $proxy.Path }}{{- end }}{{- if ne (default \"\" $proxy.Host) \"\" }}, ws-headers=\"Host:{{ $proxy.Host }}\"{{- end }}{{- else if eq $proxy.Transport \"grpc\" }}, grpc=true{{- if ne (default \"\" $proxy.ServiceName) \"\" }}, grpc-service-name={{ $proxy.ServiceName }}{{- end }}{{- end }}{{- if ne $sni \"\" }}, sni={{ $sni }}{{- end }}{{- if $proxy.AllowInsecure }}, skip-cert-verify=true{{- end }}{{- if ne (default \"\" $proxy.Flow) \"\" }}, flow={{ $proxy.Flow }}{{- end }}, {{ $common }}\n {{- else if eq $proxy.Type \"trojan\" }}\n{{ $proxy.Name }} = trojan, {{ $server }}, {{ $proxy.Port }}, password={{ $password }}{{- if or (eq $proxy.Transport \"ws\") (eq $proxy.Transport \"websocket\") }}, ws=true{{- if ne (default \"\" $proxy.Path) \"\" }}, ws-path={{ $proxy.Path }}{{- end }}{{- if ne (default \"\" $proxy.Host) \"\" }}, ws-headers=\"Host:{{ $proxy.Host }}\"{{- end }}{{- else if eq $proxy.Transport \"grpc\" }}, grpc=true{{- if ne (default \"\" $proxy.ServiceName) \"\" }}, grpc-service-name={{ $proxy.ServiceName }}{{- end }}{{- end }}{{- if ne $sni \"\" }}, sni={{ $sni }}{{- end }}{{- if $proxy.AllowInsecure }}, skip-cert-verify=true{{- end }}{{- if ne (default \"\" $proxy.Fingerprint) \"\" }}, fingerprint={{ $proxy.Fingerprint }}{{- end }}, {{ $common }}\n {{- else if or (eq $proxy.Type \"hysteria2\") (eq $proxy.Type \"hy2\") }}\n{{ $proxy.Name }} = hysteria2, {{ $server }}, {{ $proxy.Port }}, password={{ $password }}{{- if ne $sni \"\" }}, sni={{ $sni }}{{- end }}{{- if $proxy.AllowInsecure }}, skip-cert-verify=true{{- end }}{{- if ne (default \"\" $proxy.ObfsPassword) \"\" }}, obfs=salamander, obfs-password={{ $proxy.ObfsPassword }}{{- end }}{{- if ne (default \"\" $proxy.HopPorts) \"\" }}, ports={{ $proxy.HopPorts }}{{- end }}{{- if ne (default 0 $proxy.HopInterval) 0 }}, hop-interval={{ $proxy.HopInterval }}{{- end }}, {{ $common }}\n {{- else if eq $proxy.Type \"tuic\" }}\n{{ $proxy.Name }} = tuic, {{ $server }}, {{ $proxy.Port }}, uuid={{ default \"\" $proxy.ServerKey }}, password={{ $password }}{{- if ne $sni \"\" }}, sni={{ $sni }}{{- end }}{{- if $proxy.AllowInsecure }}, skip-cert-verify=true{{- end }}{{- if $proxy.DisableSNI }}, disable-sni=true{{- end }}{{- if $proxy.ReduceRtt }}, reduce-rtt=true{{- end }}{{- if ne (default \"\" $proxy.UDPRelayMode) \"\" }}, udp-relay-mode={{ $proxy.UDPRelayMode }}{{- end }}{{- if ne (default \"\" $proxy.CongestionController) \"\" }}, congestion-controller={{ $proxy.CongestionController }}{{- end }}, {{ $common }}\n {{- else if eq $proxy.Type \"wireguard\" }}\n{{ $proxy.Name }} = wireguard, {{ $server }}, {{ $proxy.Port }}, private-key={{ default \"\" $proxy.ServerKey }}, public-key={{ default \"\" $proxy.RealityPublicKey }}{{- if ne (default \"\" $proxy.Path) \"\" }}, preshared-key={{ $proxy.Path }}{{- end }}{{- if ne (default \"\" $proxy.RealityServerAddr) \"\" }}, ip={{ $proxy.RealityServerAddr }}{{- end }}{{- if ne (default 0 $proxy.RealityServerPort) 0 }}, ipv6={{ $proxy.RealityServerPort }}{{- end }}, {{ $common }}\n {{- else if eq $proxy.Type \"anytls\" }}\n{{ $proxy.Name }} = anytls, {{ $server }}, {{ $proxy.Port }}, password={{ $password }}{{- if ne $sni \"\" }}, sni={{ $sni }}{{- end }}{{- if $proxy.AllowInsecure }}, skip-cert-verify=true{{- end }}, {{ $common }}\n {{- else }}\n{{ $proxy.Name }} = {{ $proxy.Type }}, {{ $server }}, {{ $proxy.Port }}, {{ $common }}\n {{- end }}\n{{- end }}\n\n[Proxy Group]\n🚀 Proxy = select, 🌏 Auto, 🎯 Direct, include-other-group=🇺🇳 Nodes\n🍎 Apple = select, 🚀 Proxy, 🎯 Direct, include-other-group=🇺🇳 Nodes\n🔍 Google = select, 🚀 Proxy, 🎯 Direct, include-other-group=🇺🇳 Nodes\n🪟 Microsoft = select, 🚀 Proxy, 🎯 Direct, include-other-group=🇺🇳 Nodes\n📺 GlobalMedia = select, 🚀 Proxy, 🎯 Direct, include-other-group=🇺🇳 Nodes\n🤖 AI = select, 🚀 Proxy, 🎯 Direct, include-other-group=🇺🇳 Nodes\n🪙 Crypto = select, 🚀 Proxy, 🎯 Direct, include-other-group=🇺🇳 Nodes\n🎮 Game = select, 🚀 Proxy, 🎯 Direct, include-other-group=🇺🇳 Nodes\n📟 Telegram = select, 🚀 Proxy, 🎯 Direct, include-other-group=🇺🇳 Nodes\n🇨🇳 China = select, 🎯 Direct, 🚀 Proxy, include-other-group=🇺🇳 Nodes\n🐠 Final = select, 🚀 Proxy, 🎯 Direct, include-other-group=🇺🇳 Nodes\n🌏 Auto = smart, include-other-group=🇺🇳 Nodes\n🎯 Direct = select, DIRECT, hidden=1\n🇺🇳 Nodes = select, {{ $proxyNames }}, hidden=1\n\n[Rule]\nRULE-SET, https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/refs/heads/master/rule/Surge/Apple/Apple_All.list, 🍎 Apple\nRULE-SET, https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/refs/heads/master/rule/Surge/Google/Google.list, 🔍 Google\nRULE-SET, https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/refs/heads/master/rule/Surge/GitHub/GitHub.list, 🪟 Microsoft\nRULE-SET, https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/refs/heads/master/rule/Surge/Microsoft/Microsoft.list, 🪟 Microsoft\nRULE-SET, https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/refs/heads/master/rule/Surge/HBO/HBO.list, 📺 GlobalMedia\nRULE-SET, https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/refs/heads/master/rule/Surge/Disney/Disney.list, 📺 GlobalMedia\nRULE-SET, https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/refs/heads/master/rule/Surge/TikTok/TikTok.list, 📺 GlobalMedia\nRULE-SET, https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/refs/heads/master/rule/Surge/Netflix/Netflix.list, 📺 GlobalMedia\nRULE-SET, https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/refs/heads/master/rule/Surge/GlobalMedia/GlobalMedia_All_No_Resolve.list, 📺 GlobalMedia\nRULE-SET, https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/refs/heads/master/rule/Surge/Telegram/Telegram.list, 📟 Telegram\nRULE-SET, https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/refs/heads/master/rule/Surge/OpenAI/OpenAI.list, 🤖 AI\nRULE-SET, https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/refs/heads/master/rule/Surge/Gemini/Gemini.list, 🤖 AI\nRULE-SET, https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/refs/heads/master/rule/Surge/Copilot/Copilot.list, 🤖 AI\nRULE-SET, https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/refs/heads/master/rule/Surge/Claude/Claude.list, 🤖 AI\nRULE-SET, https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/refs/heads/master/rule/Surge/Crypto/Crypto.list, 🪙 Crypto\nRULE-SET, https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/refs/heads/master/rule/Surge/Cryptocurrency/Cryptocurrency.list, 🪙 Crypto\nRULE-SET, https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/refs/heads/master/rule/Surge/Game/Game.list, 🎮 Game\nRULE-SET, https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/refs/heads/master/rule/Surge/Global/Global_All_No_Resolve.list, 🚀 Proxy\nRULE-SET, https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/refs/heads/master/rule/Surge/ChinaMax/ChinaMax_All_No_Resolve.list, 🇨🇳 China\nRULE-SET, https://raw.githubusercontent.com/blackmatrix7/ios_rule_script/refs/heads/master/rule/Surge/Lan/Lan.list, 🎯 Direct\n\nGEOIP, CN, 🇨🇳 China\nFINAL, 🐠 Final, dns-failed\n\n[URL Rewrite]\n^https?:\\/\\/(www.)?g\\.cn https://www.google.com 302\n^https?:\\/\\/(www.)?google\\.cn https://www.google.com 302\n\n{{- range $proxy := $supportedProxies }}\n {{- if not (or (eq $proxy.Type \"shadowsocks\") (eq $proxy.Type \"vmess\") (eq $proxy.Type \"trojan\") (eq $proxy.Type \"hysteria2\") (eq $proxy.Type \"tuic\")) }}\n# Skipped (unsupported by Surge): {{ $proxy.Name }} ({{ $proxy.Type }})\n {{- end }}\n{{- end }}','conf','{}','2025-08-13 00:12:37.809','2025-08-15 22:00:50.528'); +/*!40000 ALTER TABLE `subscribe_application` ENABLE KEYS */; +UNLOCK TABLES; + +LOCK TABLES `system` WRITE; +/*!40000 ALTER TABLE `system` DISABLE KEYS */; +INSERT INTO `system` VALUES (1,'site','SiteLogo','/favicon.svg','string','Site Logo','2025-04-22 14:25:16.637','2025-04-22 14:25:16.637'),(2,'site','SiteName','Perfect Panel','string','Site Name','2025-04-22 14:25:16.637','2025-04-22 14:25:16.637'),(3,'site','SiteDesc','PPanel is a pure, professional, and perfect open-source proxy panel tool, designed to be your ideal choice for learning and practical use.','string','Site Description','2025-04-22 14:25:16.637','2025-04-22 14:25:16.637'),(4,'site','Host','','string','Site Host','2025-04-22 14:25:16.637','2025-04-22 14:25:16.637'),(5,'site','Keywords','Perfect Panel,PPanel','string','Site Keywords','2025-04-22 14:25:16.637','2025-04-22 14:25:16.637'),(6,'site','CustomHTML','','string','Custom HTML','2025-04-22 14:25:16.637','2025-04-22 14:25:16.637'),(7,'tos','TosContent','Welcome to use Perfect Panel','string','Terms of Service','2025-04-22 14:25:16.637','2025-04-22 14:25:16.637'),(8,'tos','PrivacyPolicy','','string','PrivacyPolicy','2025-04-22 14:25:16.637','2025-04-22 14:25:16.637'),(9,'ad','WebAD','false','bool','Display ad on the web','2025-04-22 14:25:16.637','2025-04-22 14:25:16.637'),(10,'subscribe','SingleModel','false','bool','是否单订阅模式','2025-04-22 14:25:16.639','2025-04-22 14:25:16.639'),(11,'subscribe','SubscribePath','/api/subscribe','string','订阅路径','2025-04-22 14:25:16.639','2025-04-22 14:25:16.639'),(12,'subscribe','SubscribeDomain','','string','订阅域名','2025-04-22 14:25:16.639','2025-04-22 14:25:16.639'),(13,'subscribe','PanDomain','false','bool','是否使用泛域名','2025-04-22 14:25:16.639','2025-04-22 14:25:16.639'),(14,'verify','TurnstileSiteKey','','string','TurnstileSiteKey','2025-04-22 14:25:16.639','2025-04-22 14:25:16.639'),(15,'verify','TurnstileSecret','','string','TurnstileSecret','2025-04-22 14:25:16.639','2025-04-22 14:25:16.639'),(16,'verify','EnableLoginVerify','false','bool','is enable login verify','2025-04-22 14:25:16.639','2025-04-22 14:25:16.639'),(17,'verify','EnableRegisterVerify','false','bool','is enable register verify','2025-04-22 14:25:16.639','2025-04-22 14:25:16.639'),(18,'verify','EnableResetPasswordVerify','false','bool','is enable reset password verify','2025-04-22 14:25:16.639','2025-04-22 14:25:16.639'),(19,'server','NodeSecret','12345678','string','node secret','2025-04-22 14:25:16.640','2025-04-22 14:25:16.640'),(20,'server','NodePullInterval','10','int','node pull interval','2025-04-22 14:25:16.640','2025-04-22 14:25:16.640'),(21,'server','NodePushInterval','60','int','node push interval','2025-04-22 14:25:16.640','2025-04-22 14:25:16.640'),(22,'server','NodeMultiplierConfig','[]','string','node multiplier config','2025-04-22 14:25:16.640','2025-04-22 14:25:16.640'),(23,'invite','ForcedInvite','false','bool','Forced invite','2025-04-22 14:25:16.640','2025-04-22 14:25:16.640'),(24,'invite','ReferralPercentage','20','int','Referral percentage','2025-04-22 14:25:16.640','2025-04-22 14:25:16.640'),(25,'invite','OnlyFirstPurchase','false','bool','Only first purchase','2025-04-22 14:25:16.640','2025-04-22 14:25:16.640'),(26,'register','StopRegister','false','bool','is stop register','2025-04-22 14:25:16.640','2025-04-22 14:25:16.640'),(27,'register','EnableTrial','false','bool','is enable trial','2025-04-22 14:25:16.640','2025-04-22 14:25:16.640'),(28,'register','TrialSubscribe','','int','Trial subscription','2025-04-22 14:25:16.640','2025-04-22 14:25:16.640'),(29,'register','TrialTime','24','int','Trial time','2025-04-22 14:25:16.640','2025-04-22 14:25:16.640'),(30,'register','TrialTimeUnit','Hour','string','Trial time unit','2025-04-22 14:25:16.640','2025-04-22 14:25:16.640'),(31,'register','EnableIpRegisterLimit','false','bool','is enable IP register limit','2025-04-22 14:25:16.640','2025-04-22 14:25:16.640'),(32,'register','IpRegisterLimit','3','int','IP Register Limit','2025-04-22 14:25:16.640','2025-04-22 14:25:16.640'),(33,'register','IpRegisterLimitDuration','64','int','IP Register Limit Duration (minutes)','2025-04-22 14:25:16.640','2025-04-22 14:25:16.640'),(34,'currency','Currency','USD','string','Currency','2025-04-22 14:25:16.641','2025-04-22 14:25:16.641'),(35,'currency','CurrencySymbol','$','string','Currency Symbol','2025-04-22 14:25:16.641','2025-04-22 14:25:16.641'),(36,'currency','CurrencyUnit','USD','string','Currency Unit','2025-04-22 14:25:16.641','2025-04-22 14:25:16.641'),(37,'currency','AccessKey','','string','Exchangerate Access Key','2025-04-22 14:25:16.641','2025-04-22 14:25:16.641'),(38,'verify_code','VerifyCodeExpireTime','300','int','Verify code expire time','2025-04-22 14:25:16.641','2025-04-22 14:25:16.641'),(39,'verify_code','VerifyCodeLimit','15','int','limits of verify code','2025-04-22 14:25:16.641','2025-04-22 14:25:16.641'),(40,'verify_code','VerifyCodeInterval','60','int','Interval of verify code','2025-04-22 14:25:16.641','2025-04-22 14:25:16.641'),(41,'system','Version','0.2.0(02002)','string','System Version','2025-04-22 14:25:16.642','2025-04-22 14:25:16.642'),(42,'subscribe','UserAgentLimit','false','bool','User Agent Limit','2025-04-22 14:25:16.637','2025-04-22 14:25:16.637'),(43,'subscribe','UserAgentList','','string','User Agent List','2025-04-22 14:25:16.637','2025-04-22 14:25:16.637'),(44,'log','AutoClear','true','bool','Auto Clear Log','2025-04-22 14:25:16.637','2025-04-22 14:25:16.637'),(45,'log','ClearDays','7','int','Clear Days','2025-04-22 14:25:16.637','2025-04-22 14:25:16.637'),(46,'server','TrafficReportThreshold','0','int','Traffic report threshold','2025-04-22 14:25:16.637','2025-04-22 14:25:16.637'),(47,'server','IPStrategy','','string','IP Strategy','2025-04-22 14:25:16.637','2025-04-22 14:25:16.637'),(48,'server','DNS','','string','DNS','2025-04-22 14:25:16.637','2025-04-22 14:25:16.637'),(49,'server','Block','','string','Block','2025-04-22 14:25:16.637','2025-04-22 14:25:16.637'),(50,'server','Outbound','','string','Proxy Outbound','2025-04-22 14:25:16.637','2025-04-22 14:25:16.637'),(51,'site','CustomData','{\n \"kr_website_id\": \"\"\n}','string','Custom Data','2025-04-22 14:25:16.637','2025-10-14 15:47:19.187'),(52,'invite','WithdrawalMethod','','string','withdrawal method','2025-04-22 14:25:16.637','2025-04-22 14:25:16.637'); +/*!40000 ALTER TABLE `system` ENABLE KEYS */; +UNLOCK TABLES; + +LOCK TABLES `system_logs` WRITE; +/*!40000 ALTER TABLE `system_logs` DISABLE KEYS */; +/*!40000 ALTER TABLE `system_logs` ENABLE KEYS */; +UNLOCK TABLES; + +LOCK TABLES `task` WRITE; +/*!40000 ALTER TABLE `task` DISABLE KEYS */; +/*!40000 ALTER TABLE `task` ENABLE KEYS */; +UNLOCK TABLES; + +LOCK TABLES `ticket` WRITE; +/*!40000 ALTER TABLE `ticket` DISABLE KEYS */; +/*!40000 ALTER TABLE `ticket` ENABLE KEYS */; +UNLOCK TABLES; + +LOCK TABLES `ticket_follow` WRITE; +/*!40000 ALTER TABLE `ticket_follow` DISABLE KEYS */; +/*!40000 ALTER TABLE `ticket_follow` ENABLE KEYS */; +UNLOCK TABLES; + +LOCK TABLES `traffic_log` WRITE; +/*!40000 ALTER TABLE `traffic_log` DISABLE KEYS */; +/*!40000 ALTER TABLE `traffic_log` ENABLE KEYS */; +UNLOCK TABLES; + +LOCK TABLES `user` WRITE; +/*!40000 ALTER TABLE `user` DISABLE KEYS */; +/*!40000 ALTER TABLE `user` ENABLE KEYS */; +UNLOCK TABLES; + +LOCK TABLES `user_auth_methods` WRITE; +/*!40000 ALTER TABLE `user_auth_methods` DISABLE KEYS */; +/*!40000 ALTER TABLE `user_auth_methods` ENABLE KEYS */; +UNLOCK TABLES; + +LOCK TABLES `user_device` WRITE; +/*!40000 ALTER TABLE `user_device` DISABLE KEYS */; +/*!40000 ALTER TABLE `user_device` ENABLE KEYS */; +UNLOCK TABLES; + +LOCK TABLES `user_device_online_record` WRITE; +/*!40000 ALTER TABLE `user_device_online_record` DISABLE KEYS */; +/*!40000 ALTER TABLE `user_device_online_record` ENABLE KEYS */; +UNLOCK TABLES; + +LOCK TABLES `user_subscribe` WRITE; +/*!40000 ALTER TABLE `user_subscribe` DISABLE KEYS */; +/*!40000 ALTER TABLE `user_subscribe` ENABLE KEYS */; +UNLOCK TABLES; + +LOCK TABLES `withdrawals` WRITE; +/*!40000 ALTER TABLE `withdrawals` DISABLE KEYS */; +/*!40000 ALTER TABLE `withdrawals` ENABLE KEYS */; +UNLOCK TABLES; +/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */; + +/*!40101 SET SQL_MODE=@OLD_SQL_MODE */; +/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; +/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */; +/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; +/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; +/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; +/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; + diff --git a/sql/001_init.down.sql b/sql/001_init.down.sql deleted file mode 100644 index ccf0da7..0000000 --- a/sql/001_init.down.sql +++ /dev/null @@ -1,7 +0,0 @@ --- PPanel Database Schema Rollback --- Migration: 001_init --- Description: Drop all tables from initial schema - -DROP TABLE IF EXISTS `user`; - --- TODO: Add remaining DROP TABLE statements (in reverse order of creation) diff --git a/sql/001_init.up.sql b/sql/001_init.up.sql deleted file mode 100644 index 4e95c1f..0000000 --- a/sql/001_init.up.sql +++ /dev/null @@ -1,40 +0,0 @@ --- PPanel Database Schema --- Migration: 001_init --- Description: Initial database schema - --- ============================================================ --- User Domain --- ============================================================ - -CREATE TABLE IF NOT EXISTS `user` ( - `id` bigint unsigned NOT NULL AUTO_INCREMENT, - `email` varchar(255) DEFAULT NULL, - `telephone` varchar(32) DEFAULT NULL, - `password` varchar(255) NOT NULL DEFAULT '', - `refer_code` varchar(32) DEFAULT NULL, - `refer_id` bigint unsigned DEFAULT 0, - `avatar` varchar(512) DEFAULT '', - `balance` bigint DEFAULT 0, - `commission` bigint DEFAULT 0, - `gift_amount` bigint DEFAULT 0, - `is_admin` tinyint(1) NOT NULL DEFAULT 0, - `is_staff` tinyint(1) NOT NULL DEFAULT 0, - `enable` tinyint(1) NOT NULL DEFAULT 1, - `created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, - `updated_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, - PRIMARY KEY (`id`), - UNIQUE KEY `idx_email` (`email`), - UNIQUE KEY `idx_telephone` (`telephone`), - UNIQUE KEY `idx_refer_code` (`refer_code`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; - --- TODO: Add remaining tables --- user_auth_methods, user_device, user_subscribe, user_balance_log, --- user_commission_log, user_subscribe_log, user_login_log, --- user_device_online_record, user_gift_amount_log, user_reset_subscribe_log --- order, coupon, ticket, ticket_follow --- payment, announcement, document --- system, server, server_group, server_rule_group --- subscribe, subscribe_group, subscribe_type, subscribe_application --- ads, application, application_config, application_version --- traffic_log, system_logs