Completion work after Phase 6
The original plan contains six numbered phases. This increment closes several remaining requirements within those phases. Source implementation and automated checks are separate from production acceptance.
Upgrade
Back up PostgreSQL and the existing SECRET_ENCRYPTION_KEY. Apply numbered migrations 010–016, in order, using the migration administrator; do not rerun initialization scripts or reset a populated volume. Deploy API, dashboard and worker together. Upgrade customer agents to 0.7.0 using independently verified checksums before enabling private source downloads or scheduled backups. Build bundles with node scripts/build-agent.mjs. Configure the separate dashboard ACCOUNT_ENCRYPTION_KEY for optional MFA.
| Migration | Adds |
|---|---|
| 010 | Account security challenges, explicit OAuth linking, deleted identity protection, invitations and member changes |
| 011 | Owned authoritative zones, typed records, DNSSEC status and generation-checked reconciliation |
| 012 | Signed GitHub push deliveries, deduplication and paid automatic deployment dispatch |
| 013 | Consent-based cold backup schedules and readiness checks |
| 014 | App-bound encrypted private GitHub credentials |
| 015 | Authenticator MFA, encrypted enrollment, recovery hashes and shared session decisions |
| 016 | Versioned operator-reviewed policies, checkout consent evidence, signup acceptance, privacy requests and cleanup |
| 017 | Encrypted OAuth configuration, contact inbox and consent-based public visit counts |
Account and team controls
Account settings list active sessions and connected sign-in providers. Users can revoke sessions, set/change a password, change email, connect/disconnect Google or GitHub, or delete access to their account. Sensitive changes require a random one-time code sent through configured SMTP to the current email. Codes expire after fifteen minutes and bind to the user, current session, current email, action and target. Email changes also require a second proof at the new address. Password/email changes revoke all sessions. Disconnecting a provider cannot remove the last usable sign-in method.
Account deletion requires the code and typed DELETE. Sole workspace owners must transfer ownership first. Deletion removes login methods, sessions and memberships and pseudonymizes the profile; organization and required billing/audit references remain. This is not an erasure of every historical record. Authenticator MFA adds encrypted manual enrollment, single-use recovery codes and second-factor enforcement for password/OAuth sessions in both runtimes.
Team owners/admins can issue seven-day private invitation tokens and revoke pending invitations. Share the token privately; automatic invitation email delivery is not implemented. Acceptance requires the invited verified email and rechecks the issuing member's current authority. Admins cannot grant owner/admin or change those members. Owners can transfer ownership or remove members, with a serialized last-owner check.
DNS
Set PUBLIC_APP_DOMAIN and two to six comma-separated DNS_NAMESERVERS on the API. Configure the worker's existing PDNS_API_URL and PDNS_API_KEY for an authoritative PowerDNS backend capable of Native zone creation and, when requested, DNSSEC. The same provider may hold the operator routing zone, but customer controls reject that zone, its ancestors and descendants.
Owner/admin DNS controls require current domain ownership. External TXT proofs expire after thirty days and must be refreshed. Record changes stop reconciling when proof expires; already published records are not automatically deleted. The worker creates customer zones with a unique ownserva:ZONE_UUID account marker and refuses to adopt an existing foreign zone. It publishes only requested records and checks provider readback before acknowledging the current generation. Customer DNS uses a separate maintenance task so slow gateway verification cannot exhaust its task deadline.
Supported records: A, AAAA, CNAME, MX, TXT, CAA and SRV. TTL is 60–86400 seconds; each set has up to ten values, and a zone up to 256 sets. Targets must be absolute where required; TXT values must be quoted. Apex CNAME and CNAME coexistence are rejected. The UI shows authoritative nameservers, delegation status and public DNSSEC DS records. Registrar delegation and DS publication require operator/user action. Zone removal and DNSSEC key rollover UI are not implemented; never remove or replace signing keys while a parent DS remains published.
GitHub automation and private source
Automation configures one branch and a fresh one-time webhook secret per application. In GitHub, create a push webhook at the returned API path, with JSON payloads, HTTPS and that secret. The API checks the raw-body SHA-256 signature, delivery UUID, repository, branch and current GitHub branch head. Duplicate deliveries cannot queue duplicate jobs; a reused delivery ID with different content is rejected. The worker coalesces pending pushes to the latest immutable commit, rechecks member authority and applies paid-plan enforcement when configured. Original branch settings remain separate from pinned deployment commits. Provider outages can require webhook redelivery.
GITHUB_API_TOKEN is an optional API-only credential for public commit lookup rate limits; it is independent of Google/GitHub sign-in. Private repositories use explicit, expiring, repository-scoped GitHub tokens with Contents read access. Connect one during deployment or under Automation. Credentials are encrypted with app-specific authenticated context, hidden from normal response bodies and viewers, and delivered only over the signed assigned-agent channel. The agent uses GitHub's native archive authorization, validates an immutable codeload redirect and never forwards the long-lived token to the archive host. Tokens do not enter the build context or runtime environment. A root-owned local job journal may retain a dispatched credential until reconciliation; the customer host is trusted. Disconnect also disables future automatic pushes; revoke at GitHub to invalidate an already dispatched token. No GitHub App installation flow or non-GitHub source is provided.
Scheduled cold backups
Configure restic using the Phase 6 instructions, run a manual backup/recovery drill, then schedule a compiled template volume at 6–168 hour intervals. Enabling requires explicit downtime consent. Agent 0.7 reports backup_ready only with usable protected restic configuration, Docker and deployment opt-in. The worker requires a deployed, online application, current authorized creator, entitlement and no competing active server job.
For a previously running app the agent pauses the verified managed container, creates the cold snapshot, restarts the same managed release, checks health and refreshes its loopback route if its port changed. Previously stopped apps stay stopped. Failed, interrupted, expired or uncertain jobs pause future scheduling for operator review. A host crash after stopping an app can leave it stopped; inspect the journal, container, route and backup result before restarting/re-enabling. Schedules do not prune snapshots. Recovery creates isolated new volumes; automated retention, activation and replacement remain outstanding.
API additions
All API paths below start with /v1, except the public signed webhook. Dashboard account routes use same-origin cookie authentication. Tenant mutations enforce current roles and rate limits.
| Method/path | Purpose |
|---|---|
GET/POST /organizations/{id}/invitations | List/create or revoke by revoke_id |
POST /organizations/{id}/members | Change/remove member using user_id, role, confirm:true |
POST /invitations/accept | Consume private token |
GET /organizations/{id}/dns | Zone, records, delegation and DS status |
POST /organizations/{id}/dns-zones | domain_id, dnssec, confirm:true |
POST /organizations/{id}/dns-records | zone_id, typed record, confirm:true; a deleted record is a reconciliation tombstone |
GET/POST /applications/{id}/automation | Branch/enable/confirmed secret rotation and delivery history |
GET/POST /applications/{id}/repository | Connection metadata; confirmed token replacement or disconnect |
POST /webhooks/github/{id} (no /v1) | Native signed push event |
GET/POST /organizations/{id}/backup-schedules | List/save app/slot schedule, consent and next run |
GET /api/account/security | Profile login status, active sessions and providers |
POST /api/account/{action} | Security code, email/password changes, explicit provider linking, session revocation, account deletion |
Account action names and request validation live in src/lib/account-security.ts; schedule/record types are validated again by API and shared agent protocol. Never pass secrets in URLs.
Acceptance and remaining requirements
Before production, exercise live SMTP and OAuth linking/denial; invitation concurrency; private repository token expiry/revocation and immutable downloads; signed webhook delivery/redelivery against deployed PostgreSQL/Redis; DNS create/readback/delegation/DNSSEC on the actual backend; and Ubuntu Docker/restic stop-backup-restart, changed ports, disk-full, failure, crash and recovery cases. Automated fixtures do not prove those services.
Remaining original requirements include buildpacks/framework autodetection, ZIP/Compose imports, general Git URLs, edge bandwidth accounting and quota enforcement, broader platform administration, application/volume lifecycle deletion and GC, backup retention and activation, agent update/key rotation, and operator-approved production legal policies. Real regional gateways, payment/registrar transactions, template/model startup and disaster-recovery acceptance also remain. This increment does not claim the entire original specification is production complete.