Skip to content

feat(sites): add per-server Sites CRUD#23

Merged
fbarrento merged 1 commit into
mainfrom
feat/7-sites
May 24, 2026
Merged

feat(sites): add per-server Sites CRUD#23
fbarrento merged 1 commit into
mainfrom
feat/7-sites

Conversation

@fbarrento
Copy link
Copy Markdown
Contributor

Summary

Adds the Sites resource under the server chain — $forge->server($id)->sites() / ->site($siteId). The most actively-managed Forge resource and the base for #8 Deployments.

  • Data\Site output DTO with nested Data\SiteRepository + Data\SiteMaintenanceMode value objects
  • Data\CreateSiteData (type required + common create surface), Data\UpdateSiteData (all optional), Data\ListSitesOptions
  • Enums\SiteType, Enums\WwwRedirectType (input) and Enums\SiteStatus (output)
  • Requests: GetSites, GetSite, CreateSite (POST), UpdateSite (PUT), DeleteSite
  • Resources\SitesResource (all/iterate/create) and Resources\SiteResource (get / update[void] / delete)

Spec-vs-runtime findings (for docs/FINDINGS.md once #20-derived doc lands)

  • Individual-site GET is server-less: /orgs/{org}/sites/{site}. The /servers/{server}/sites/{site} path only supports PUT/DELETE (GET there → 405).
  • Create requires domain_mode (spec marks it optional); on-forge mode needs a single dotless subdomain name.
  • Fresh sites return aliases / deployment_status / maintenance_mode.enabled as null despite required-non-null in spec — DTO loosened.
  • PUT update returns 202 empty bodyupdate() is void.
  • Provisioning race: an on-forge site is briefly un-GET/PUT-able while installing. The lifecycle test waits on a live un-mocked connector before the individual-site routes (skipped on replay).

Test plan

  • composer test — pint, rector, phpstan, 344 tests / 670 assertions, 100% coverage.
  • Lifecycle test creates a real on-forge site, exercises update/list/get, then deletes — five fixtures recorded live, redacted (site/repository URLs, deployment_url token, healthcheck URL).

🤖 Generated with Claude Code

Adds the Sites resource under the server chain
($forge->server($id)->sites() / ->site($siteId)) — the most actively
managed Forge resource and the base for Deployments (#8).

- Data\Site output DTO with nested Data\SiteRepository and
  Data\SiteMaintenanceMode value objects
- Data\CreateSiteData (type required + common create surface),
  Data\UpdateSiteData (all optional), Data\ListSitesOptions
- Enums\SiteType, Enums\WwwRedirectType (input), Enums\SiteStatus (output)
- Requests: GetSites, GetSite, CreateSite (POST), UpdateSite (PUT),
  DeleteSite
- Resources\SitesResource (all/iterate/create) and
  Resources\SiteResource (get/update[void]/delete)

Spec-vs-runtime findings (to append to docs/FINDINGS.md):
- Individual-site GET lives at the server-less `/orgs/{org}/sites/{site}`
  path; `/servers/{server}/sites/{site}` only supports PUT/DELETE.
- Create requires `domain_mode` (spec marks optional) and, for on-forge
  mode, a single dotless subdomain `name`.
- Freshly-created sites return `aliases`, `deployment_status`, and
  `maintenance_mode.enabled` as null despite the spec marking them
  required — DTO loosened accordingly.
- PUT update returns 202 with empty body, so update() is void.
- An on-forge site is briefly un-GET/PUT-able while provisioning; the
  lifecycle test waits on a live un-mocked connector before exercising
  the individual-site routes (skipped on replay).

344 tests / 670 assertions / 100% coverage.

Closes #7.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@fbarrento fbarrento self-assigned this May 24, 2026
@fbarrento fbarrento merged commit 6c576fb into main May 24, 2026
26 checks passed
fbarrento added a commit that referenced this pull request May 24, 2026
…it (#28)

Folds the divergences that had only lived in PR descriptions into
docs/FINDINGS.md: ssh-key create 202-empty, the four Sites findings
(server-less GET, runtime-required domain_mode, fresh-site nulls,
PUT-empty), the deployments script/trigger notes, the two daemon findings
(update needs config, install-state race), and the fixture-redaction
hardening from the security audit (#27).

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant