architect/prospective/operation-platform.md

type: standard
title: "Эксплуатация платформы"
status: active
version: 1.0.0
date: 2026-04-10
knowledge_level: У1


Эксплуатация платформы

Объединённый стандарт эксплуатации: мониторинг, деплой, Docker/Drupal, очистка, создание проектов, оценка времени.


1. МОНИТОРИНГ

Принцип

СНАЧАЛА найти причину, ПОТОМ чистить.

Резкий рост диска (>5% в час) — симптом проблемы: утечка логов, зацикленный процесс, атака. Очистка без устранения причины — борьба с симптомами.

Классификация роста

Скорость роста Классификация Действия
< 5% в час Нормальный L0 автоочистка при 90%, L1 меню при 95%
5-10% в час Быстрый АЛЕРТ "НАЙДИ ПРИЧИНУ" + топ-5 директорий
> 10% в час Критический АЛЕРТ "СРОЧНО НАЙДИ ПРИЧИНУ" + детальный анализ

Алгоритм monitor

Каждые 30 минут:

1. Проверить текущий % диска
2. Записать в disk_history.json
3. Вычислить рост за последний час

4. IF рост >= 10% в час:
     → КРИТИЧЕСКИЙ АЛЕРТ аномального роста
     → Показать топ-5 директорий
     → Показать активные логи (изменены за 24ч)
     → Показать большие файлы >50MB
     → НЕ предлагать очистку (сначала причину)

5. ELSE IF рост >= 5% в час:
     → АЛЕРТ быстрого роста
     → Показать топ-5 директорий
     → Рекомендовать проверить вручную

6. ELSE IF диск >= 98%:
     → КРИТИЧЕСКИЙ алерт (нужна L2 через SSH)

7. ELSE IF диск >= 95%:
     → L1 меню очистки (интерактивное)

8. ELSE IF диск >= 90%:
     → L0 автоочистка (БЕЗ уведомления если успешно)

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

# system/monitor/config.yaml
infra:
  disk:
    warning: 80
    critical: 90
    emergency: 98
    auto_cleanup: true
    auto_cleanup_level: L0
    auto_cleanup_confirm_L1: false

Диагностические функции

from commands.diagnostics import detect_anomalous_growth

result = detect_anomalous_growth()
# {"is_anomalous": True, "growth_per_hour": 7.5, "current_percent": 93, "severity": "fast"}
from commands.diagnostics import find_large_directories
dirs = find_large_directories(limit=10)

from commands.diagnostics import find_large_files
files = find_large_files(min_size_mb=50, limit=20)

from commands.diagnostics import get_recent_log_growth
logs = get_recent_log_growth()

from commands.diagnostics import suggest_cleanup_targets
suggestions = suggest_cleanup_targets()

История диска

Файл: system/monitor/output/disk_history.json

[
  {"time": "2025-12-30T14:00:00", "percent": 85},
  {"time": "2025-12-30T14:30:00", "percent": 87}
]

Ротация: последние 24 часа.

Формат алерта аномального роста

КРИТИЧЕСКИЙ РОСТ ДИСКА

Рост: +12.5% за последний час
Текущий: 93%

СНАЧАЛА НАЙДИ ПРИЧИНУ

Топ-5 директорий:
  /var/lib/docker: 12.5G
  /var/log: 3.2G
  /tmp: 1.8G

Активные логи (изменены за 24ч):
  /var/log/nginx/access.log: 2.1G

Проверить вручную:
du -sh /var/lib/docker /var/log /tmp /opt | sort -h

Профилактика

# Ротация логов: /etc/logrotate.d/nginx
/var/log/nginx/*.log {
    daily
    rotate 7
    compress
    delaycompress
    missingok
    notifempty
}

# Docker автоочистка (еженедельно в cron)
0 2 * * 0 docker image prune -a -f --filter "until=168h"

# Мониторинг конкретных путей
# Алерт если /var/log >5GB или /var/lib/docker >20GB

Примеры диагностики

# Активные логи
find /var/log -type f -mtime -1 -size +10M -exec du -h {} \;

# Docker образы
docker images | wc -l
docker system df

# Большие файлы в /tmp
find /tmp -type f -size +50M -exec du -h {} \;

# БД дампы
find /var/backups -name "*.sql.gz" -exec du -h {} \;

Диагностика перед очисткой

# Что занимает место (top 20)
du -sh /* 2>/dev/null | sort -h | tail -20
du -sh /var/* 2>/dev/null | sort -h | tail -20

# Docker размеры
docker system df

# Claude
du -sh ~/.claude/*

2. ДЕПЛОЙ СЕРВИСОВ

Правило размещения

/etc/systemd/system/   ← ТОЛЬКО системное (OS-уровень)
Docker compose         ← ВСЕ проектные и платформенные сервисы
system/scheduler/      ← ВСЕ расписания (не cron напрямую)

ЗАПРЕЩЕНО создавать .service файлы в /etc/systemd/system/ для проектных сервисов.

Что куда

Категория Где Примеры
OS-уровень systemd nginx, docker, hub-mount, infra-mount, fail2ban
Платформа Docker md-viewer, file-share
Проекты Docker erp, pro1, filemanager, n8n, nocodb
Боты Docker telegram-vip, любые боты
Расписания scheduler python3 system/scheduler/run.py --list

Структура сервиса в проекте

projects/org/{project}/app/{service}/
├── solution/              ← код
├── infrastructure/
│   ├── Dockerfile         ← как собрать образ
│   ├── docker-compose.yml ← как запустить
│   └── .env.example       ← переменные окружения (без секретов)
└── CLAUDE.md

Конфиг рядом с кодом — переехал проект, конфиг переехал.

Шаблон Dockerfile (Python/FastAPI/Flask)

FROM python:3.10-slim

WORKDIR /app

COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

COPY . .

EXPOSE 8000

CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000"]

Шаблон docker-compose.yml

services:
  app:
    build: ../solution
    container_name: {project}-{service}
    restart: always
    ports:
      - "8000:8000"
    volumes:
      - ../solution:/app
      - /mnt/beget-s3:/data:ro
    env_file:
      - ../solution/.env
    networks:
      - {project}-network

networks:
  {project}-network:
    driver: bridge

Миграция systemd-сервиса в Docker

# 1. Создать Dockerfile + docker-compose.yml в infrastructure/
# 2. Проверить запуск
docker compose -f infrastructure/docker-compose.yml up -d

# 3. Убедиться что работает
curl http://localhost:{port}/

# 4. Остановить и отключить systemd
systemctl stop {service}
systemctl disable {service}

# 5. Удалить unit-файл
rm /etc/systemd/system/{service}.service
systemctl daemon-reload

3. DOCKER И DRUPAL

Структура официального образа

Образ drupal:11.3-php8.3-apache основан на drupal/recommended-project.

/opt/drupal/           PROJECT ROOT (composer, vendor, drush)
├── composer.json
├── composer.lock
├── vendor/
   └── bin/
       └── drush      правильный путь к drush
├── config/
   └── sync/
└── web/               WEB ROOT (Apache DocumentRoot)
    ├── core/
    ├── modules/
    └── sites/
        └── default/
            ├── settings.php
            └── files/

/var/www/html  /opt/drupal/web   (симлинк)

Критично: /var/www/html — это симлинк на web root, не project root.

Drush: правила

# ПРАВИЛЬНО — устанавливать в project root
cd /opt/drupal && composer require drush/drush

# НЕПРАВИЛЬНО — устанавливает в web root (не работает)
cd /var/www/html && composer require drush/drush

# ПРАВИЛЬНО — запуск
/opt/drupal/vendor/bin/drush --root=/opt/drupal/web status

Dockerfile шаблон

FROM drupal:11.3-php8.3-apache

RUN cd /opt/drupal && composer require drush/drush --no-interaction 2>&1 | tail -3
RUN chown -R www-data:www-data /opt/drupal/vendor

Права на папки

# Обязательно при первом запуске
chown -R www-data:www-data /opt/drupal/web/sites/default/files
chown www-data:www-data /opt/drupal/web/sites/default/settings.php
chown -R www-data:www-data /opt/drupal/web/modules/custom
chown -R www-data:www-data /opt/drupal/web/themes/custom

settings.php

volumes:
  # rw — обязательно, Drupal пишет hash_salt и config_sync_directory
  - ./drupal/settings.php:/var/www/html/sites/default/settings.php:rw

Никогда :ro — Drupal не сможет завершить установку.

После drush site:install добавить:

// Разрешить доступ с любого хоста (dev)
$settings['trusted_host_patterns'] = ['^.*$'];

// Или для конкретных доменов (prod)
$settings['trusted_host_patterns'] = [
  '^lideravto\.aipd\.ru$',
  '^new\.lideravto\.ru$',
];

Docker Compose паттерн

services:
  app:
    build: .
    volumes:
      - drupal-files:/var/www/html/sites/default/files
      - ./drupal/settings.php:/var/www/html/sites/default/settings.php:rw
      - ./drupal/modules:/var/www/html/modules/custom:rw
      - ./drupal/themes:/var/www/html/themes/custom:rw
    environment:
      DRUPAL_DATABASE_HOST: db
      DRUPAL_DATABASE_NAME: ${MYSQL_DATABASE}
      DRUPAL_DATABASE_USERNAME: ${MYSQL_USER}
      DRUPAL_DATABASE_PASSWORD: ${MYSQL_PASSWORD}
    depends_on:
      db:
        condition: service_healthy

  db:
    image: mysql:8.4
    healthcheck:
      test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
      interval: 10s
      retries: 10

Entrypoint — авто-установка

#!/bin/bash
set -e

DRUSH=/opt/drupal/vendor/bin/drush
ROOT=/opt/drupal/web

if ! $DRUSH --root=$ROOT status --field=bootstrap 2>/dev/null | grep -q "Successful"; then
    echo "[entrypoint] Installing Drupal..."

    $DRUSH --root=$ROOT site:install standard \
        --db-url="mysql://${DRUPAL_DATABASE_USERNAME}:${DRUPAL_DATABASE_PASSWORD}@${DRUPAL_DATABASE_HOST}:3306/${DRUPAL_DATABASE_NAME}" \
        --site-name="${DRUPAL_SITE_NAME:-Drupal}" \
        --account-name=admin \
        --account-pass="${DRUPAL_ADMIN_PASS:-Admin2026!}" \
        --locale=ru \
        --yes

    echo "[entrypoint] Drupal installed successfully"
fi

exec "$@"

Drush шпаргалка

# Статус
docker exec -u www-data app /opt/drupal/vendor/bin/drush --root=/opt/drupal/web status

# Сбросить кеш
docker exec -u www-data app /opt/drupal/vendor/bin/drush --root=/opt/drupal/web cr

# Включить модуль
docker exec -u www-data app /opt/drupal/vendor/bin/drush --root=/opt/drupal/web en module_name -y

# Сменить пароль admin
docker exec -u www-data app /opt/drupal/vendor/bin/drush --root=/opt/drupal/web user:password admin "NewPass123"

# Установить модуль через composer
docker exec app bash -c "cd /opt/drupal && composer require drupal/module_name"

Диагностика Drupal/Docker

Симптом Причина Решение
Сайт показывает install.php БД пустая Запустить entrypoint / drush site:install
sites/default/files не writable root:root chown -R www-data:www-data ...files
settings.php не пишется mount :ro Изменить на :rw, пересоздать контейнер
drush: command not found Drush в web root cd /opt/drupal && composer require drush/drush
trusted_host_patterns error Домен не в списке Добавить в settings.php

4. ОЧИСТКА И ДИСК-АУДИТ

Три уровня очистки

L0 → Автоматическая (monitor при disk >= 90%)
L1 → С подтверждением (вручную или при disk >= 95%)
L2 → Только вручную (критическая ситуация)

L0 — Безопасная очистка

Освобождает: 100-500 MB. Не влияет на сервисы, не требует перезапуска.

Категория Команда
/tmp (>7 дней) find /tmp -type f -mtime +7 -delete
APT кэш apt-get clean
PIP кэш rm -rf ~/.cache/pip/*
NPM кэш npm cache clean --force
Docker dangling docker image prune -f
Docker volumes dangling docker volume prune -f
Journald journalctl --vacuum-size=500M
Логи ротированные (>7 дней) find /var/log -name "*.gz" -mtime +7 -delete
Claude логи (>7 дней) find .logs -name "*.log" -mtime +7 -delete
Claude temp (>3 дня) find /tmp -name "claude-*" -mtime +3 -delete

Скрипт: infra/scripts/cleanup-L0.sh

#!/bin/bash
echo "=== L0: Безопасная очистка ==="
find /tmp -type f -mtime +7 -delete 2>/dev/null
apt-get clean -y >/dev/null 2>&1
rm -rf ~/.cache/pip/* 2>/dev/null
docker image prune -f >/dev/null 2>&1
docker volume prune -f >/dev/null 2>&1
journalctl --vacuum-size=500M >/dev/null 2>&1
find /var/log -name "*.gz" -mtime +7 -delete 2>/dev/null
find /var/log -name "*.1" -mtime +7 -exec truncate -s 0 {} \; 2>/dev/null
find $WORKSPACE/.logs -name "*.log" -mtime +7 -delete 2>/dev/null
find /tmp -name "claude-*" -mtime +3 -delete 2>/dev/null
df -h / | tail -1

L1 — Средняя очистка

Освобождает: 3-8 GB. Требует подтверждения.

Категория Риск
Docker images (все неиспользуемые) Потребуется pull
Snap packages Только если не используется
Старые бэкапы (>30 дней) Потеря старых версий
venv неактивных проектов (>60 дней) Потребуется rebuild
node_modules неактивных (>60 дней) Потребуется npm install
Claude history (>60 дней) Потеря старых сессий
Git gc Сжатие репозитория
Активные логи >100M Потеря истории

Скрипт: infra/scripts/cleanup-L1.sh

#!/bin/bash
echo "=== L1: Средняя очистка ==="
read -p "Продолжить? (yes/no): " confirm
[ "$confirm" != "yes" ] && exit 1

docker system prune -a --volumes -f
find $INFRA/backups -type f -mtime +30 -delete 2>/dev/null
find $WORKSPACE/projects -name "venv" -type d -mtime +60 -exec rm -rf {} \; 2>/dev/null
find $WORKSPACE -name "node_modules" -type d -mtime +60 -exec rm -rf {} \; 2>/dev/null
find ~/.claude/projects -name "*.jsonl" -mtime +60 -exec gzip {} \; 2>/dev/null
cd $WORKSPACE && git gc --aggressive >/dev/null 2>&1
find /var/log -name "*.log" -size +100M -exec truncate -s 50M {} \; 2>/dev/null
df -h / | tail -1

L2 — Опасная очистка

Освобождает: 10-20 GB. Удаляет production данные. Только через SSH.

Категория Риск
Docker volumes (используемые) Потеря данных
БД дампы Потеря recovery точек
Архивы проектов Потеря истории
Claude сессии (все) Потеря всех сессий
Git objects (агрессивно) Потеря истории

Скрипт: infra/scripts/cleanup-L2.sh (подтверждение: DELETE ALL DATA)

Автоматическая очистка (Monitor)

if disk >= 98%:
     Алерт критический
     НЕ запускать автоочистку (слишком опасно)
     Требовать ручное вмешательство

elif disk >= 95%:
     Запустить L0
     Если не помогло  алерт с предложением L1

elif disk >= 90%:
     Запустить L0
     Если помогло  ОК
     Если не помогло  алерт с рекомендацией L1

Ручной запуск

bash infra/scripts/cleanup-L0.sh    # безопасная (в любое время)
bash infra/scripts/cleanup-L1.sh    # средняя (с подтверждением)
bash infra/scripts/cleanup-L2.sh    # опасная (только критическая ситуация)

Автоматизация rclone

# Добавить в system/monitor/auto_cleanup.sh
RCLONE_SIZE=$(du -sm /tmp/rclone 2>/dev/null | cut -f1)
if [ "$RCLONE_SIZE" -gt 300 ]; then
    rm -rf /tmp/rclone
    log "Очищен rclone кэш: ${RCLONE_SIZE}MB"
fi

find /tmp -type f -mtime +7 -delete 2>/dev/null

5. СОЗДАНИЕ ПРОЕКТОВ

Концепция

Автоматизированная система создания новых проектов: единообразная структура, валидация, переменные вместо хардкода, синхронизация workspace/dataspace.

Переменные платформы

Файл: system/config/platform-vars.sh

export WORKSPACE=/opt/claude-workspace
export DATASPACE=/mnt/beget-s3
export INFRA=/mnt/beget-infra
export PROJECTS_NAMESPACE="projects/org"

project_ws() { echo "$WORKSPACE/$PROJECTS_NAMESPACE/$1"; }
project_data() { echo "$DATASPACE/$PROJECTS_NAMESPACE/$1"; }
project_infra() { echo "$INFRA/$PROJECTS_NAMESPACE/$1"; }

Правила

ЗАПРЕЩЕНО:

cd /opt/claude-workspace/projects/org/myproject  # хардкод

ПРАВИЛЬНО:

source $WORKSPACE/system/config/platform-vars.sh
cd $(project_ws myproject)

Зеркальность workspace и dataspace

$WORKSPACE/projects/org/{name}/    $DATASPACE/projects/org/{name}/
├── CLAUDE.md                      ├── prices/
├── PROJECT.md                     ├── images/
├── config/                        ├── exports/
└── services/                      └── _inbox/

Процесс создания

# Интерактивный режим
create-project

# Прямое создание
create-project myproject --type=commercial --nocodb

Шаги:

  1. Валидация имени (только a-z0-9-_)
  2. Проверка что проект не существует
  3. Создание структуры в workspace (из шаблона)
  4. Создание структуры в dataspace (prices/, images/, exports/, _inbox/)
  5. Инициализация git
  6. Создание базы NocoDB (опционально)
  7. Валидация результата

Типы проектов

Шаблон Файл
Коммерческий architect/templates/PROJECT_COMMERCIAL.md
Внутренний architect/templates/PROJECT_INTERNAL.md
Исследовательский architect/templates/PROJECT_RESEARCH.md
Платформа architect/templates/PROJECT_PLATFORM.md

Валидация

Файл: system/scripts/validate-platform.sh

# Проверить конкретный проект
validate-platform myproject

# Проверить все проекты
validate-platform

Проверки:
- Соответствие workspace/dataspace
- Наличие обязательных файлов (CLAUDE.md, PROJECT.md)
- Отсутствие хардкодов
- Отсутствие больших файлов в workspace (>10MB)
- Соответствие стандартам именования

Правила работы

  1. Данные только в dataspace — изображения, xlsx, pdf, видео, архивы >10MB
  2. Credentials отдельно.credentials.md в .gitignore, не в git
  3. Валидация обязательна — перед коммитом проверить хардкоды и размер файлов
  4. Атомарность — создание проекта = транзакция (всё или откат)

Автоматизация

# system/scheduler/schedule.yaml
validate_platform:
  description: "Ежедневная валидация платформы"
  command: "bash system/scripts/validate-platform.sh"
  cron: "0 4 * * *"
  enabled: true

Pre-commit hook

#!/bin/bash
# Проверка хардкодов
if git diff --cached | grep -E "/opt/claude-workspace|/mnt/beget-s3"; then
    echo "Найдены хардкоды! Используйте переменные."
    exit 1
fi

# Проверка больших файлов
for file in $(git diff --cached --name-only); do
    if [ -f "$file" ]; then
        size=$(stat -c%s "$file" 2>/dev/null)
        if [ "$size" -gt 10485760 ]; then
            echo "Файл $file слишком большой ($(($size/1024/1024))MB)"
            echo "Переместите в dataspace!"
            exit 1
        fi
    fi
done

6. ОЦЕНКА ВРЕМЕНИ

Проблема

AI завышает оценки в 10-20 раз, думая как человек-разработчик.

Пишу Реально Ошибка
"1-2 дня" 30-60 минут x20
"3-5 дней" 2-4 часа x10
"2-3 часа" 15-30 минут x5

Формула

AI_time = Human_time / Коэффициент

Коэффициенты:
- Механический код (CRUD, шаблоны, CSS): x10
- Логика + код (views, hooks, API): x6-8
- Исследование + код (новая библиотека): x3-4
- Только исследование/анализ: x2

Матрица реального времени

Типовые задачи Drupal:

Задача Human AI Коэф.
Создать content type 30 мин 3 мин x10
Создать view 1 час 10 мин x6
Портировать CSS 2 часа 10-15 мин x10
Написать PHP hook 1 час 10 мин x6

Комплексные задачи:

Задача Human AI
Мигрировать footer на блоки 1 день 30-45 мин
Создать hero slider (View) 3 часа 20-30 мин
Полная миграция hardcoded->blocks 2-3 дня 2-4 часа
Создать новую тему с нуля 1 неделя 6-8 часов

Backend задачи:

Задача Human AI Коэф.
REST API endpoint 2 часа 15 мин x8
Database migration 1 час 10 мин x6
Написать тесты (10 кейсов) 3 часа 30 мин x6
Интеграция с API (OZON) 1 день 2-3 часа x3

Правила оценки

  1. Указывать МИНУТЫ для задач < 2 часов
  2. Декомпозировать на подзадачи с оценкой каждой
  3. Учитывать параллельность независимых задач
  4. Не добавлять буфер "на всякий случай"
  5. Разделять оценку и риски

Формат оценки

Оценка: 30-45 минут
Включает: создание блоков (10 мин), шаблоны (15 мин), стили (10 мин), деплой (5 мин)

Риски:
- Если Drupal кеш не очистится: +5 мин
- Если нужно дебажить CSS конфликты: +15 мин

Формат отчёта

ВЫПОЛНЕНО за 35 минут:
  Создано 4 menu blocks
  Обновлён footer.html.twig
  Портированы стили footer.css

ОТКЛОНЕНИЕ: -10 мин (оценка была 45 мин)

Когда оценка может быть больше

Чеклист перед оценкой

[ ] Учёл ли я что работаю как AI, а не человек?
[ ] Разделил ли задачу на подзадачи?
[ ] Указал ли время в минутах для задач < 2 часов?
[ ] Учёл ли параллельность независимых задач?
[ ] Не добавил ли "буфер на всякий случай"?

Источники

Объединены из:
- operation-monitoring.md — мониторинг роста диска
- operation-services-deployment.md — деплой сервисов
- operation-drupal-docker.md — Drupal в Docker
- operation-cleanup.md — уровни очистки диска
- operation-disk-audit.md — аудит диска
- operation-project-creation-system.md — система создания проектов
- operation-time-estimation.md — оценка времени для AI