- docker-compose.yml: профили docs (Nextcloud), office (ONLYOFFICE Document Server), ai (Ollama + скачивание модели) - автонастройка: адреса Nextcloud, ONLYOFFICE, портала и модели подставляются из .env или по именам сервисов во внутренней сети Docker; значения из интерфейса важнее - локальная модель в своей сети (имя сервиса, частный IP) подключается без ключа API - .env.example, docs/DEPLOY.md (раздел 7а), README
163 lines
24 KiB
Markdown
163 lines
24 KiB
Markdown
# Портал технической службы (чек-листы, наряды, инструмент)
|
||
|
||
FastAPI + SQLAlchemy, веб-интерфейс на чистом JS, JWT-API для будущего Android-приложения.
|
||
Документация API (Swagger): `/docs`.
|
||
|
||
## Модель
|
||
- **Должность** (`technician` / `engineer`) имеет **график** (по дням недели или цикл N/M, дневная/ночная смена).
|
||
**Пользователь** привязывается к должности администратором.
|
||
- **Чек-лист** — список задач; тип ответа: статус (в работе/выполнено), список, число (с границами), текст.
|
||
- **Шаблон наряда** — единожды настроенный наряд + периодичность (каждый день / дни недели / раз в месяц / каждые N дней).
|
||
Планировщик внутри приложения создаёт из него наряды.
|
||
- **Наряд** — копия чек-листа с оборудованием, местом, исполнителем и проверяющим.
|
||
Исполнитель: конкретный человек **или** должность (тогда наряд видят те, кто сейчас на смене; кто первый начал — тот исполнитель).
|
||
Статусы: `new → in_progress → review → completed` (проверяющий может вернуть на доработку), `cancelled`.
|
||
- Права: техник — только свои наряды; инженер — всё про наряды/чек-листы/оборудование + проверка; админ — ещё пользователи, должности, графики.
|
||
|
||
## Документация
|
||
- **[Руководство пользователя (PDF)](docs/user-guide.pdf)** — для техников, инженеров, модераторов и администраторов: скриншоты с пометками, работа без связи, проверка, графики, отчёты, FAQ. Пересборка: [tools/guide](tools/guide/README.md).
|
||
- [docs/DEPLOY.md](docs/DEPLOY.md) — установка на свой сервер (Docker Compose); [docs/API.md](docs/API.md) — описание API для разработчика клиентов; [android/README.md](android/README.md) — сборка приложения.
|
||
|
||
## Роли
|
||
- **Администратор** — всё, включая «Настройки сервера» (каталог фото, лимит размера, контакт push).
|
||
- **Модератор** — панель «Администрирование»: пользователи, должности, графики, чек-листы, оборудование, наряды; не меняет администраторов, не выдаёт права, не видит настройки сервера, сам наряды не выполняет.
|
||
- **Инженер / техник** — по типу должности (см. выше).
|
||
|
||
## Android-приложение
|
||
Нативное приложение (Kotlin + Compose) в каталоге [android/](android/README.md): список и выполнение нарядов, фото с камеры,
|
||
комментарии, проверка для инженеров, **полноценная работа без связи** (накопленное уходит на сервер само), уведомления.
|
||
Распространяется APK-файлом: готовая версия лежит в `release/` и раздаётся по `https://<домен>/app.apk` (ссылка на экране входа);
|
||
новый файл можно положить в `DATA_DIR/apk/` — он важнее.
|
||
|
||
## Мобильная версия в браузере (PWA)
|
||
Запасной вариант, если приложение недоступно (например, iPhone): **`https://<домен>/m`**. Устанавливается на экран «Домой»
|
||
(Android: «Установить приложение»; iPhone: «Поделиться → На экран Домой»), работает **полностью без связи**: наряды и чек-листы
|
||
хранятся в браузере (IndexedDB), ответы, фото, комментарии и сдача копятся в очереди и уходят сами (фото с `Idempotency-Key`,
|
||
ответы пачкой через `/orders/{id}/sync`). Все экраны: список с фильтрами и поиском, чек-лист с крупными кнопками, фото с камеры,
|
||
комментарии, проверка для инженеров, уведомления (Web Push), выход.
|
||
- С телефона на основном адресе предлагается перейти на `/m` (выбор «Остаться» запоминается); на ПК остаётся полная версия.
|
||
- Файлы: `app/static/m/` (m.js, m.css, manifest, иконки); service worker — `app/static/sw.js` (кэш оболочки + push).
|
||
- Ограничения iOS: нет фоновой синхронизации (отправка идёт, пока приложение открыто), push работает только у установленной PWA
|
||
(iOS 16.4+) и только по HTTPS. Данные браузера iOS может очистить, если не открывать сайт долго.
|
||
|
||
## Демонстрационный режим (личный)
|
||
«Администрирование → Демонстрационный режим». Демо включается **только для того, кто его включил**: его запросы идут в отдельную
|
||
SQLite-базу с тестовыми данными (сотрудники, оборудование и краны, чек-листы, наряды и задачи за 14 дней, карты, склады, инциденты),
|
||
остальные пользователи продолжают работать с рабочей базой. Администратор может включить или выключить демо любому сотруднику.
|
||
Тестовые учётные записи (пароль `demo1234`) работают параллельно с рабочими. Приложение для Android и мобильная версия при смене
|
||
режима очищают локальные данные. Подробнее — docs/API.md, раздел «Демонстрационный режим».
|
||
|
||
## Графики и отчёты
|
||
- Графики: по дням недели, простой цикл N через M или **конструктор цикла из шагов** (смена/выходной, любая длительность,
|
||
дневные, ночные и суточные смены, метки «отсыпной» и т. п.) с календарём-предпросмотром на 6 недель.
|
||
- Отчёты → «Выполненные наряды»: машина, чек-лист, кто выполнил, должность, когда. Период (дата+время) обязателен;
|
||
фильтры по машине, должности, исполнителю; экспорт в PDF и CSV. Шрифт DejaVu лежит в `app/fonts` (кириллица в PDF).
|
||
|
||
## Регламентное обслуживание и «Текущее состояние»
|
||
- **Узлы машины.** Карточка машины («Оборудование» → «Узлы и наработка») хранит наработку (моточасы) и список обслуживаемых узлов:
|
||
масло, фильтры, ремни и т. п. Для каждого узла выбирается, как он обслуживается: **по наработке** (каждые N м/ч), **по календарю**
|
||
(раз в N дней / недель / месяцев) или **что наступит раньше**; задаётся порог предупреждения «Скоро» (% от интервала).
|
||
При добавлении указывается, когда и при какой наработке узел обслуживался в последний раз.
|
||
- **Чек-лист «Регламентное обслуживание».** Тип чек-листа в редакторе. В наряд подставляются: показание наработки машины,
|
||
ваши обычные задачи и по пункту «обслужено?» на каждый узел выбранной машины (можно только «Требуется/Скоро»). Оборудование обязательно.
|
||
Когда наряд завершён (после проверки, если она есть), отмеченные узлы сбрасываются, а наработка машины обновляется.
|
||
Работает и в автозапуске (шаблоны нарядов). Android-приложение показывает пункты узлов с остатком и содержит экран «Состояние узлов» (наработка, сброс); мобильная версия — как обычные задачи.
|
||
- **Сброс узла** вручную — если замена или обслуживание выполнены отдельно либо при внештатной ситуации (дата, наработка, комментарий; всё в истории узла).
|
||
Показание счётчика не может уменьшаться, кроме «коррекции» (замена/обнуление счётчика).
|
||
- **Отчёт «Текущее состояние»** (Отчёты): узлы всех машин с состоянием **Требуется / Скоро / В норме**, остатком по наработке и календарю,
|
||
сроком и **прогнозом даты** (по средней наработке в сутки за 30 дней). Фильтры по машине, месту и состоянию; экспорт PDF и CSV.
|
||
- API: `/equipment/{id}/service-units`, `/service-units/{id}[/reset|/events]`, `/equipment/{id}/meter`, `/reports/equipment-state` (см. [docs/API.md](docs/API.md)).
|
||
|
||
## Портал: задания, инциденты, карта, инструмент, сотрудники
|
||
- **Боковое меню** вместо шапок: на компьютере всегда видно, на телефоне (сайт, /m, Android 1.1.0) — по кнопке ☰.
|
||
- **Суточные задания** (`/tasks`): назначен / в работе / приостановлен / выполнен / отменён; для трёх последних комментарий обязателен;
|
||
фото, привязка к машине или узлу. Другим ставят инженер, модератор, админ; техник — себе.
|
||
- **Инциденты** (`/incidents`): авария на машине — описание, затронутые узлы, была ли замена (замена сбрасывает ресурс узла).
|
||
Открытый инцидент — состояние машины «Авария». Сводка состояний: `/equipment-health`.
|
||
- **Иконки оборудования**: встроенный набор `app/static/icons` (генерируется `tools/make_icons.py`) или своё фото.
|
||
- **Карта завода** (`/map`): картинку и расстановку иконок ведёт админ; «!» — авария, жёлтое свечение — скоро/пора ТО.
|
||
**Карта складов** — зоны складов на том же плане (ведёт администратор склада), клик — содержимое склада.
|
||
- **Инструмент и склады** (`/inventory/*`, `/warehouses`): каталог, остатки, выдача лично сотруднику, возврат, перемещение, списание,
|
||
журнал. Роль **«Администратор склада»** (`is_storekeeper`). Сотрудник видит только выданное ему (`/me/inventory`).
|
||
- **Заявки на инструмент** (`/tool-requests`): что купить, зачем, ссылка на товар; статусы и ответ ответственного.
|
||
- **Карточка сотрудника** (`/users/{id}/card`): ФИО, фото, должность, ближайшие смены, «что умею», текущие задания и наряды, инструмент.
|
||
- **Передача задания** (`POST /tasks/{id}/transfer`): исполнитель, поставивший задание или инженер; причина обязательна, видна в истории.
|
||
- **Инциденты извне.** Публичная форма **`/report`** без входа: место → только машины этого места (и вложенных) → описание и контакты
|
||
(обязательно); лимит отправок по адресу, ловушка для ботов, выключается в «Настройках сервера». API для внешних систем:
|
||
`POST /external/incidents` с заголовком `X-API-Key` (машина по id или инвентарному номеру, `external_id` защищает от дублей),
|
||
справочник `GET /external/equipment`; ключи выпускает и отзывает админ в «Настройках сервера» (в БД — только хэш).
|
||
- **История машины** (`GET /equipment/{id}/history`, вкладка в карточке машины): инциденты, обслуживание и замены узлов, наработка,
|
||
наряды, задания; фильтры по типу, периоду и тексту.
|
||
- **Отделы** (`/departments`): вложенность, руководитель; отдел в карточке пользователя, фильтр в «Сотрудниках».
|
||
- **Мастер первичной настройки** (Администрирование → 🧭): графики, должности, отделы, места, оборудование, сотрудники
|
||
(пакетный ввод строками, логины и временные пароли — таблицей для печати), карта, склады и остатки, чек-листы, внешние обращения, копии.
|
||
- **Резервные копии** (Администрирование → «Резервные копии», `/backups`): база в переносимом формате + конфигурация (+ фото по желанию),
|
||
автокопии по расписанию, скачивание, загрузка, восстановление.
|
||
- **AI-помощник** (включается в «Настройках сервера»: провайдер, адрес, модель, ключ): кнопка в правом нижнем углу на всех
|
||
экранах; отвечает только о работе в портале, учитывает права пользователя и читает данные только от его имени.
|
||
- **Отчёт «Выполнение работ»** (`/reports/execution`): % выполнения суточных осмотров, чек-листов, ТО и заданий по машинам, отклонения; PDF/CSV.
|
||
|
||
## Комментарии, фото, уведомления
|
||
- Комментарии к наряду видят все, кто видит наряд; участникам (исполнитель, проверяющий, назначенный) уходит уведомление.
|
||
- Фото: у пункта чек-листа режим «без фото / по желанию / обязательно». Браузер уменьшает снимок до 1600 px. Файлы лежат в каталоге из настроек (по умолчанию `data/photos`, в Docker — `./photos` на хосте), в БД — только путь. API: `POST /api/orders/{id}/items/{item_id}/photos` (тело — сам файл, `Content-Type: image/jpeg|png|webp`), `GET /api/photos/{id}` (с токеном).
|
||
- Уведомления — Web Push: кнопка «🔔» в шапке. Нужен **HTTPS** (через Nginx Proxy Manager подойдёт). Приходят при назначении наряда (человеку или тем, кто в этот момент на смене в должности), на проверку, при возврате и при комментариях.
|
||
|
||
## API
|
||
Версионированный REST: `/api/v1`, Swagger на `/docs`. Короткий access-токен + refresh с ротацией, пакетная офлайн-синхронизация
|
||
(`POST /orders/{id}/sync`), курсор `updated_since`, идемпотентная загрузка фото, FCM для Android.
|
||
**Полное описание для разработчика приложения: [docs/API.md](docs/API.md).**
|
||
Переменные: `ACCESS_TTL_MIN` (60), `REFRESH_TTL_DAYS` (90), `LOGIN_MAX_FAILS` (5), `LOGIN_WINDOW_SEC` (300).
|
||
|
||
## Локальный запуск
|
||
```
|
||
python -m venv .venv && .venv\Scripts\pip install -r requirements.txt
|
||
.venv\Scripts\python -m uvicorn app.main:app --reload
|
||
```
|
||
Вход: `admin` / `admin` (создаётся при первом старте, **смените**). Тесты: `pytest tests`.
|
||
|
||
## Требования к серверу
|
||
Оценка по устройству портала (одно приложение на Python + PostgreSQL в Docker), нагрузочных замеров не было.
|
||
|
||
| | Минимум (до 20–30 сотрудников) | Рекомендуется (до 100–150 сотрудников, с запасом) |
|
||
|---|---|---|
|
||
| Процессор | 1 ядро (x86-64 или ARM64) | 2 ядра |
|
||
| Память | 2 ГБ (с 1 ГБ работает, но первая сборка образа может не пройти без файла подкачки) | 4 ГБ |
|
||
| Диск | 10 ГБ: система, Docker, образ ~1 ГБ, база, резервные копии | 40 ГБ |
|
||
| ОС | Linux (Debian 12/13, Ubuntu 22.04/24.04), Docker 24+ с Compose v2 | — |
|
||
|
||
- **Фото — главный расход места.** Приложение их сжимает, ориентир 0,3–0,5 МБ на снимок: при 50 фото в день — 6–9 ГБ в год,
|
||
и ещё столько же, если резервные копии делаются с фото.
|
||
- **Нужны домен и HTTPS** (обратный прокси): без них не работают уведомления, мобильная версия на iPhone и релизное приложение для Android.
|
||
- **Интернет** серверу нужен только для уведомлений Android (Firebase) и AI-помощника, если он включён; остальное работает в локальной сети.
|
||
- Тяжелее всего для процессора PDF-отчёты и анализ надёжности — секунды на запрос, не постоянная нагрузка.
|
||
|
||
Пошаговая установка — [docs/DEPLOY.md](docs/DEPLOY.md).
|
||
|
||
## Дополнительные сервисы
|
||
Рядом с порталом `docker-compose.yml` может поднять **Nextcloud** (документация оборудования), **ONLYOFFICE** (просмотр
|
||
Word/Excel/PowerPoint в портале) и **Ollama** (локальная модель для AI-помощника) — профилями `docs`, `office`, `ai`
|
||
(`COMPOSE_PROFILES=docs,office,ai` в `.env`). Портал сам находит их во внутренней сети Docker и заполняет адреса в настройках.
|
||
Подробно — [docs/DEPLOY.md](docs/DEPLOY.md), раздел 7а.
|
||
|
||
## Установка без Coolify (Docker Compose)
|
||
Пошаговая инструкция для любого Linux-сервера с Docker: **[docs/DEPLOY.md](docs/DEPLOY.md)** (шаблон настроек — `.env.example`).
|
||
Коротко: `cp .env.example .env` → заполнить → `docker compose up -d --build` → обратный прокси с HTTPS на `APP_PORT`.
|
||
|
||
## Деплой (Coolify + Nginx Proxy Manager)
|
||
Приложение разворачивается из `docker-compose.yml` (сервис приложения + PostgreSQL, тома `pgdata`, `photos`, `appdata`).
|
||
1. В Coolify: Project → New → Application из Git-репозитория, **Build Pack = Docker Compose**, файл `docker-compose.yml`.
|
||
2. Переменные окружения (Coolify → Environment Variables): `DB_PASSWORD`, `SECRET_KEY` (случайная строка), `ADMIN_PASSWORD`
|
||
(пароль администратора `admin`, применяется при первом старте), `FORWARDED_ALLOW_IPS` (**IP вашего NPM**, например `192.168.1.10`),
|
||
при желании `APP_TZ` (по умолчанию Europe/Moscow) и `APP_PORT` (порт хоста, по умолчанию **8080**).
|
||
В боевом режиме (`APP_ENV=production`, уже прописан в compose) приложение **не запустится**, если `SECRET_KEY` короче 32 символов
|
||
или пуст, а `ADMIN_PASSWORD` слабее 10 символов (проверяется при первом создании администратора). Пароли пользователей — от 10 символов.
|
||
3. Домен в Coolify не задаётся: прокси — NPM. Proxy Host → Forward `http://<IP сервера Coolify>:8080`, SSL (Let's Encrypt),
|
||
Force SSL. **В Advanced добавьте `client_max_body_size 20m;`** (иначе фото больше 1 МБ вернут 413).
|
||
Порт приложения обязательно закройте файрволом для всех, кроме адреса NPM, а в `FORWARDED_ALLOW_IPS` укажите этот адрес: только от него
|
||
принимаются заголовки `X-Forwarded-For`. Проверка: «Администрирование → Настройки сервера» показывает адрес клиента, каким его видит сервер.
|
||
4. Запуск строго в **одном процессе** (так и настроено): планировщик нарядов и демо-режим живут внутри процесса.
|
||
5. APK: готовый подписанный файл лежит в репозитории (`release/`) и входит в образ, поэтому ссылка «Скачать приложение для
|
||
Android» на экране входа и адрес `/app.apk` работают сразу после деплоя. Новую версию можно выложить без передеплоя: положить
|
||
файл в том `appdata` по пути `apk/` (он важнее файла из образа): `docker cp checklists.apk <контейнер приложения>:/srv/data/apk/`.
|
||
6. Резервные копии: `pg_dump` базы по расписанию + тома `photos` и `appdata`.
|