Refactor webpack configuration to include multiple entry points for index and terms pages. Remove SSR script and update package dependencies for improved build process. Add terms.html as a static page with appropriate styles and metadata.
All checks were successful
platform/bro-js/bro.landing/pipeline/head This commit looks good
All checks were successful
platform/bro-js/bro.landing/pipeline/head This commit looks good
This commit is contained in:
parent
3b997a18e2
commit
6e55a331cb
@ -1,5 +1,6 @@
|
||||
/* eslint-disable @typescript-eslint/no-require-imports */
|
||||
/* eslint-disable no-undef */
|
||||
const path = require('path');
|
||||
const pkg = require('./package');
|
||||
const HtmlWebpackPlugin = require('html-webpack-plugin');
|
||||
const webpack = require('webpack');
|
||||
@ -13,15 +14,31 @@ module.exports = {
|
||||
version: 'master',
|
||||
name: 'cleanName',
|
||||
},
|
||||
},
|
||||
},
|
||||
webpackConfig: {
|
||||
entry: {
|
||||
index: './src/index.tsx',
|
||||
// terms страница не нужен JS, только HTML
|
||||
},
|
||||
output: {
|
||||
publicPath: isProd
|
||||
? 'https://static.brojs.ru/landing/main/'
|
||||
: `/static/${pkg.name}/${process.env.VERSION || pkg.version}/`,
|
||||
filename: '[name].js?[contenthash]',
|
||||
},
|
||||
plugins: [
|
||||
new HtmlWebpackPlugin({}),
|
||||
// Главная страница (с React)
|
||||
new HtmlWebpackPlugin({
|
||||
template: './src/index.ejs',
|
||||
filename: 'index.html',
|
||||
chunks: ['index'],
|
||||
}),
|
||||
// Terms страница (чистый HTML без JS)
|
||||
new HtmlWebpackPlugin({
|
||||
template: './src/terms.html',
|
||||
filename: 'terms.html',
|
||||
inject: false, // Не инжектим JS
|
||||
}),
|
||||
new webpack.DefinePlugin({
|
||||
IS_PROD: process.env.NODE_ENV === 'production',
|
||||
}),
|
||||
|
||||
2260
package-lock.json
generated
2260
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
14
package.json
14
package.json
@ -13,7 +13,7 @@
|
||||
"test": "jest --coverage",
|
||||
"start": "brojs server --port=8099 --with-open-browser",
|
||||
"build": "npm run clean && brojs build --dev",
|
||||
"build:prod": "npm run clean && brojs build && node scripts/ssr-render.js"
|
||||
"build:prod": "npm run clean && brojs build"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "",
|
||||
@ -22,10 +22,7 @@
|
||||
"@babel/preset-typescript": "7.24.7",
|
||||
"@brojs/cli": "1.9.5",
|
||||
"@chakra-ui/icons": "^2.1.1",
|
||||
"@chakra-ui/react": "^2.8.2",
|
||||
"@emotion/css": "^11.13.0",
|
||||
"@emotion/react": "^11.13.0",
|
||||
"@emotion/styled": "^11.13.0",
|
||||
"@reduxjs/toolkit": "^2.2.6",
|
||||
"dayjs": "^1.11.12",
|
||||
"express": "^4.19.2",
|
||||
@ -36,28 +33,19 @@
|
||||
"prettier": "^3.3.3",
|
||||
"react": "^18.3.1",
|
||||
"react-dom": "^18.3.1",
|
||||
"react-helmet": "^6.1.0",
|
||||
"react-i18next": "^15.0.0",
|
||||
"react-redux": "^9.1.2",
|
||||
"react-router-dom": "^6.25.1",
|
||||
"redux": "^5.0.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.28.5",
|
||||
"@babel/preset-env": "^7.28.5",
|
||||
"@babel/preset-react": "^7.28.5",
|
||||
"@babel/register": "^7.28.3",
|
||||
"@emotion/cache": "^11.14.0",
|
||||
"@emotion/server": "^11.11.0",
|
||||
"@eslint/js": "^9.9.0",
|
||||
"@types/jest": "^29.5.12",
|
||||
"babel-jest": "^29.7.0",
|
||||
"canvas": "^3.2.0",
|
||||
"eslint": "^8.57.0",
|
||||
"eslint-plugin-react": "^7.35.0",
|
||||
"eslint-plugin-react-hooks": "^4.6.2",
|
||||
"globals": "^15.9.0",
|
||||
"happy-dom": "^15.11.7",
|
||||
"html-webpack-plugin": "^5.6.0",
|
||||
"jest": "^29.7.0",
|
||||
"puppeteer": "^24.26.1",
|
||||
|
||||
@ -1,140 +0,0 @@
|
||||
/* eslint-disable @typescript-eslint/no-require-imports */
|
||||
/* eslint-disable no-undef */
|
||||
|
||||
// Настройка Babel для транспиляции TSX/JSX в Node.js
|
||||
require('@babel/register')({
|
||||
extensions: ['.ts', '.tsx', '.js', '.jsx'],
|
||||
presets: [
|
||||
'@babel/preset-env',
|
||||
'@babel/preset-react',
|
||||
'@babel/preset-typescript'
|
||||
],
|
||||
ignore: [/node_modules/],
|
||||
cache: false
|
||||
});
|
||||
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const React = require('react');
|
||||
const { renderToString } = require('react-dom/server');
|
||||
const { Window } = require('happy-dom');
|
||||
const { createCanvas } = require('canvas');
|
||||
|
||||
// Читаем index.ejs как основу для SSR
|
||||
const ejsTemplatePath = path.resolve(__dirname, '../src/index.ejs');
|
||||
const ejsTemplate = fs.readFileSync(ejsTemplatePath, 'utf-8');
|
||||
|
||||
// Настройка полноценного DOM окружения через happy-dom на основе index.ejs
|
||||
const window = new Window({
|
||||
url: 'http://localhost',
|
||||
width: 1024,
|
||||
height: 768
|
||||
});
|
||||
|
||||
const document = window.document;
|
||||
document.write(ejsTemplate);
|
||||
|
||||
// Расширяем happy-dom canvas поддержкой
|
||||
window.HTMLCanvasElement.prototype.getContext = function() {
|
||||
return createCanvas(200, 200).getContext('2d');
|
||||
};
|
||||
|
||||
global.window = window;
|
||||
global.document = document;
|
||||
global.navigator = window.navigator;
|
||||
global.HTMLElement = window.HTMLElement;
|
||||
global.SVGElement = window.SVGElement;
|
||||
|
||||
console.log('🚀 Запуск SSR с рендерингом React компонентов...');
|
||||
|
||||
try {
|
||||
// Импортируем компоненты
|
||||
const { UnderConstruction } = require('../src/pages/under-construction/underConstruction.tsx');
|
||||
const { Terms } = require('../src/pages/terms/Terms.tsx');
|
||||
const { ChakraProvider, extendTheme } = require('@chakra-ui/react');
|
||||
|
||||
console.log('✅ Компоненты загружены');
|
||||
|
||||
// Функция для рендера с Chakra UI + базовыми стилями
|
||||
function renderWithStyles(Component) {
|
||||
// Chakra theme с базовыми стилями
|
||||
const theme = extendTheme({});
|
||||
|
||||
// Генерируем базовые CSS переменные и стили Chakra
|
||||
const baseStyles = `
|
||||
<style data-emotion="chakra-global">
|
||||
:root,:host{--chakra-vh:100vh}@supports(height:100dvh){:root,:host{--chakra-vh:100dvh}}
|
||||
:root{color-scheme:light;--chakra-colors-chakra-body-text:#1A202C;--chakra-colors-chakra-body-bg:#fff;
|
||||
--chakra-colors-chakra-border-color:#E2E8F0;--chakra-colors-chakra-placeholder-color:#A0AEC0}
|
||||
body{background:var(--chakra-colors-chakra-body-bg);color:var(--chakra-colors-chakra-body-text);
|
||||
font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Helvetica,Arial,sans-serif;line-height:1.5}
|
||||
.chakra-container{width:100%;max-width:1200px;margin-left:auto;margin-right:auto;padding-left:16px;padding-right:16px}
|
||||
.chakra-stack>*:not(style)~*:not(style){margin-top:1.5rem;margin-inline-start:0}
|
||||
.chakra-heading{font-weight:700;font-size:1.875rem;line-height:2.25rem;margin-bottom:0.5rem}
|
||||
.chakra-text{margin:0;margin-bottom:0.5rem}
|
||||
.chakra-link{color:#3182ce;text-decoration:none}
|
||||
.chakra-link:hover{text-decoration:underline}
|
||||
.chakra-divider{border-color:var(--chakra-colors-chakra-border-color);border-style:solid;
|
||||
border-width:0;border-bottom-width:1px;margin-top:1rem;margin-bottom:1rem}
|
||||
ul,ol{margin-left:1.5rem;margin-bottom:1rem}
|
||||
li{margin-bottom:0.5rem}
|
||||
hr{border-top-width:1px;border-color:#E2E8F0}
|
||||
</style>`;
|
||||
|
||||
const html = renderToString(
|
||||
React.createElement(
|
||||
ChakraProvider,
|
||||
{ theme, cssVarsRoot: 'body' },
|
||||
React.createElement(Component)
|
||||
)
|
||||
);
|
||||
|
||||
return { html, styles: baseStyles };
|
||||
}
|
||||
|
||||
// Рендерим компоненты с извлечением стилей
|
||||
const { html: homeContent, styles: homeStyles } = renderWithStyles(UnderConstruction);
|
||||
const { html: termsContent, styles: termsStyles } = renderWithStyles(Terms);
|
||||
|
||||
console.log('✅ Компоненты отрендерены с Chakra UI + Emotion стилями');
|
||||
|
||||
// Читаем dist/index.html
|
||||
const distPath = path.resolve(__dirname, '../dist');
|
||||
const indexPath = path.join(distPath, 'index.html');
|
||||
let indexHtml = fs.readFileSync(indexPath, 'utf-8');
|
||||
|
||||
// 1. Главная страница
|
||||
const searchString = '<div id="app"></div>';
|
||||
if (indexHtml.includes(searchString)) {
|
||||
indexHtml = indexHtml
|
||||
.replace(searchString, `<div id="app">${homeContent}</div>`)
|
||||
.replace('</head>', `${homeStyles}</head>`);
|
||||
fs.writeFileSync(indexPath, indexHtml, 'utf-8');
|
||||
console.log('✅ index.html обновлен с SSR контентом и стилями');
|
||||
}
|
||||
|
||||
// 2. Страница terms
|
||||
let termsHtml = indexHtml
|
||||
.replace(homeContent, termsContent)
|
||||
.replace(homeStyles, termsStyles)
|
||||
.replace('<title>bro-js admin</title>', '<title>Пользовательское соглашение - BROJS.RU</title>')
|
||||
.replace(
|
||||
'</head>',
|
||||
'<meta name="description" content="Пользовательское соглашение для платформы обучения фронтенд-разработке BROJS.RU. Условия использования, обработка персональных данных, права и обязанности сторон." /></head>'
|
||||
);
|
||||
|
||||
const termsPath = path.join(distPath, 'terms.html');
|
||||
fs.writeFileSync(termsPath, termsHtml, 'utf-8');
|
||||
console.log('✅ terms.html создан с SSR контентом и стилями');
|
||||
|
||||
console.log('🎉 SSR завершен успешно!');
|
||||
console.log('📄 Созданы: index.html, terms.html');
|
||||
console.log('💡 Весь контент отрендерен через React SSR');
|
||||
console.log('🎨 Критические стили Emotion встроены в HTML');
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ Ошибка при SSR:', error.message);
|
||||
console.error(error.stack);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
12
src/app.tsx
12
src/app.tsx
@ -1,19 +1,13 @@
|
||||
import React from "react";
|
||||
import { BrowserRouter } from "react-router-dom";
|
||||
import {Helmet} from 'react-helmet';
|
||||
|
||||
import { Dashboard } from './dashboard';
|
||||
|
||||
const App = () => {
|
||||
return (
|
||||
<>
|
||||
<Helmet>
|
||||
<title>bro js</title>
|
||||
</Helmet>
|
||||
<BrowserRouter>
|
||||
<Dashboard />
|
||||
</BrowserRouter>
|
||||
</>
|
||||
<BrowserRouter>
|
||||
<Dashboard />
|
||||
</BrowserRouter>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@ -1,14 +1,13 @@
|
||||
import React from 'react';
|
||||
import { Routes, Route } from 'react-router-dom';
|
||||
|
||||
import { UnderConstructionPage, TermsPage } from './pages';
|
||||
import { UnderConstructionPage } from './pages';
|
||||
|
||||
export const Dashboard = () => {
|
||||
return (
|
||||
<Routes>
|
||||
<Route path="/terms" element={<TermsPage />} />
|
||||
<Route path="/" element={<UnderConstructionPage />} />
|
||||
<Route path="*" element={<h1>Страница не найдена</h1>} />
|
||||
<Route path="*" element={<UnderConstructionPage />} />
|
||||
</Routes>
|
||||
);
|
||||
};
|
||||
|
||||
@ -1,2 +1 @@
|
||||
export { default as UnderConstructionPage } from './under-construction';
|
||||
export { Terms as TermsPage } from './terms';
|
||||
|
||||
268
src/terms.html
Normal file
268
src/terms.html
Normal file
@ -0,0 +1,268 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="ru">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta http-equiv="X-UA-Compatible" content="ie=edge">
|
||||
<title>Пользовательское соглашение - BROJS.RU</title>
|
||||
<meta name="description" content="Пользовательское соглашение для платформы обучения фронтенд-разработке BROJS.RU. Условия использования, обработка персональных данных, права и обязанности сторон.">
|
||||
<meta name="yandex-verification" content="98f7e15d1ad66018">
|
||||
<link href="https://fonts.googleapis.com/css?family=Montserrat:400,600,700,900&subset=cyrillic,cyrillic-ext" rel="stylesheet">
|
||||
<style>
|
||||
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif;
|
||||
line-height: 1.6;
|
||||
color: #1a202c;
|
||||
background: #f7fafc;
|
||||
}
|
||||
.container {
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
padding: 40px 20px;
|
||||
}
|
||||
.terms-doc {
|
||||
background: white;
|
||||
padding: 60px 80px;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
@media (max-width: 768px) {
|
||||
.terms-doc { padding: 40px 24px; }
|
||||
}
|
||||
h1 {
|
||||
font-size: 2.5rem;
|
||||
font-weight: 700;
|
||||
color: #2d3748;
|
||||
text-align: center;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
.subtitle {
|
||||
text-align: center;
|
||||
color: #718096;
|
||||
font-size: 1.1rem;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
.date {
|
||||
text-align: center;
|
||||
color: #a0aec0;
|
||||
font-size: 0.9rem;
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
hr {
|
||||
border: none;
|
||||
border-top: 1px solid #e2e8f0;
|
||||
margin: 2rem 0;
|
||||
}
|
||||
h2 {
|
||||
font-size: 1.75rem;
|
||||
font-weight: 700;
|
||||
color: #2d3748;
|
||||
margin: 2rem 0 1rem;
|
||||
}
|
||||
h3 {
|
||||
font-size: 1.25rem;
|
||||
font-weight: 600;
|
||||
color: #4a5568;
|
||||
margin: 1.5rem 0 0.75rem;
|
||||
}
|
||||
p {
|
||||
margin-bottom: 1rem;
|
||||
color: #4a5568;
|
||||
}
|
||||
ul {
|
||||
margin: 1rem 0 1rem 2rem;
|
||||
color: #4a5568;
|
||||
}
|
||||
li {
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
a {
|
||||
color: #3182ce;
|
||||
text-decoration: none;
|
||||
}
|
||||
a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
strong {
|
||||
font-weight: 600;
|
||||
color: #2d3748;
|
||||
}
|
||||
.footer {
|
||||
text-align: center;
|
||||
margin-top: 3rem;
|
||||
padding-top: 2rem;
|
||||
border-top: 1px solid #e2e8f0;
|
||||
color: #a0aec0;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<noscript><div><img src="https://mc.yandex.ru/watch/87860751" style="position:absolute; left:-9999px;" alt=""></div></noscript>
|
||||
|
||||
<div class="container">
|
||||
<div class="terms-doc">
|
||||
<h1>Пользовательское соглашение</h1>
|
||||
<p class="subtitle">для BROJS.RU</p>
|
||||
<p class="date">Последнее обновление: 25 мая 2025 г.</p>
|
||||
|
||||
<hr>
|
||||
|
||||
<h2>1. Термины</h2>
|
||||
<p><strong>Платформа</strong> — сайт <a href="https://brojs.ru" target="_blank">https://brojs.ru</a>, предоставляющий услуги обучения фронтенд-разработке.</p>
|
||||
<p><strong>Пользователь</strong> — лицо, зарегистрированное на Платформе.</p>
|
||||
<p><strong>Микрофронтенд-проект</strong> — код, конфигурации и иные материалы, созданные Пользователем.</p>
|
||||
<p><strong>Gravatar</strong> — сторонний сервис (<a href="https://gravatar.com" target="_blank">https://gravatar.com</a>), предоставляющий аватары на основе email-адресов пользователей.</p>
|
||||
<p><strong>Интеллектуальная собственность</strong> — результаты интеллектуальной деятельности, включая, но не ограничиваясь, программные коды, дизайны, тексты, графику и другие объекты, защищенные законом.</p>
|
||||
|
||||
<h2>2. Условия использования</h2>
|
||||
<h3>2.1. Регистрация</h3>
|
||||
<p>Регистрация осуществляется через:</p>
|
||||
<ul>
|
||||
<li>Аккаунт Yandex;</li>
|
||||
<li>Email (с подтверждением через ссылку).</li>
|
||||
</ul>
|
||||
|
||||
<h3>2.2. Обязанности Пользователя</h3>
|
||||
<p>Пользователь обязуется:</p>
|
||||
<ul>
|
||||
<li>Не передавать учетные данные третьим лицам;</li>
|
||||
<li>Не использовать Платформу для распространения незаконного контента или совершения мошеннических действий;</li>
|
||||
<li>Соблюдать конфиденциальность личных данных других участников Платформы.</li>
|
||||
</ul>
|
||||
|
||||
<h2>3. Персональные данные</h2>
|
||||
<h3>3.1. Собираемые данные</h3>
|
||||
<p>Платформа собирает:</p>
|
||||
<ul>
|
||||
<li>Никнейм;</li>
|
||||
<li>Email;</li>
|
||||
<li>ФИО (при наличии договора с учебным заведением);</li>
|
||||
<li>Данные о посещении занятий (через QR-код).</li>
|
||||
</ul>
|
||||
|
||||
<h3>3.2. Аватар через Gravatar</h3>
|
||||
<ul>
|
||||
<li>Платформа не хранит аватары на своих серверах. Для отображения используется Gravatar.</li>
|
||||
<li>Ссылка на аватар формируется на основе хэша email пользователя.</li>
|
||||
<li>Пользователь может активировать/отозвать согласие на использование Gravatar в настройках профиля.</li>
|
||||
<li>Отказ от Gravatar приведет к отображению стандартного изображения.</li>
|
||||
</ul>
|
||||
|
||||
<h3>3.3. Цели обработки данных</h3>
|
||||
<ul>
|
||||
<li>Предоставление доступа к Платформе;</li>
|
||||
<li>Передача данных о посещении учебным заведениям (ФИО, email, дата и время) в формате Excel.</li>
|
||||
</ul>
|
||||
|
||||
<h3>3.4. Хранение и передача данных</h3>
|
||||
<ul>
|
||||
<li>Персональные данные хранятся в СУБД PostgreSQL через Keycloak.</li>
|
||||
<li>Данные о посещении передаются учебным заведениям на основании договоров с преподавателями.</li>
|
||||
<li>Передача данных осуществляется с применением шифрования и протоколов безопасности.</li>
|
||||
</ul>
|
||||
|
||||
<h3>3.5. Срок хранения</h3>
|
||||
<ul>
|
||||
<li>Персональные данные удаляются в течение 30 дней после удаления аккаунта.</li>
|
||||
<li>Микрофронтенд-проекты хранятся 6 месяцев после завершения обучения.</li>
|
||||
</ul>
|
||||
|
||||
<h3>3.6. Отзыв согласия</h3>
|
||||
<ul>
|
||||
<li>Для отзыва согласия на обработку персональных данных необходимо направить письмо на <a href="mailto:primakov.pro@yandex.ru">primakov.pro@yandex.ru</a>.</li>
|
||||
<li>Отзыв приведет к удалению всех данных пользователя вручную.</li>
|
||||
<li>Частичное удаление отдельных категорий данных возможно по заявлению пользователя.</li>
|
||||
</ul>
|
||||
|
||||
<h2>4. Интеллектуальная собственность</h2>
|
||||
<h3>4.1. Права Пользователя</h3>
|
||||
<ul>
|
||||
<li>Пользователь сохраняет авторские права на созданные проекты.</li>
|
||||
<li>Платформа не имеет прав на использование материалов Пользователя без явного согласия.</li>
|
||||
</ul>
|
||||
|
||||
<h3>4.2. Права Администрации</h3>
|
||||
<ul>
|
||||
<li>Администрация вправе удалить контент при нарушении условий соглашения или через 6 месяцев после завершения обучения.</li>
|
||||
<li>Проверка подлинности загружаемого материала осуществляется преподавателем, отвечающим за группу.</li>
|
||||
</ul>
|
||||
|
||||
<h2>5. Ответственность</h2>
|
||||
<h3>5.1. Ограничение ответственности</h3>
|
||||
<p>Администрация не несет ответственности за:</p>
|
||||
<ul>
|
||||
<li>Утрату данных из-за действий Пользователя;</li>
|
||||
<li>Использование данных учебными заведениями после их передачи;</li>
|
||||
<li>Некорректное отображение аватаров через Gravatar.</li>
|
||||
</ul>
|
||||
|
||||
<h3>5.2. Основания для блокировки аккаунта</h3>
|
||||
<ul>
|
||||
<li>Нарушение авторских прав;</li>
|
||||
<li>Распространение спама/вирусов;</li>
|
||||
<li>Предоставление недостоверных данных (включая ФИО).</li>
|
||||
</ul>
|
||||
|
||||
<h3>5.3. Компенсация ущерба</h3>
|
||||
<ul>
|
||||
<li>В случае нарушения правил или утечки данных, Администрация обязана принять меры для минимизации последствий.</li>
|
||||
</ul>
|
||||
|
||||
<h2>6. Уведомления</h2>
|
||||
<h3>6.1. Информационные сообщения</h3>
|
||||
<p>Платформа вправе отправлять Пользователю:</p>
|
||||
<ul>
|
||||
<li>Уведомления о технических работах, изменениях функционала;</li>
|
||||
<li>Сообщения о нарушениях или блокировке аккаунта;</li>
|
||||
<li>Рекламу собственных услуг или услуг третьих лиц.</li>
|
||||
</ul>
|
||||
|
||||
<h3>6.2. Отказ от уведомлений</h3>
|
||||
<ul>
|
||||
<li>Отказ от рекламных сообщений возможен через настройки Личного кабинета.</li>
|
||||
<li>Отказ от информационных уведомлений может ограничить доступ к функциям Платформы.</li>
|
||||
</ul>
|
||||
|
||||
<h2>7. Безопасность данных</h2>
|
||||
<h3>7.1. Технические меры</h3>
|
||||
<ul>
|
||||
<li>Данные хранятся в СУБД PostgreSQL через Keycloak.</li>
|
||||
<li>Шифрование данных при передаче (HTTPS).</li>
|
||||
<li>Периодические тестирования системы на уязвимости.</li>
|
||||
</ul>
|
||||
|
||||
<h3>7.2. Двухфакторная аутентификация</h3>
|
||||
<ul>
|
||||
<li>Пользователи могут добровольно активировать двухфакторную аутентификацию (OTP) через Личный кабинет.</li>
|
||||
</ul>
|
||||
|
||||
<h2>8. Применимое право и разрешение споров</h2>
|
||||
<h3>8.1. Применимое право</h3>
|
||||
<ul>
|
||||
<li>Соглашение регулируется законодательством РФ. Для пользователей из стран СНГ применяются нормы ЕАЭС.</li>
|
||||
<li>При расширении географии услуг Платформа будет соблюдать законодательство стран ЕСВР и ЕС.</li>
|
||||
</ul>
|
||||
|
||||
<h3>8.2. Разрешение споров</h3>
|
||||
<ul>
|
||||
<li>Споры разрешаются в суде по месту нахождения администрации Платформы.</li>
|
||||
</ul>
|
||||
|
||||
<h2>9. Изменения соглашения</h2>
|
||||
<p>Изменения вступают в силу после публикации на сайте.</p>
|
||||
|
||||
<h2>10. Контакты</h2>
|
||||
<p>Для обращений: <a href="mailto:primakov.pro@yandex.ru">primakov.pro@yandex.ru</a></p>
|
||||
|
||||
<div class="footer">
|
||||
<p>© 2025 BROJS.RU. Все права защищены.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="https://static.brojs.ru/fire.app/1.8.4/index.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user