Files
Sluijsens 9a77eec0f1 Designs where the deploy workflow puts things on the Pi
Infrastructure design for U6: single Pi split by directory not port,
systemd --user services instead of sudo, a releases/current/shared
layout that keeps the customer website outside every atomic switch,
and a health check through the existing reverse proxy before pruning
anything. Flags that user-level systemd needs enable-linger or the
service dies the moment the deploy SSH session closes.
2026-07-28 15:32:51 +02:00

9.3 KiB

Infrastructure Design Plan — U6 Deploy Workflow

Prerequisite note (deliberate deviation)

Functional Design and NFR Design are skipped for U6 per the execution plan (unit-of-work.md, aidlc-state.md) — U6 is a Pipeline-type unit (YAML, no C# logic), and its behavioural contract is already fully specified by FR-02, FR-03, FR-04, FR-06, FR-08, FR-20, ASM-01, ASM-03, ASM-04, D-02, D-05, D-09, D-26, D-27 and the U5↔U6 shared-interface constraint in unit-of-work-dependency.md ("U5 with U6 — one interface, two files"). Infrastructure Design is the right entry point: it maps that contract onto an actual host layout.

Steps

  • Step 1: Analyze design artifacts (requirements.md §§ Decisions/FR/ASM, unit-of-work.md U6, unit-of-work-dependency.md, reference project .gitea/workflows/ at K:\Development\SlpSoftware\Projects\SlpSoftware)
  • Step 2: Create this plan
  • Step 3: Generate context-appropriate questions (below)
  • Step 4: Store plan (this file)
  • Step 5: Notify user in chat
  • Step 6: Collect and analyze answers (12/12 answered, no contradictions — Q1/Q10 initially looked like a conflict, same-port two-instance clash, resolved: port assignment is a host/nginx-level fact outside the workflow's concern, so "directory-only" split is consistent)
  • Step 7: Generate infrastructure design artifacts (infrastructure-design.md, deployment-architecture.md)
  • Step 8: Present completion message
  • Step 9: Wait for explicit approval
  • Step 10: Record approval and update progress

What the reference project (SlpSoftware) already establishes — not re-asked

  • Reusable workflow_call deploy workflow, invoked with secrets: inherit
  • sshpass + scp in a plain shell step (container SCP actions fail on the Podman runner with a 409 attach error) — D-05
  • A config job that turns env: values into job outputs, because the env context is unavailable inside a reusable workflow's with: block
  • Gitea Actions variables for paths/environment names, secrets for host/credentials (PI_MAIN_HOST, PI_MAIN_PORT, PI_MAIN_USERNAME, PI_MAIN_PASSWORD — reusable per ASM-07)

None of that needs to be re-decided. What the reference project does not cover — because it only ever uploads a static dist/ folder to a fixed path — is everything below: this unit publishes a running .NET process, must switch releases atomically without a moment of downtime for the customer's website, must back up a database first, and must be able to restart the process and prove it came back healthy.


Category: Deployment Environment

Question 1

Is production the same Raspberry Pi as test (different port/directory), or a second, separate Pi?

A) Same Pi, different port and directory per environment B) Separate Pi per environment C) Not decided yet — design for either (parameterize host via Gitea variables/secrets, don't assume)

Answer: A, but only a different directory

Question 2

What OS architecture is the Pi running, for the dotnet publish runtime identifier?

A) linux-arm64 (Raspberry Pi 4/5, 64-bit OS) B) linux-arm (32-bit OS) C) linux-x64 (not a Pi / emulated) D) Other (please describe after Answer: tag below)

Answer: A, but I might need a windows package later as well for other client API's. For now it is on the Pi


Category: Compute Infrastructure

Question 3

How is the published process managed/restarted on the Pi (ASM-03 assumes systemd)?

A) systemd service, one unit per environment (e.g. slpmodularcms-test.service, slpmodularcms-production.service), restarted via sudo systemctl restart <unit> over SSH B) systemd service, but restart is a manual/documented step, not automated in the workflow C) Some other process manager (pm2, supervisor, a custom script) — describe below D) Other (please describe after Answer: tag below)

Answer: A, but if there are better or more convenient ways to manage .net processes let me know

Question 4

Passwordless sudo systemctl restart for the deploy user — is that already configured, or does it need to be part of the one-time host setup documented in Operations?

