Перейти к содержимому

Раскладка проекта

Как типичный проект DWE выглядит на диске: отслеживаемое дерево конфигурации в workspace.yml + workspace/, параллельные оверлеи compose/, runtime-артефакты .dwe/ и стандартные папки для конфигов, томов и снапшотов.

Проект DWE — это любая директория, корень которой содержит workspace.yml. CLI поднимается вверх от текущей рабочей директории, чтобы найти его. Вокруг этого якоря сосуществуют три семейства папок:

  • Отслеживаемое дерево конфигурации в workspace/ и корневые конфигурационные файлы — закоммичены, версионируются, источник истины для структуры проекта.
  • Отслеживаемые runtime-оверлеи — файлы Docker Compose в compose/ и контексты сборки образов (images/<service>/Dockerfile) для сервисов, собираемых из исходников. DWE не генерирует их; они лежат рядом с деревом конфигурации, и на них ссылаются из него. (Рантайм-конфиги сервисов — .env, env.php, … — рендерятся из config-пака шаблонов прямо в hub-каталог каждого сервиса.)
  • Runtime-данные, которые производят DWE и контейнеры — .dwe/ (служебные данные CLI), snapshots/ (распакованное хранилище снапшотов) и backups/ (дампы БД и прочее). Gitignored. Персистентные данные контейнеров живут в именованных томах Docker.
flowchart LR
  Root["project/"]
  RootFiles["workspace.yml<br/>.gitignore · README.md"]

  subgraph workspace["workspace/ — дерево конфигурации (tracked)"]
    direction TB
    WSServices["services/&lt;name&gt;/"]
    WSCommands["commands/"]
    WSTemplates["templates/"]
    WSI18n["i18n/"]
    WSScripts["scripts/"]
    WSPipelines["deploy · lifecycle · reset · info<br/>setup · validate · defaults · local (.yml)"]
  end

  subgraph compose["compose/ — оверлеи (tracked)"]
    direction TB
    CInfra["infra/"]
    CSvc["&lt;service&gt;/ — папка на каждый app-сервис"]
    CTools["tools/"]
  end

  subgraph other["прочее (tracked)"]
    direction TB
    ImagesDir["images/&lt;service&gt;/Dockerfile — сборки образов"]
  end

  subgraph srcdir["services/ — исходники сервисов (gitignored)"]
    direction TB
    SrcHub["&lt;hub&gt;/ — папка на каждый app"]
  end

  subgraph runtime["runtime-данные (gitignored)"]
    direction TB
    DotDir[".dwe/ — state · locks · logs · config"]
    SnapsDir["snapshots/ — распакованные снапшоты"]
    BackupsDir["backups/ — дампы БД и прочее"]
  end

  Root --> RootFiles
  Root --> workspace
  Root --> compose
  Root --> other
  Root --> srcdir
  Root --> runtime

  WSServices --> WSSvcFiles["service.yml — обязателен<br/>deploy.yml · reset.yml — опционально"]
  SrcHub --> SrcHubDetail["src/ — исходники сервиса<br/>… — рабочие папки сборки/runtime"]

Имена папок, отличные от workspace.yml и workspace/, — это конвенции, а не требования. CLI спокойно находит compose/-файлы где угодно — сервисы ссылаются на них относительным путём в service.yml (compose: [compose/web/overlay.yml]). Папки ниже описывают раскладку, к которой приходит большинство проектов; единственные ограничения, которые накладывает CLI, — папка на сервис в workspace/services/ и workspace.yml в корне проекта.

ФайлНазначениеЧитательПисательОтслеживается
workspace.ymlИдентификация проекта: project.name, project.prefixCLI на каждом вызовеАвтор вручнуюда
.gitignoreИсключает .dwe/, /services/, snapshots/, backups/ и workspace/local.yml из контроля версийgitАвтор вручнуюда
README.mdТочка входа в документацию проекта (не README DWE CLI)людиАвтор вручнуюда

