Профиль клиента: выгрузка эталона и предзаполнение мастера под клиента

Страница /admin/setup/client-profile: скачать эталон текущей конфигурации (секреты
затёрты) и — для стенда — применить профиль клиента вручную. На боевом профиль
приходит с сервера лицензий (поле config_profile в ответе активации/продления) и
предзаполняет ещё НЕ настроенные разделы мастера, ничего не перетирая. Локальный
фолбэк — файл client-profile.json рядом с setup.json. Администратор правит профиль
под клиента на lic (отличия от стандарта).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XG3zNMMf2LMoDpXo22mwMX
This commit is contained in:
fontvielle
2026-10-16 09:58:23 +03:00
parent 3ba8dcc931
commit 13832fefad
5 changed files with 362 additions and 0 deletions
+7
View File
@@ -75,6 +75,7 @@ type licenseReply struct {
Tenant string `json:"tenant"`
ExpiresAt time.Time `json:"expires_at"`
ContractUntil time.Time `json:"contract_until"`
ConfigProfile json.RawMessage `json:"config_profile,omitempty"` // профиль настроек клиента (client_profile.go)
}
func licenseCall(ctx context.Context, path string, body map[string]string) (*licenseReply, error) {
@@ -168,6 +169,9 @@ func LicenseActivate(ctx context.Context, rc *RuntimeConfig, code string) error
return err
}
log.Printf("lk-gateway: лицензия активирована на сервере лицензий: %s, лицензия %s", r.Tenant, r.LicenseID)
if len(r.ConfigProfile) > 0 {
saveAndApplyClientProfile(rc, r.ConfigProfile, r.Tenant)
}
afterLicenseChange(rc)
return nil
}
@@ -198,6 +202,9 @@ func LicenseRenew(ctx context.Context, rc *RuntimeConfig) error {
if err := licenseAccept(rc, r.Token, "продлена"); err != nil {
return err
}
if len(r.ConfigProfile) > 0 {
saveAndApplyClientProfile(rc, r.ConfigProfile, r.Tenant)
}
if nl, err := verifyLicenseToken(r.Token); err == nil && licenseScopeChanged(lic, nl) {
afterLicenseChange(rc) // в лицензию добавили модуль или план — поставить, не дожидаясь перезапуска bj
} else {