Преминете към основното съдържание

Схема на базата данни

Licensing Server използва PostgreSQL (Azure PostgreSQL в production, локален Docker container в development). Миграциите се управляват чрез golang-migrate и се прилагат автоматично при стартиране на сървъра.

ER диаграма

Таблици в детайли

users

Основната таблица с потребители. Поддържа както OAuth, така и email/password автентикация.

КолонаТипОписание
idUUID PKУникален идентификатор, генериран чрез gen_random_uuid()
emailVARCHAR(255)Email адрес на потребителя
nameVARCHAR(255)Име (nullable, от OAuth provider или регистрация)
avatar_urlVARCHAR(500)URL към аватар (nullable, от OAuth provider)
providerVARCHAR(20)Тип автентикация: google, azure, github, или email
provider_idVARCHAR(255)Уникален ID от provider-а (за email users = email адреса)
planVARCHAR(20)Текущ план: free или pro
stripe_customer_idVARCHAR(255)Stripe Customer ID (nullable, unique)
stripe_subscription_idVARCHAR(255)Stripe Subscription ID (nullable, unique)
created_atTIMESTAMPTZДата на създаване
updated_atTIMESTAMPTZПоследна промяна
trial_started_atTIMESTAMPTZНачало на trial период (nullable)
total_dictation_secondsFLOATКумулативно време на диктовка в секунди
total_dictation_countINTEGERОбщ брой диктовки
password_hashVARCHAR(255)bcrypt хеш на паролата (NULL за OAuth users)
email_verifiedBOOLEANДали email-ът е потвърден (OAuth users = TRUE автоматично)

Constraints:

  • uq_provider_identity UNIQUE (provider, provider_id) -- предотвратява дублиране на потребител от същия provider

Indexes:

  • idx_users_stripe_customer ON users (stripe_customer_id) -- за бързо търсене при Stripe webhooks

license_keys

Лицензни ключове, които могат да се активират от потребители.

КолонаТипОписание
idUUID PKУникален идентификатор
keyVARCHAR(32)Лицензен ключ (unique)
user_idUUID FKПотребител, който е активирал ключа
device_idVARCHAR(64)Устройство, на което е активиран
activated_atTIMESTAMPTZДата на активиране
is_activeBOOLEANДали ключът е активен
created_atTIMESTAMPTZДата на създаване

usage_records

Записи за използване на диктовка. Поддържа както автентикирани, така и анонимни (само device_id) потребители.

КолонаТипОписание
idUUID PKУникален идентификатор
user_idUUIDПотребител (NULL за анонимни записи)
device_idVARCHAR(128)Идентификатор на устройството
duration_secondsFLOATПродължителност на диктовката в секунди
recorded_atTIMESTAMPTZДата на записване

Indexes:

  • idx_usage_user_id -- за заявки по потребител
  • idx_usage_device_id -- за заявки по устройство (анонимни)
  • idx_usage_recorded_at -- за сортиране по време

stats_aggregate

Singleton таблица (id=1) с агрегирана статистика. Обновява се при всеки usage record чрез INSERT ... ON CONFLICT DO UPDATE (upsert).

КолонаТипОписание
idINTEGER PKВинаги 1 (singleton)
total_dictation_secondsFLOATОбщо време на диктовка за всички потребители
total_dictation_countINTEGERОбщ брой диктовки
updated_atTIMESTAMPTZПоследна промяна

device_accounts

Проследява кои потребителски акаунти са влизали от дадено устройство. Използва се за ограничаване на безплатни акаунти (anti-abuse).

КолонаТипОписание
idBIGSERIAL PKAuto increment ID
device_idTEXTИдентификатор на устройството
user_idUUID FKПотребител, който е влязъл
created_atTIMESTAMPTZДата на първо влизане от това устройство

Constraints:

  • uq_device_user UNIQUE (device_id, user_id) -- всяка комбинация се записва само веднъж

Indexes:

  • idx_device_accounts_device_id -- за бързо търсене по устройство

email_tokens

Токени за email verification и password reset. Само SHA-256 хешът на токена се съхранява в базата -- суровият токен се изпраща само в email-а.

КолонаТипОписание
idUUID PKУникален идентификатор
user_idUUID FKПотребител
token_hashVARCHAR(64)hex(sha256(rawToken)) -- unique
kindVARCHAR(20)Тип: verify или reset
expires_atTIMESTAMPTZДата на изтичане
used_atTIMESTAMPTZДата на използване (NULL до консумиране)
created_atTIMESTAMPTZДата на създаване

Indexes:

  • idx_email_tokens_user_kind ON (user_id, kind) -- за инвалидиране на стари токени
  • idx_email_tokens_expires ON (expires_at) -- за евентуално почистване

Миграции

Миграциите се намират в licensing-go/internal/database/migrations/ и се прилагат автоматично при стартиране на сървъра чрез golang-migrate.

МиграцияОписание
000001_initialСъздава users, license_keys, usage_records, stats_aggregate
000002_device_accountsДобавя device_accounts таблица за anti-abuse
000003_email_authДобавя password_hash, email_verified към users; създава email_tokens

Бележки за Azure PostgreSQL

  • pgcrypto разширението не е достъпно в Azure PostgreSQL -- вместо него се използва вградената функция gen_random_uuid() (PG 13+).
  • В production се изисква sslmode=require или sslmode=verify-full в DATABASE_URL.