Минимальный workspace.yml:

project:
name: my-project
prefix: myprefix

Полный справочник по полям — в workspace.yml.

Всё декларативное в проекте — сервисы, пайплайны, команды, шаблоны, переводы — лежит в workspace/. CLI загружает это дерево на старте; ничто вне него (кроме workspace.yml и compose-файлов, на которые он ссылается) в конфигурации проекта не участвует.

ПутьНазначениеЧитательПисательОтслеживается
workspace/defaults.ymlВерсионированные значения по умолчанию: services.<name>.enabled, runtime, state, exports.env, compose, services.<name>.render.ideCLI (слой merge 2)Автор вручнуюда
workspace/local.ymlПереопределения на разработчика поверх defaults.yml: порты, флаги enabled, креды, ответы мастераCLI (слой merge 3)Автор вручную + setup wizard + dwe services enable/disableнет
workspace/services/<name>/Одна папка на сервис. Имя папки — это ID сервиса, поля name: нет.Загрузчик сервисов CLIАвтор вручнуюда (кроме оверрайдов local.yml)
workspace/commands/Декларативные пользовательские команды, доступные как dwe <name>Реестр команд CLIАвтор вручнуюда
workspace/templates/Template-паки для dwe render — по подкаталогу на вид: config/, ai/, git/, ide/, в каждом <pack>/manifest.yml + файлы (render env пак не использует). Паки config/ рендерят рантайм-конфиги сервисов (.env, …) в hub сервисаRender-пайплайн CLIАвтор вручнуюда
workspace/i18n/Переопределения строк по локалям (<lang>.yml); сливаются со встроенными дефолтамиi18n-стор CLIАвтор вручную + переводчикида
workspace/scripts/Shell-скрипты, на которые ссылаются декларативные команды и пайплайныШаги пайплайна + пользовательские командыАвтор вручнуюда
workspace/deploy.ymlВерхнеуровневый оркестратор пайплайна деплоя. Опционально — у DWE есть встроенный дефолт.Исполнитель deployАвтор вручнуюда
workspace/lifecycle.ymlФазы и хуки run / stop / restartИсполнитель lifecycleАвтор вручнуюда
workspace/reset.ymlПайплайн сброса проектаИсполнитель resetАвтор вручнуюда
workspace/info.ymlЭлементы информационной панели (заголовок, URL, хосты, команды, пользовательские секции)Рендерер dwe infoАвтор вручнуюда
workspace/setup.ymlВопросы мастера настройки (input / confirm / select / multiselect)Workflow setupАвтор вручнуюда
workspace/validate.ymlПроверки готовности проекта (shell / file_exists / tcp_reachable / …)dwe validate + preflightАвтор вручнуюда
workspace/tests/Сценарии интеграционных тестов (<name>.yml), запускаемые на одноразовой копии проектаdwe test / dwe validate testsАвтор вручнуюда
workspace/docker.ymlСлой оркестрации compose: шаблон имени проекта, список файлов, топология, скрытые сервисыПодсистема DockerАвтор вручнуюда
workspace/docker.local.ymlПереопределения compose на разработчика, глубоко смерженные поверх docker.ymlПодсистема DockerАвтор вручнуюнет
workspace/styles.ymlПалитра семантических токенов (accent / success / warning / danger / muted / border / text)UI-стилизацияАвтор вручнуюда

Конфигурация каждого сервиса лежит в workspace/services/<name>/. Имя папки — это канонический ID сервиса; переименование папки переименовывает и сервис. Папка всегда содержит service.yml; опциональные deploy.yml и reset.yml объявляют пайплайны конкретного сервиса, которые оркестратор встраивает в нужной точке в топологическом порядке.

workspace/services/web/
├── service.yml # обязательный: type, container, compose, ports, hosts, configs, dirs
├── deploy.yml # опциональный: пайплайн деплоя сервиса
└── reset.yml # опциональный: пайплайн сброса сервиса

