Licensing Server -- Архитектурен преглед
Dictaro Licensing Server е Go/Gin HTTP сървър, който обслужва автентикация, billing, лицензиране, usage tracking и quota management за Dictaro desktop клиента. Деплойнат е на Azure VM (dictaro-vm) чрез Docker.
Слоеста архитектура
Сървърът следва класическа трислойна архитектура: Handlers (HTTP слой) -> Services (бизнес логика) -> Database (PostgreSQL).
Middleware верига
Всяка заявка минава през следната верига middleware-и (в ред на изпълнение):
| Middleware | Описание |
|---|---|
gin.Logger() | Логване на заявки |
gin.Recovery() | Panic recovery |
PrometheusMiddleware | HTTP метрики (request count, duration, response size) |
SecurityHeadersMiddleware | X-Content-Type-Options, X-Frame-Options, Referrer-Policy, HSTS |
CORSMiddleware | CORS headers за конфигурирани origins |
LoginRateLimit | 5 req/min per IP за login endpoints |
SensitiveEndpointRateLimit | 3 req/min per IP за password reset, verification |
RefreshRateLimit | 30 req/min per IP за token refresh |
RequireAuth | Задължителен JWT -- зарежда user от DB |
OptionalAuth | Опционален JWT -- user или nil |
Маршрути (Routes)
Health
| Метод | Път | Auth | Описание |
|---|---|---|---|
| GET | /health | -- | Health check |
OAuth автентикация
| Метод | Път | Auth | Описание |
|---|---|---|---|
| GET | /auth/login-page | -- | HTML login страница |
| GET | /auth/login/:provider | -- | Redirect към OAuth provider |
| GET | /auth/callback/:provider | -- | OAuth callback |
| POST | /auth/refresh | -- | Refresh JWT token |
Email автентикация
| Метод | Път | Auth | Описание |
|---|---|---|---|
| POST | /auth/register | -- | Регистрация с email/password |
| POST | /auth/login/email | -- | Login с email/password |
| GET | /auth/verify-email | -- | Страница за потвърждение на email |
| POST | /auth/confirm-email | -- | Потвърждение на email token |
| POST | /auth/resend-verification | -- | Повторно изпращане на verification email |
| POST | /auth/forgot-password | -- | Заявка за password reset |
| GET | /auth/reset-password-page | -- | HTML страница за нова парола |
| POST | /auth/reset-password | -- | Задаване на нова парола |
Лицензиране и акаунт
| Метод | Път | Auth | Описание |
|---|---|---|---|
| POST | /license/activate | RequireAuth | Активиране на license key |
| GET | /account/status | RequireAuth | Статус на акаунта |
Usage и Quota
| Метод | Път | Auth | Описание |
|---|---|---|---|
| POST | /usage/record | OptionalAuth | Записване на usage |
| GET | /usage/quota-status | OptionalAuth | Текущ quota статус |
| GET | /stats/public | -- | Публична статистика |
Pricing
| Метод | Път | Auth | Описание |
|---|---|---|---|
| GET | /pricing/plans | -- | Списък с планове от Stripe |
Billing
| Метод | Път | Auth | Описание |
|---|---|---|---|
| GET | /billing/choose-plan | -- (JWT в query) | HTML страница за избор на план |
| POST | /billing/create-checkout | RequireAuth | Създаване на Stripe Checkout Session |
| POST | /billing/webhook | -- (Stripe signature) | Stripe webhook receiver |
| GET | /billing/checkout-success | -- | Успешно плащане |
| GET | /billing/checkout-cancel | -- | Отказано плащане |
| POST | /account/portal-url | RequireAuth | Stripe Customer Portal URL |
Ключови дизайнерски решения
-
Stripe е source of truth за план: При всеки login се прави
SyncStripeSubscription, за да се синхронизира локалният план с реалния Stripe subscription статус. -
Device account limiting: Free потребители имат ограничение за брой акаунти на устройство (по подразбиране 2), за да се предотврати злоупотреба. Pro потребители нямат ограничение.
-
Два HTTP сървъра: Основният сървър слуша на port 8000 (конфигурируем), а вътрешен metrics сървър -- на port 9090 (само за Prometheus scraping).
-
Graceful shutdown: Сървърът обработва
SIGINT/SIGTERMи изчаква до 10 секунди за приключване на текущи заявки. -
Автоматични миграции: При стартиране се изпълняват SQL миграции автоматично чрез
golang-migrate. -
Build time injection:
buildTimeсе инжектира при компилация чрез-ldflagsи се показва в login page footer.
Файлова структура
licensing-go/
├── cmd/server/main.go # Entry point, routes, middleware
├── internal/
│ ├── config/config.go # Environment variables
│ ├── database/
│ │ ├── connect.go # PostgreSQL connection pool
│ │ └── migrations/ # SQL миграции (golang-migrate)
│ ├── handlers/
│ │ ├── auth.go # OAuth handlers
│ │ ├── email_auth.go # Email/password handlers
│ │ ├── billing.go # Stripe handlers
│ │ ├── license.go # License activation, account status
│ │ ├── usage.go # Usage recording, quota
│ │ └── pricing.go # Pricing plans
│ ├── middleware/
│ │ ├── auth.go # RequireAuth, OptionalAuth
│ │ ├── cors.go # CORS
│ │ ├── metrics.go # Prometheus metrics
│ │ ├── ratelimit.go # Per-IP rate limiting
│ │ └── security_headers.go # Security headers
│ ├── models/ # Data models (User, LicenseKey, UsageRecord)
│ ├── services/
│ │ ├── auth.go # JWT, OAuth user management
│ │ ├── email_auth.go # Email registration, verification, password reset
│ │ ├── email.go # Resend API email sending
│ │ ├── billing.go # Stripe checkout, webhooks, portal
│ │ ├── usage.go # Usage recording, quota calculation
│ │ ├── device.go # Device account limiting
│ │ └── pricing.go # Stripe price fetching/caching
│ ├── i18n/ # Internationalization (EN, BG)
│ ├── metrics/ # Prometheus metric definitions
│ └── session/ # Session cookie management
└── templates/ # HTML templates (login, checkout, email verify, etc.)