A) Already configured B) Needs to be added — document it as a one-time host-setup step in Operations C) Avoid sudo entirely — run the app as the deploy user's own systemd user service (systemctl --user restart), no elevation needed D) Other (please describe after Answer: tag below)

Question 5

Should the workflow publish (dotnet publish -r <RID> --self-contained ...) framework-dependent or self-contained?

A) Self-contained (Pi doesn't need a separately-installed .NET runtime; larger artifact) B) Framework-dependent (assumes .NET 10 runtime already installed on the Pi, per ASM-03; smaller artifact) C) Other (please describe after Answer: tag below)


Category: Storage Infrastructure

Question 6

Release directory layout on the host, given deploy_path as the single input (FR-02) — how should releases/, the atomic current pointer, and the persistent wwwroot/web/ be arranged underneath it?

A) {deploy_path}/releases/{timestamp-or-sha}/ per release, {deploy_path}/current symlink switched atomically to point at one release, {deploy_path}/shared/wwwroot-web/ persistent and symlinked into each new release as wwwroot/web B) Same as A, but the persistent website content lives at a path outside deploy_path entirely (e.g. a fixed host path unrelated to the deploy target), to make it structurally impossible for any future workflow change to prune it by mistake C) Other (please describe after Answer: tag below)

Question 7

How many previous releases should be retained after pruning (FR-06: "at least the previous one")?

A) 2 (current + 1 previous) B) 3 (current + 2 previous) C) 5 D) Other (please describe after Answer: tag below)

Question 8

Database backup before production deploy (FR-20) — is it automatable from the Gitea runner over SSH (ASM-04 assumes the database is reachable from the application, not necessarily from the runner)?

A) Automatable: the deploy workflow runs a backup command over SSH on the Pi itself (e.g. sqlcmd/sqlpackage or a SQL Server backup script already on the host), before the atomic switch B) Not automatable from the runner: emit a clear, verifiable manual step in the deployment instructions instead (FR-20's documented fallback), and the workflow does not attempt it C) Not sure yet — design the workflow with an explicit backup step that can be a placeholder script the user fills in during Operations D) Other (please describe after Answer: tag below)


Category: Networking Infrastructure

Question 9

Post-switch health verification (FR-06 implies confirming the restart succeeded) — how should the workflow check /health?

A) curl from the Gitea runner against the environment's public HTTPS URL B) curl executed on the Pi itself over the same SSH connection, against localhost:<port> (works even if the public URL is only reachable through a reverse proxy not yet configured, and doesn't depend on external DNS/TLS) C) Both — localhost check on the Pi first, then a public-URL check as a secondary confirmation D) Other (please describe after Answer: tag below)

Question 10

Is there an existing reverse proxy (nginx, as in the reference project) in front of this application, or does Kestrel serve requests directly?

A) Kestrel serves directly on a fixed port per environment (e.g. 5000 test, 5001 production) — no reverse proxy for this app B) Existing nginx reverse proxy in front, forwarding to Kestrel on a local port C) Not decided yet / out of scope for this workflow — document the assumption and let Operations confirm the real topology D) Other (please describe after Answer: tag below)


Category: Monitoring Infrastructure

Question 11

If the post-switch health check (Question 9) fails, what should the workflow do?

A) Fail the job loudly (red pipeline) but leave the atomic switch as-is — no automatic rollback; manual rollback via Operations' documented procedure B) Automatically re-point current back to the previous release and restart, then fail the job C) Other (please describe after Answer: tag below)


Category: Shared Infrastructure

Question 12

Gitea Actions variable/secret naming for the deploy target — reuse the reference project's PI_MAIN_* secrets (ASM-07), or introduce project-specific names since this repo has its own test and production paths on the same or a different host?

A) Reuse PI_MAIN_HOST / PI_MAIN_PORT / PI_MAIN_USERNAME / PI_MAIN_PASSWORD as-is (same values already configured for the reference repo, since it's the same Pi) B) New, project-scoped secrets (e.g. SLPMODULARCMS_PI_HOST, etc.) even if the values happen to be identical today, so the two repositories' deploy targets can diverge independently later C) Other (please describe after Answer: tag below)

Answer: A, but rename PI_MAIN_HOST to PI_MAIN_ADDRESS


Self-Validation

  • Every question uses lettered multiple-choice options
  • Every question ends in an explicit Other option
  • Every question has an [Answer]: tag
  • No process/approval question is included here (those stay in chat)