No description
  • Go 91.6%
  • Makefile 8.4%
Find a file
2026-10-13 00:47:36 +03:00
api feat: api codegen, sqlc generation, started to implement methods 2026-10-13 00:47:36 +03:00
cmd/server feat: api codegen, sqlc generation, started to implement methods 2026-10-13 00:47:36 +03:00
internal feat: api codegen, sqlc generation, started to implement methods 2026-10-13 00:47:36 +03:00
.env.example feat: initial & database scheme & migrations 2026-10-11 23:58:36 +03:00
.gitignore fix: gitignore 2026-10-12 00:01:02 +03:00
go.mod feat: api codegen, sqlc generation, started to implement methods 2026-10-13 00:47:36 +03:00
go.sum feat: api codegen, sqlc generation, started to implement methods 2026-10-13 00:47:36 +03:00
main.go feat: initial & database scheme & migrations 2026-10-11 23:58:36 +03:00
Makefile feat: api codegen, sqlc generation, started to implement methods 2026-10-13 00:47:36 +03:00
README.md feat: initial & database scheme & migrations 2026-10-11 23:58:36 +03:00
sqlc.yaml feat: api codegen, sqlc generation, started to implement methods 2026-10-13 00:47:36 +03:00

АСО-Контроль — Backend

Серверная часть сервиса контроля наличия и исправности аварийно-спасательного оборудования (АСО) воздушных судов.

Бэкенд — единственный источник правды: хранит борты и оборудование, принимает считанные RFID-метки с мобильного приложения, сам сравнивает факт с ожидаемым, сам считает статусы по срокам и сам отправляет заявки инженерам.

Решения по проекту

Вопрос Решение
Офлайн-режим Нет. Приложение всегда работает с сервером
Роли inspector и admin. Роли «инженер» в системе нет
Заявки инженерам Уходят во внешний API как уведомление. Для демо — mock
Клиенты Мобильное приложение сейчас, веб-админка позже
API Ресурсный, без эндпоинтов «под экран». Контракт — api/openapi.json, он первичен
Стек Go, PostgreSQL, миграции goose, JWT

Статус

# Этап Состояние
1 Первая миграция (users, aircraft, equipment_types, equipment), /health миграции готовы, /health — нет
2 Генерация кода из OpenAPI, /auth/login, /auth/me, JWT-middleware, проверка admin не начат
3 CRUD бортов и оборудования, /tags/{code} не начат
4 Осмотры: start, scans, close + интеграционные тесты не начат
5 Заявки (/requests) + mock внешнего API не начат

Структура репозитория