Allowlist полей по типу (какие поля может объявлять type: app / type: tool / type: infra) проверяется строго — см. services/fields.md.

Эти три файла сливаются в одну эффективную конфигурацию:

  1. workspace.yml задаёт структуру (идентификацию проекта, версию схемы).
  2. workspace/defaults.yml заполняет отслеживаемые значения по умолчанию.
  3. workspace/local.yml переопределяет значения на стороне разработчика (gitignored).

Каждый слой опционален; отсутствующие ключи берутся со слоя ниже. Карты портов и хостов сервисов глубоко мержатся по имени записи, так что local.yml может переопределить один порт без перечисления остальных. Детальная модель merge — в workspace.yml.

compose/ содержит файлы Docker Compose, на которые ссылается workspace/services/<name>/service.yml. DWE не генерирует эти файлы и не управляет ими — он собирает их список в runtime и передаёт как docker compose -f a.yml -f b.yml ….

ПутьНазначениеЧитательПисательОтслеживается
compose/infra/Оверлеи для сервисов type: infra (БД, очереди, кэши)Docker Compose через DWEАвтор вручнуюда
compose/<service>/Оверлей конкретного сервиса type: app — папка на каждый appDocker Compose через DWEАвтор вручнуюда
compose/tools/Оверлеи для сервисов type: tool (админ-UI, одноразовые утилиты)Docker Compose через DWEАвтор вручнуюда

Типичный оверлей сервиса объявляет образ контейнера, монтирование из hub-каталога сервиса (куда попадают отрендеренные конфиги) и любое окружение, экспортированное из defaults.yml:

services:
web:
image: nginx:latest
container_name: ${PROJECT}-web
volumes:
- ./services/web/src:/var/www/html
- ./services/web/nginx.conf:/etc/nginx/conf.d/default.conf # отрендерено `dwe render config`
ports:
- "${WEB_HTTP_PORT}:80"

Список compose-файлов также включает workspace/docker.local.yml в самом конце, так что переопределения на разработчика (альтернативные образы, debug-порты, дополнительные тома) накладываются поверх отслеживаемых оверлеев без их редактирования. Полная сборка — в docker.yml и Интеграции с Docker.

Сервисы, собираемые из исходников (а не тянущиеся из реестра), хранят контекст сборки в images/<service>/ с Dockerfile в корне. Compose-оверлей указывает build: на эту папку:

services:
web:
build:
context: ../images/web
container_name: ${PROJECT}-web

images/ отслеживается: Dockerfile и контекст сборки — часть проекта. Имя папки — это имя сервиса, на которое ссылается build.context оверлея.

Рантайм-конфиги (.env, env.php, какой-нибудь nginx.conf, …) рендерятся из config-пака шаблонов под workspace/templates/config/<pack>/ прямо в hub-каталог каждого сервиса, откуда их монтирует compose-оверлей. Секреты, чеканенные сервисом (Laravel APP_KEY, …), харвестятся в gitignore’нутое хранилище .dwe/generated.yml и переигрываются при каждом рендере. Пак авторьте под workspace/templates/config/.

Рядом с деревом конфигурации обычно остаётся одна папка:

ПутьНазначениеЧитательПисательОтслеживается
backups/…Дампы БД и прочее, создаваемые во время разработкиОператор / команды проектаОператор / команды проектанет

backups/ gitignored, потому что содержит сгенерированные дампы, которые различаются от машины к машине. Персистентные данные контейнеров (БД, загрузки, кэши) живут в именованных томах Docker.

Gitignored project-root каталог services/ хранит исходный код сервисов-приложений — он выкачивается/клонируется на каждой машине и никогда не отслеживается репозиторием проекта. Создаётся по требованию (например, шагом деплоя или командой проекта), а не скаффолдингом.

Внутри — по одной папке на приложение (его хаб), которая группирует всё, чем владеет это приложение; в каждом хабе есть как минимум src/ с исходниками сервиса:

