first commit

This commit is contained in:
lendry
2026-06-24 14:37:15 +03:00
commit 995adeedd4
188 changed files with 28810 additions and 0 deletions

View File

@@ -0,0 +1,62 @@
export type SystemSettingFieldType = 'text' | 'number' | 'boolean';
export interface SystemSettingMeta {
key: string;
label: string;
group: string;
type: SystemSettingFieldType;
unit?: string;
hint?: string;
}
export const SYSTEM_SETTING_GROUPS: Record<string, string> = {
general: 'Проект и брендинг',
pin: 'PIN-код и блокировка сессии',
auth: 'Аутентификация и регистрация',
ldap: 'LDAP / Active Directory',
limits: 'Лимиты и ограничения',
media: 'Медиа и файлы'
};
export const SYSTEM_SETTING_CATALOG: SystemSettingMeta[] = [
{ key: 'PROJECT_NAME', label: 'Название проекта', group: 'general', type: 'text', hint: 'Отображается в меню, заголовке и боковой панели' },
{ key: 'PROJECT_TAGLINE', label: 'Слоган проекта', group: 'general', type: 'text' },
{ key: 'PROJECT_DOMAIN', label: 'Домен IdP', group: 'general', type: 'text' },
{ key: 'PIN_LOCK_TIMEOUT_MINUTES', label: 'Таймаут блокировки PIN', group: 'pin', type: 'number', unit: 'мин' },
{ key: 'PIN_DELETE_GRACE_MINUTES', label: 'Задержка удаления PIN', group: 'pin', type: 'number', unit: 'мин', hint: 'Сколько ждать после запроса удаления PIN-кода' },
{ key: 'PIN_REQUIRE_ON_DELETE', label: 'Требовать PIN при удалении', group: 'pin', type: 'boolean' },
{ key: 'PIN_MIN_LENGTH', label: 'Мин. длина PIN', group: 'pin', type: 'number', unit: 'цифр' },
{ key: 'PIN_MAX_LENGTH', label: 'Макс. длина PIN', group: 'pin', type: 'number', unit: 'цифр' },
{ key: 'OTP_EXPIRY_MINUTES', label: 'Срок жизни OTP', group: 'auth', type: 'number', unit: 'мин' },
{ key: 'OTP_MAX_ATTEMPTS', label: 'Попыток ввода OTP', group: 'auth', type: 'number' },
{ key: 'SESSION_REFRESH_DAYS', label: 'Срок refresh-токена', group: 'auth', type: 'number', unit: 'дн' },
{ key: 'PASSWORD_MIN_LENGTH', label: 'Мин. длина пароля', group: 'auth', type: 'number', unit: 'симв' },
{ key: 'REGISTRATION_ENABLED', label: 'Регистрация включена', group: 'auth', type: 'boolean' },
{ key: 'MAINTENANCE_MODE', label: 'Режим обслуживания', group: 'auth', type: 'boolean', hint: 'Блокирует вход для обычных пользователей' },
{ key: 'LDAP_ENABLED', label: 'LDAP включён', group: 'ldap', type: 'boolean', hint: 'Показывает кнопку входа через LDAP на странице авторизации' },
{ key: 'LDAP_USE_LDAPS', label: 'Использовать LDAPS', group: 'ldap', type: 'boolean', hint: 'Шифрованное подключение (порт 636)' },
{ key: 'LDAP_HOST', label: 'Хост LDAP', group: 'ldap', type: 'text', hint: 'DC-1.local,DC-2.local или ldaps://DC-1.local:636' },
{ key: 'LDAP_PORT', label: 'Порт LDAP', group: 'ldap', type: 'number', hint: '636 для LDAPS, 389 для LDAP. Не используйте 640.' },
{ key: 'LDAP_DOMAIN', label: 'Домен AD', group: 'ldap', type: 'text', hint: 'mvkug.local — для bind вида user@domain' },
{ key: 'LDAP_SKIP_TLS_VERIFY', label: 'Не проверять TLS', group: 'ldap', type: 'boolean', hint: 'Только для тестовых окружений' },
{ key: 'LDAP_BASE_DN', label: 'Base DN (поиск пользователей)', group: 'ldap', type: 'text', hint: 'OU или CN контейнера с пользователями. Напр. OU=Lugansk,DC=mvkug,DC=local. Если CN не работает — попробуйте OU' },
{ key: 'LDAP_BIND_USERNAME', label: 'Логин сервисной УЗ', group: 'ldap', type: 'text', hint: 'mvkadmin или mvkug\\mvkadmin — учётная запись для подключения к AD' },
{ key: 'LDAP_BIND_DN', label: 'Bind DN (опционально)', group: 'ldap', type: 'text', hint: 'Полный DN сервисной УЗ. Оставьте пустым, если указан логин выше' },
{ key: 'LDAP_BIND_PASSWORD', label: 'Пароль сервисной УЗ', group: 'ldap', type: 'text', hint: 'Секретное значение' },
{ key: 'LDAP_USER_FILTER', label: 'Фильтр пользователя', group: 'ldap', type: 'text', hint: 'Placeholder {username}' },
{ key: 'LDAP_USERNAME_ATTR', label: 'Атрибут логина', group: 'ldap', type: 'text' },
{ key: 'LDAP_EMAIL_ATTR', label: 'Атрибут почты', group: 'ldap', type: 'text' },
{ key: 'LDAP_DISPLAY_NAME_ATTR', label: 'Атрибут имени', group: 'ldap', type: 'text' },
{ key: 'MAX_FAMILY_MEMBERS', label: 'Макс. участников семьи', group: 'limits', type: 'number' },
{ key: 'MAX_ACTIVE_SESSIONS', label: 'Макс. активных сессий', group: 'limits', type: 'number' },
{ key: 'AVATAR_URL_TTL_MINUTES', label: 'TTL ссылки на аватар', group: 'media', type: 'number', unit: 'мин' }
];
export function getSettingMeta(key: string) {
return SYSTEM_SETTING_CATALOG.find((item) => item.key === key);
}
export function sortSettingsByCatalog<T extends { key: string }>(settings: T[]) {
const order = new Map(SYSTEM_SETTING_CATALOG.map((item, index) => [item.key, index]));
return [...settings].sort((a, b) => (order.get(a.key) ?? 999) - (order.get(b.key) ?? 999));
}