cmd/server/main.go          # сборка зависимостей, запуск
api/openapi.json            # твой спек
internal/
  api/gen.go                # сгенерировано oapi-codegen (не править)
  db/migrations/*.sql       # goose
  db/queries/*.sql          # запросы для sqlc
  db/sqlc/                  # сгенерировано sqlc
  handler/                  # реализация интерфейса StrictServerInterface
  service/                  # бизнес-логика: осмотры, заявки, статусы
  auth/                     # JWT, middleware, проверка роли
  notify/                   # клиент внешней системы заявок
sqlc.yaml
oapi-codegen.yaml
Makefile                    # generate, migrate, run, test                            команды миграций

Модель данных

  • users — login, password_hash (bcrypt через pgcrypto), full_name, role ∈ {inspector, admin}.

  • aircraft — tail_number (уникальный бортовой номер), model.

  • equipment_types — name, has_expiry_date (нужен ли срок годности).

  • equipment — единица оборудования: тип, serial_number, tag_code (код RFID-метки, уникален), aircraft_id, location, expiry_date, status ∈ {ok, faulty, missing}. Пара (type_id, serial_number) уникальна. При удалении борта оборудование не удаляется, а открепляется (aircraft_id = NULL).

  • equipment_v — view, добавляет effective_status:

    Условие effective_status
    в таблице faulty или missing как в таблице
    у типа есть срок и expiry_date < сегодня expired
    у типа есть срок и expiry_date < сегодня + 30 дней expiring
    иначе ok

    Статусы expired и expiring не хранятся — считаются на лету, пересчитывать по расписанию не нужно. Порог 30 дней сейчас зашит во view.

Таблиц inspections, inspection_scans и requests ещё нет — они появятся в миграциях этапов 4 и 5.

API

Базовый URL: http://localhost:8080/api. Полное описание — в api/openapi.json.

Общие правила:

  • JSON, поля в camelCase; даты YYYY-MM-DD, время — ISO 8601 UTC.
  • Авторизация: Authorization: Bearer <token>, кроме /auth/login и /health.
  • Ошибки: {"error": {"code": "not_found", "message": "..."}}.
  • Эндпоинты, помеченные (admin), доступны только администратору.
Метод Путь Описание
GET /health сервер и БД живы
POST /auth/login вход, возвращает токен и пользователя
GET /auth/me текущий пользователь
GET, POST /aircraft список бортов (со счётчиками equipmentCount, problemCount, lastInspectionAt) / добавить (admin)
GET, PUT, DELETE /aircraft/{id} карточка борта с оборудованием / изменить (admin) / удалить (admin)
GET, POST /equipment-types типы оборудования / добавить (admin)
GET, POST /equipment список (фильтры aircraftId, status) / добавить (admin)
GET, PUT, DELETE /equipment/{id} карточка / изменить (admin) / удалить (admin)
GET /tags/{code} найти оборудование по коду метки
GET, POST /inspections список (фильтры aircraftId, status) / начать осмотр борта
GET /inspections/{id} состояние осмотра: найдено / не найдено
POST /inspections/{id}/scans отправить один считанный код метки
POST /inspections/{id}/close закрыть осмотр, получить итог
GET, POST /requests список заявок (фильтр aircraftId) / создать заявку инженерам

Сценарий осмотра

  1. POST /inspections {aircraftId} — осмотр в статусе in_progress.
  2. На каждую считанную метку — POST /inspections/{id}/scans {code, source}. Сервер возвращает вердикт result:
    • expected — оборудование этого борта, засчитано;
    • already_scanned — уже считано в этом осмотре;
    • wrong_aircraft — числится на другом борту;
    • unknown — метки нет в системе.
  3. GET /inspections/{id} — что найдено, что ещё нет.
  4. POST /inspections/{id}/close — осмотр closed; итог InspectionSummary: expected, found, notFound, extra, expired.
  5. По проблемному оборудованию (faulty / missing / expired) — POST /requests {equipmentId, inspectionId, reason, comment}. Сервер отправляет уведомление во внешний API и сохраняет статус sent или failed.

source сканирования: nfc (по умолчанию), ble, manual, mock.

Быстрый старт

Нужны: Go, PostgreSQL с расширением pgcrypto, goose.

# 1. БД и расширение (один раз, от суперпользователя)
psql "$DB_URL" -c 'CREATE EXTENSION IF NOT EXISTS pgcrypto;'

# 2. Миграции (Makefile читает DB_URL из окружения)
export DB_URL='postgres://user:pass@localhost:5432/ere-control'
make migrate-up

# 3. Сервер (после этапа 1-2)
go run ./cmd/server

Команды Makefile:

Команда Действие
make migrate-up применить миграции
make migrate-down откатить последнюю
make migrate-status показать состояние
make migrate-new name=add_inspections создать новую SQL-миграцию

00002_seed.sql вызывает crypt() и gen_salt() — без pgcrypto миграция упадёт.

Демо-данные (seed)

Логин Пароль Роль
inspector inspector123 inspector
admin admin1234! admin

Борты: RA-73001 (Boeing 737-800), RA-89002 (Sukhoi Superjet 100). Типы: огнетушитель, спасательный жилет, аптечка (со сроком), фонарь (без срока). Оборудования в seed пока нет.

Это только для разработки. На проде seed не применять.

Конфигурация

Планируемые переменные окружения (будут в .env.example; .env — в .gitignore):

APP_PORT=8080
DATABASE_URL=postgres://user:pass@localhost:5432/ere-control
AUTH_TOKEN_SECRET=          # секрет подписи JWT
AUTH_TOKEN_TTL=12h
NOTIFY_PROVIDER=mock        # mock | real
NOTIFY_API_URL=
NOTIFY_API_KEY=
LOG_LEVEL=info

План работ

Этап 1. Миграции и /health

  • Миграция: users, aircraft, equipment_types, equipment, view equipment_v
  • Seed
  • Каркас сервера, подключение к БД (pgx), конфиг из окружения
  • GET /health с пингом БД

Этап 2. Генерация из OpenAPI, авторизация

  • Кодогенерация сервера и типов из api/openapi.json
  • POST /auth/login: проверка bcrypt-хеша, выдача JWT
  • GET /auth/me
  • JWT-middleware и проверка роли admin

Этап 3. Борта, оборудование, метки

  • CRUD бортов (счётчики equipmentCount, problemCount, lastInspectionAt)
  • CRUD типов и оборудования, фильтры
  • GET /tags/{code}

Этап 4. Осмотры (ядро)

  • Миграция: inspections, inspection_scans
  • POST /inspections, GET /inspections, GET /inspections/{id}
  • POST /inspections/{id}/scans с вердиктом по метке
  • POST /inspections/{id}/close с итогом
  • Интеграционные тесты на весь сценарий осмотра (пишутся вместе с кодом)

Этап 5. Заявки

  • Миграция: requests
  • Интерфейс уведомлений + mock-провайдер
  • POST /requests, GET /requests
  • Реальный провайдер внешнего API (по готовности)

Правила работы с репозиторием

  • Ветки: main защищена, работа в feature/<кратко> и fix/<кратко>.
  • Одно изменение — один коммит, стиль сообщений единый.
  • В main только через PR с ревью.
  • Меняется контракт — в том же PR обновляется api/openapi.json и сообщается команде мобилки.
  • Секреты в репозиторий не попадают.