services/ # gitignored
└── <hub>/ # папка на каждое приложение
├── src/ # исходники сервиса (свой git-репозиторий / worktree)
└── … # вывод сборки, рабочие папки и т.п.

Чекаут src/ — это обычный вложенный репозиторий, его .gitignore — забота приложения, а не DWE. Compose-оверлеи монтируют отсюда (./services/<hub>/src:/var/www/html), а dwe render git ставит хуки в services/<hub>/src/.git/hooks/. Поскольку всё дерево привязано к корню как /services/ в .gitignore, отслеживаемое дерево workspace/services/ не затрагивается.

Всё, что DWE пишет во время нормальной работы, попадает в .dwe/. Папка gitignored и её безопасно удалить — следующий запуск пайплайна пересоберёт всё, что нужно.

ПутьНазначениеЧитательПисательОтслеживается
.dwe/deploy/state.ymlИдемпотентный журнал деплоя: action_hash, status, started_at, duration по каждому шагуИсполнитель deploy + dwe deploy state showИсполнитель deployнет
.dwe/deploy/deploy.lockЭксклюзивный flock, удерживаемый во время dwe deploy runПодсистема блокировокПодсистема блокировокнет
.dwe/snapshots/snapshot.lockЭксклюзивный flock, удерживаемый во время изменений снапшотовПодсистема блокировокПодсистема блокировокнет
.dwe/snapshots/currentУказатель на активный снапшот, выставляется командами snapshot create и snapshot restore (очищается при snapshot remove)Подсистема снапшотовПодсистема снапшотовнет
.dwe/snapshots/.pre-restore-backup/Резервная копия workspace/local.yml + deploy state перед restore, для ручного восстановленияОператор (вручную)Подсистема снапшотовнет
.dwe/logs/deploy.logОбъединённый stdout/stderr последнего dwe deploy run (пишется по умолчанию; отключается через log: false)Оператор (вручную)Исполнитель deployнет
.dwe/logs/run.log · stop.log · reset.logОбъединённый stdout/stderr соответствующей фазы lifecycle (при log: true)Оператор (вручную)Исполнители lifecycle / resetнет
.dwe/configПереопределение user-config на проект (язык, тема mermaid, условия уведомлений)CLI на каждом вызовеАвтор вручнуюнет

Команды, изменяющие проект, берут deploy.lock до snapshot.lock (алфавитный порядок) и освобождают в обратном. Чтения (docs, status) блокировок не берут. См. Состояние и блокировки.

Файл состояния пишется атомарно после каждого шага. Если деплой прерван, следующий dwe deploy run находит последний известный статус, трактует in-progress шаг как упавший и продолжает с этого места. Устаревшие flock-файлы, оставшиеся после kill -9, распознаются (lock-файл содержит PID держателя; если процесса нет, lock считается устаревшим) и тихо переподбираются.

Минимальный .gitignore для проекта DWE покрывает пути, которыми управляет runtime. Сам runtime никогда не пишет вне этих папок.

.dwe/
/services/
snapshots/
backups/
workspace/local.yml
workspace/docker.local.yml

Всё остальное — workspace.yml, остальная часть workspace/ (включая паки workspace/templates/config/), весь compose/ — отслеживается. Авторы редактируют отслеживаемое дерево; CLI пишет только внутрь gitignored-папок (с одним исключением: setup wizard и dwe services enable/disable дописывают в workspace/local.yml, который и сам gitignored).

  • Начало работы — собрать бинарник, зайти в проект, запустить первый dwe deploy.
  • Архитектура — как устроен сам CLI и что встроено, а что читается с диска.
  • Интеграция с Docker — как собирается список compose-файлов из папок выше.
  • Состояние и блокировки — что записывает .dwe/deploy/state.yml и как блокировки сериализуют изменения.
  • workspace.yml — справочник по полям трёхслойного конфига.
  • services/ — структура папки сервиса и allowlist полей по типу.