p4n4-docs

ADR-002: Per-Layer Subdirectories in Multi-Layer Projects

Date: 2026-07 Status: Accepted Deciders: raisga core team

Context

p4n4 init --layer iot,ai originally copied every enabled stack’s files into the project root. The stacks collide there:

The stacks are deliberately designed to run as separate Compose projects sharing one external network (see ADR-001), so the scaffolded project has to preserve that.

Decision

Multi-layer projects scaffold each layer into its own subdirectory:

my-project/
├── .p4n4.json          ← manifest at the root, lists all layers
├── iot/                ← docker-compose.yml, config/, scripts/, .env
└── ai/                 ← docker-compose.yml, config/, scripts/, .env

Single-layer projects keep the original flat layout (stack files at the project root). Layout detection is derived, not recorded: a docker-compose.yml at the project root means flat; otherwise each <layer>/docker-compose.yml is a stack directory. The rules live in p4n4_lib.layout so all clients (CLI, API, dashboard) resolve projects the same way.

Consequences for the CLI commands:

Consequences

Positive:

Negative:

Alternatives considered

  1. Merge compose files into one project (COMPOSE_FILE=iot.yml:ai.yml or a root file with include:) — rejected: the conflicting p4n4-net definitions error out, and working around it means rewriting the stacks’ YAML at scaffold time.
  2. Single shared .env at the project root — rejected with the per-directory Compose model: compose only auto-loads the .env next to the compose file, and passing --env-file ../.env everywhere breaks standalone docker compose usage inside a layer directory.

References