docs: Add comprehensive project documentation covering architecture, development, and APIs, and update AGENTS.md.
All checks were successful
Build and Push Docker Images / build-and-push-backend (push) Successful in 17s
Build and Push Docker Images / build-and-push-frontend (push) Successful in 10s
Build and Push Docker Images / deploy-to-k8s (push) Successful in 1m57s

This commit is contained in:
Zuev
2026-03-22 02:49:13 +03:00
parent 81e91e056f
commit 491807cd94
10 changed files with 1829 additions and 145 deletions

275
docs/DEVELOPMENT.md Normal file
View File

@@ -0,0 +1,275 @@
# 🛠 Руководство для разработчиков
## Локальный запуск
### Предварительные требования
- Docker и Docker Compose
- Git
- (Опционально) Java 17 + Maven 3.9+ для запуска backend вне Docker
### Первый запуск
```bash
# Создать Docker-сеть
docker network create proxy
# Собрать и запустить
docker compose up -d --build
# Убедиться, что всё работает
docker compose logs -f
```
Приложение доступно: **http://localhost:80**
### Пересборка после изменений
```bash
# Пересобрать только backend
docker compose up -d --build backend
# Пересобрать только frontend
docker compose up -d --build frontend
```
### Полный сброс данных
```bash
docker compose down -v # Удаляет БД
docker compose up -d # Пересоздаёт с нуля
```
---
## Соглашения о коде
### Java (Backend)
#### Именование
| Категория | Стиль | Пример |
|-----------|-------|--------|
| Классы | PascalCase | `LessonsController`, `LessonResponse` |
| Методы и переменные | camelCase | `getAllLessons()`, `teacherId` |
| Константы | UPPER_SNAKE_CASE | `ROLE_REDIRECTS` |
| Пакеты | lowercase | `com.magistr.app.controller` |
#### Архитектурные правила
- **Constructor Injection** — все зависимости через конструктор (не `@Autowired` на поля)
- **Controller → Repository** — контроллеры работают напрямую с репозиториями (без слоя service)
- **Префикс `/api/`** — все REST-эндпоинты
- **`ResponseEntity<?>`** — все мутирующие методы возвращают `ResponseEntity` с HTTP-статусом
- **Сообщения на русском** — все ошибки и уведомления на русском языке
#### Логирование
Используйте SLF4J:
```java
private static final Logger logger = LoggerFactory.getLogger(MyController.class);
// Информационные сообщения
logger.info("Запрос на получение всех занятий");
// Ошибки с полным стектрейсом
logger.error("Ошибка при сохранении: {}", e.getMessage(), e);
```
#### Валидация
- Для сложных правил — отдельные классы-валидаторы (`DayAndWeekValidator`, `TypeAndFormatLessonValidator`)
- Для простых — inline-проверки в контроллере с `ResponseEntity.badRequest()`
#### Импорты
```java
// 1. Static imports
import static org.junit.Assert.*;
// 2. Java/Jakarta
import java.util.*;
import jakarta.persistence.*;
// 3. External libraries
import org.springframework.web.bind.annotation.*;
import com.fasterxml.jackson.databind.ObjectMapper;
// 4. Internal packages (wildcard для того же модуля)
import com.magistr.app.model.*;
import com.magistr.app.repository.*;
```
#### Форматирование
- **Отступы:** 4 пробела
- **Скобки:** K&R style (открывающая на той же строке)
- **Длина строки:** до 120 символов
- **Фигурные скобки** обязательны для `if`/`for`/`while`
### JavaScript (Frontend)
#### Именование
| Категория | Стиль | Пример |
|-----------|-------|--------|
| Файлы | kebab-case | `main.js`, `schedule-view.js` |
| Функции и переменные | camelCase | `loadUsers()`, `pageTitle` |
| Константы | UPPER_SNAKE_CASE | `API_BASE_URL` |
#### Модули
- ES6 Modules с `import`/`export`
- **Всегда указывать расширение:** `import { api } from './api.js';`
#### Лучшие практики
```javascript
// ✅ Предпочитайте const
const token = localStorage.getItem('token');
// ✅ Async/await вместо .then()
async function loadData() {
try {
const data = await api.get('/api/users');
} catch (e) {
console.error('Ошибка:', e.message);
}
}
// ✅ Template literals
const msg = `Найдено ${items.length} записей`;
// ✅ Деструктуризация
const { id, name, role } = user;
```
#### Форматирование
- **Отступы:** 4 пробела
- **Кавычки:** одинарные `'`
- **Точки с запятой:** обязательны
---
## Создание нового эндпоинта (пошагово)
### 1. Модель (если нужна новая таблица)
Создайте Flyway миграцию `V{N}__{description}.sql`:
```sql
-- backend/src/main/resources/db/migration/V3__add_absences.sql
CREATE TABLE IF NOT EXISTS absences (
id BIGSERIAL PRIMARY KEY,
teacher_id BIGINT NOT NULL REFERENCES users(id),
reason VARCHAR(255) NOT NULL,
start_date DATE NOT NULL,
end_date DATE NOT NULL
);
```
Создайте JPA-сущность:
```java
@Entity
@Table(name = "absences")
public class Absence {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
// ...
}
```
### 2. Репозиторий
```java
public interface AbsenceRepository extends JpaRepository<Absence, Long> {
List<Absence> findByTeacherId(Long teacherId);
}
```
### 3. DTO (опционально)
```java
public record AbsenceResponse(Long id, String teacherName, String reason) {}
```
### 4. Контроллер
```java
@RestController
@RequestMapping("/api/absences")
public class AbsenceController {
private final AbsenceRepository absenceRepository;
public AbsenceController(AbsenceRepository absenceRepository) {
this.absenceRepository = absenceRepository;
}
@GetMapping
public List<Absence> getAll() {
return absenceRepository.findAll();
}
}
```
---
## Работа с миграциями Flyway
### Правила
1. **Никогда** не изменяйте уже закоммиченные файлы миграций
2. Имя файла: `V{номер}__{описание}.sql` (два подчёркивания!)
3. Нумерация строго инкрементальная: `V1`, `V2`, `V3`, ...
4. После добавления — перезапустите backend для применения
### Применение
```bash
# Локально — сброс и повтор всех миграций
docker compose down -v && docker compose up -d
# Продакшн — применить к существующим тенантам
kubectl rollout restart deployment backend -n magistr
```
---
## Структура пакетов (Backend)
```
com.magistr.app/
├── Application.java # Точка входа
├── config/
│ ├── AppConfig.java # Бины (BCryptPasswordEncoder)
│ ├── DataInitializer.java # Инициализация данных
│ └── tenant/ # Мультитенантность
│ ├── TenantConfig.java # POJO конфигурации тенанта
│ ├── TenantContext.java # ThreadLocal текущего тенанта
│ ├── TenantInterceptor.java # Определение тенанта из Host
│ ├── TenantRoutingDataSource.java # Маршрутизация к БД
│ ├── TenantDataSourceConfig.java # Spring-конфигурация
│ ├── TenantConfigWatcher.java # Периодическая синхронизация
│ └── ConfigMapUpdater.java # Обновление K8s ConfigMap
├── controller/ # REST-контроллеры
│ ├── AuthController.java
│ ├── LessonsController.java
│ ├── ClassroomController.java
│ ├── DatabaseController.java
│ ├── UserController.java
│ ├── GroupController.java
│ ├── SubjectController.java
│ ├── EquipmentController.java
│ ├── EducationFormController.java
│ └── TeacherSubjectController.java
├── dto/ # Data Transfer Objects
├── model/ # JPA-сущности
├── repository/ # Spring Data JPA
└── utils/ # Валидаторы
├── DayAndWeekValidator.java
└── TypeAndFormatLessonValidator.java
```