Local Teardown
Plan: dapsman local teardown
Section titled “Plan: dapsman local teardown”Context
Section titled “Context”dapsman local build brings up the local dev Docker environment for a project: it composes containers, syncs caddy site files, and runs prerequisites. Until now there is no workflow to cleanly reverse this. The immediate need that surfaced this: if a dapsman init produces a broken project (e.g. the _docker/_secrets bug), re-running init leaves stale Docker volumes behind. When the fixed project is built, MySQL finds an existing data volume and ignores the new secret files — leading to “access denied” errors with no obvious cause.
dapsman local teardown closes this loop. It is the local counterpart to dapsman prod teardown.
Command
Section titled “Command”dapsman local teardown --project <name> [--dry-run] [--config <path>]--project <name>— required (destructive operation; exactly one project)--dry-run— print plan and skip execution--config <path>— override daps.yaml path
Requires a confirmation prompt (“Type ‘yes’ to confirm”) before executing, like prod teardown.
-
Stop containers and delete volumes
- Run
docker compose -f {base} [-f {dev}] down -von the workstation -vremoves named volumes (e.g.loccom_loccom-mysql-data) so they cannot cause stale-state issues on the next build- Use the same compose files as
local build: base (compose_{project}.yaml) + dev overlay (compose_{project}.dev.yaml) if present; resolved viaProjectDockerDefinition - Tolerates compose failure with
|| true(containers may already be stopped)
- Run
-
Delete caddy site files
- Delete each
*.dev.caddyfile that was copied into{dapsRoot}/caddy_sites/for this project - The set of files to delete comes from
ProjectCaddyDefinition.WorkstationLocalSiteFilePaths, mapped to their destination filenames in{dapsRoot}/caddy_sites/
- Delete each
-
Reload Caddy
- Run
docker exec daps-caddy-1 caddy reload --config /etc/caddy/Caddyfileon the workstation - Removes the project’s site from the running Caddy config
- Tolerates failure if Caddy is not running
- Run
-
Delete project folder
- Delete the project directory (
project.Definition.Path) and all its contents - This is what makes the confirmation prompt important
- Delete the project directory (
C# Changes
Section titled “C# Changes”New domain types
Section titled “New domain types”src/Dapsman.Domain/LocalTeardownPlan.cs
public sealed class LocalTeardownPlan{ public required string ProjectName { get; init; } public required string ProjectPath { get; init; } public required IReadOnlyList<string> ComposeFiles { get; init; } // base + dev overlay public required IReadOnlyList<string> CaddySiteFilesToDelete { get; init; } // abs paths in dapsRoot/caddy_sites/ public required string CaddyContainerName { get; init; } public required string CaddyConfigPath { get; init; }}src/Dapsman.Application/LocalTeardownOptions.cs
public sealed class LocalTeardownOptions{ public string? ProjectName { get; init; }}Application layer
Section titled “Application layer”src/Dapsman.Application/Interfaces.cs — add:
public interface ILocalTeardownPlanBuilder{ LocalTeardownPlan BuildPlan(DapsConfig config, LocalTeardownOptions options);}
public interface ILocalTeardownExecutor{ void Execute(LocalTeardownPlan plan);}src/Dapsman.Application/LocalTeardownService.cs (new, follows TeardownService pattern)
public sealed class LocalTeardownService( ILocalTeardownPlanBuilder planBuilder, ILocalTeardownExecutor executor){ public LocalTeardownPlan CreatePlan(DapsConfig config, LocalTeardownOptions options); public void Execute(LocalTeardownPlan plan);}Infrastructure
Section titled “Infrastructure”src/Dapsman.Infrastructure/ConventionLocalTeardownPlanBuilder.cs (new)
- Resolves project via
IProjectResolver - Resolves compose files via
IDockerResolver.ResolveForProject(project)— usesProjectDockerDefinition.WorkstationBaseComposeFilePathandWorkstationDevComposeFilePath(same files local build uses) - Resolves caddy site files to delete via
ICaddyResolver.ResolveForProject(project)— mapsWorkstationLocalSiteFilePathsbasenames to{dapsRoot}/caddy_sites/ - Resolves caddy container name + config path via
ICaddyResolver.Resolve()
src/Dapsman.Infrastructure/WorkstationLocalTeardownExecutor.cs (new)
- Injects
IBashRunner _workstationBashRunnerandICaddyRestarter _caddyRestarter(or inline the reload) - Step 1: builds compose file flags string from plan; calls
_workstationBashRunner.RunShell($"docker compose {flags} down -v || true", workingDirectory) - Step 2: deletes each file in
plan.CaddySiteFilesToDeleteviaFile.Delete(no-op if missing) - Step 3: reloads Caddy —
_workstationBashRunner.RunShell($"docker exec {plan.CaddyContainerName} caddy reload --config {plan.CaddyConfigPath}", workingDirectory)— wrapped in try/catch to tolerate Caddy not running - Step 4: deletes project folder via
Directory.Delete(plan.ProjectPath, recursive: true)
src/Dapsman.Cli/CliArguments.cs
- Add
IsLocalTeardownbool - Parse
local teardownaction (alongsidelocal build,local restore, etc.)
src/Dapsman.Cli/DapsmanRunner.cs — add RunLocalTeardown():
- Validates
--projectis specified - Creates plan + service
- Prints plan:
Step: stop containers- docker compose down -v ({compose files})Step: delete caddy site files- {dapsRoot}/caddy_sites/{file}.dev.caddyStep: reload Caddy- docker exec daps-caddy-1 caddy reloadStep: delete project folder- {projectPath}
- Confirmation prompt: “This will delete all containers, volumes, caddy site files, and the project folder. Type ‘yes’ to confirm:”
- Executes if confirmed; returns 1 if declined
Key Design Notes
Section titled “Key Design Notes”-vis essential — this is the whole motivation for the workflow; without it, stale volumes persist and cause broken builds on re-init- Workstation runner, not toolkit — teardown acts on local Docker directly, no need for toolkit container; mirrors how
local buildusesWorkstationBashRunner - Reuses existing resolvers —
IDockerResolver,ICaddyResolver,IProjectResolveralready resolve the paths thatlocal builduses; the plan builder simply reads the same data in reverse - Caddy reload tolerance — if Caddy container isn’t running (e.g. user tore down daps stack), the caddy reload step should not fail the whole teardown
- No daps.yaml cleanup — prod teardown does not remove the project from daps.yaml; local teardown follows the same convention; the user can clean that up manually or we add it later
Verification
Section titled “Verification”dapsman local teardown --project loccom --dry-rundapsman local teardown --project loccomAfter execution:
docker ps -a | grep loccom— no containersdocker volume ls | grep loccom— no volumesls {dapsRoot}/caddy_sites/— noloccom*.dev.caddyfilehttps://loccom.localhost— no longer routes (Caddy returns 404 or connection refused){projectPath}— directory no longer exists