Skip to content

Срок действия подписки + фоновый планировщик автоотключения по истечении #104

Description

@Postlog

Категория: feature · Приоритет: high · Размер: L · Ранг: 2/10

Что построить

Поле «Срок действия» в форме пользователя: режимы «Без срока» / «До даты» (date-picker) / «N дней от первого подключения» (число + чекбокс «активировать при первом подключении»); бейдж «истекает через N дней» в строке (жёлтый/красный у порога) и бейдж «истёк». Фоновый воркер раз в интервал отключает истёкших.

Паритет с конкурентами

Marzban (unix expire), Marzneshin (expire_strategy: fixed_date / start_on_first_use / never), 3x-ui (expiryTime, режим активации при первом подключении), Remnawave (статус expired), Hiddify (package days).

Чего не хватает сейчас (код)

fleet/build.go уже читает cs.Expiry, а sub/handler.go:139 отдаёт expire в Subscription-Userinfo, но это read-only зеркало панели — subgen не задаёт expiryTime (add_client.go шлёт expiryTime:0), не показывает дату/остаток дней и не отключает истёкших. Планировщика/cron в кодовой базе нет.

Зачем

Операторы продают планы с ограничением по времени (30/90/365 дней); «активация при первом подключении» критична для предоплаченных ваучеров — часы не идут, пока код не активирован. Subgen сегодня не умеет ограничивать доступ по времени вообще.

Предлагаемая реализация

ClientSpec.ExpiryTime + убрать хардкод; колонка expiry_ms в users (отрицательная для режима «от первого использования», как у 3x-ui) + поля в Create/EditParams. Новый internal/service/reconciler (горутина-тикер в cmd/service/main.go): читает флит, сравнивает Expiry с now, переводит истёкших в disabled (через флаг #89, re-bind без удаления uuid/subId). Режим first-use — флип отрицательной длительности в дату при первом успешном /sub (хендлер уже резолвит юзера по токену). Остаток дней — в users_get, бейдж во Vue.

Затронутые файлы

  • internal/entity/panel.go (ClientSpec.ExpiryTime), internal/entity/user.go
  • internal/clients/xui/add_client.go, update_client.go (новый) + тест
  • internal/service/provisioning/service.go, internal/service/reconciler/ (новый), cmd/service/main.go
  • migrations/NNNN-user-expiry.sql, openapi/{user_create,user_edit}.yaml
  • internal/handlers/users_get/, internal/handlers/sub/handler.go (first-use), internal/handlers/web/static/

Продуктовый ресёрч: изучены аналоги (Marzban/Marzneshin, 3x-ui, Remnawave, Hiddify, sub-store + клиентские стандарты импорта). Паритет и subgen-gap код-обоснованы. Ранг = продуктовый приоритет.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions