43 KiB
Keystone UI Gap Review
A full audit of the current Vue/Inertia UI in resources/js/pages/ against
docs/implementation-spec.md. Findings are grouped by spec section/feature.
Each gap lists what is missing, where the relevant code lives today, and a
suggested resolution.
Conventions:
- Missing — feature has no UI surface at all.
- Partial — surface exists but does not cover the spec.
- Broken — surface exists but has a bug or dead code path.
1. Global Navigation & Information Architecture
- Partial — active header navigation is still not environment-first. The active
AppLayoutusesresources/js/layouts/app/AppHeaderLayout.vue, whose header navigation (resources/js/components/AppHeader.vue) exposes organisation,Applications, andServerswhen an organisation is selected. There are still no entries forOperationsorOnboarding, and environments are only reachable after choosing an application. The inactive sidebar layout (resources/js/components/AppSidebar.vue:19-37) is even narrower, exposing onlyDashboardandServers. The spec frames environments as the primary surface (§20 Phase 6: "Present environments as the primary application surface"). Add an environment-primary route/navigation surface, plusOperationsand onboarding access while setup is incomplete. - Partial — organisation switcher exists only in the active header chrome. Multiple organisations are modeled (
Organisation::members()onapp/Models/Organisation.php), and the active header (resources/js/components/AppSidebarHeader.vue) includes organisation/application/environment dropdowns. The inactive sidebar layout has no equivalent, and onboarding/operations are still absent from the switcher flow. Keep the header switcher ifAppHeaderLayoutremains the canonical layout; otherwise add parity to the sidebar chrome. - Missing — no Operations index. Operations are the spec's audit/execution backbone (§3) but the UI only surfaces them inline on
environments/Show.vueandservers/Show.vue. There is no organisation-wide operations feed for triage. Add anoperations.indexview with filters (kind, status, target). - Missing — no global empty/help state. A fresh org with no servers/apps has no "Get started" CTA in the primary app chrome; user must guess to visit
/onboarding. Promote the onboarding link until all onboarding steps are complete.
2. Onboarding (Spec §19)
- Partial — onboarding page exists but is unreachable from primary nav.
resources/js/pages/onboarding/Show.vueis only reachable via the URL/organisations/{id}/onboarding. There is no link fromDashboard, the active header navigation,AppSidebar, ororganisations/Show.vue. Surface a persistent banner or primary-nav entry whilenextStepis non-terminal. - Partial — onboarding "Provider" step routes to organisation show.
app/Http/Controllers/OnboardingController.php:25sets the Provider stephreftoorganisations.show, but the Server Providers list there (resources/js/pages/organisations/Show.vue:202-220) has no Add button. There is noproviders.createroute or page. Either add aProviderController@create+ Vue page or make the step open an inline dialog. - Missing — registry/source/server-create steps don't enforce a single org-level "default" once configured. Spec §19 says registry is required for multi-server. The UI never blocks deployment on this — see Deployment Flow gap below.
- Missing — onboarding doesn't reflect deploy-key install step (§5). The spec lists "Deploy key installation and verification" as a discrete step; onboarding shows none. Add a step gated on
applications.deploy_key_installed_at.
3. Organisation & Provider Management
- Missing — server-provider UI is read-only.
resources/js/pages/organisations/Show.vue:202-220lists providers but offers no add/edit/delete. There is noProviderControllerregistered (seeroutes/web.php). The Hetzner provider must currently be seeded outside the UI. - Missing — registry/source-provider lists have no edit/delete. Only
createandstoreare wired (routes/web.php:33-41). Users can produce duplicate registries with bad credentials and never repair them. - Missing — no organisation member management.
organisations/Show.vue:111-122shows a members count with no roster, invite flow, role editor, or removal. Themembers()BelongsToMany onOrganisationis unused by the UI. - Partial — registry credentials cannot be rotated. No edit page; the only fix is delete-and-recreate, but delete is also missing. Add
registries.edit+registries.update.
4. Source Providers & Repository Access (Spec §5)
- Partial — deploy-key card disappears once installed.
resources/js/pages/applications/Show.vue:46-75only shows the deploy-key card whenapplication.deploy_key_public && !application.deploy_key_installed_at. After install there is no way to view or rotate the key. Show key +deploy_key_fingerprintand a "Rotate" action permanently in an Application Settings tab. - Missing — no fingerprint display. The model stores
deploy_key_fingerprint(app/Models/Application.php), but the UI never renders it. Surface beside the public key for verification. - Missing — no way to re-run
git ls-remoteverification after install. Verify button is gated by the same conditional inapplications/Show.vue:46. Move it to an always-available action; spec §5 implies verification can be re-run. - Missing — application creation does not pick a source provider.
resources/js/pages/applications/Create.vuecollectsrepository_urlas a free string. Source providers exist (§5: Gitea/GitHub/generic Git) but the form never references them — users have no guidance for which provider corresponds to the URL, and the application schema/UI currently has no source-provider association. - Missing — repository type selector. Spec lists
repository_type(§2 Application). UI hardcodesRepositoryType::GIT(app/Http/Controllers/ApplicationController.php:39). Even if Git is the only v1 type, the form should display the resolved type.
5. Applications & Environments (Spec §2, §6, §17)
Applications
- Missing — no Application edit/delete. Only
index/show/create/storeare routed (routes/web.php:62-66). Renaming or removing an app requires DB intervention. - Missing — environment creation UI. The initial environment is auto-created in
ApplicationController@store(CreateLaravelEnvironment). There is no "Add environment" affordance onapplications/Show.vue, despite the spec describing multiple environments (production/staging/dev) as the primary deployment unit (§2). - Broken — Applications/Index uses wrong key + has no empty state.
resources/js/pages/applications/Index.vue:46writes:key=\application{$applications.id}`(literal$applications). Replace with:key="application.id"and render an empty card whenapplications.length === 0`. - Partial — Application Show has no overview. No "last deployed at", no current commit, no current image digest. Spec §6 stores
current_image_digeston Service andBuildArtifactper environment but neither is rendered.
Environments
- Missing — environment-level edit page. Cannot change
branch,name,status,scheduler_enabled,scheduler_target_service_id,scheduler_mode, orbuild_config(spec §2). All are dead fields in the DB from the UI's perspective. - Missing — branch change / redeploy with a specific commit. Deploy is a fire-and-forget POST (
environments/Show.vue:63-76andapplications/Show.vue:139-153). The spec resolves a "target commit" (§17 step 1) — there is no commit picker or branch switcher in the UI. - Missing — build artifact view per environment.
BuildArtifactexists with status/digest/registry_ref but is not rendered onenvironments/Show.vue. Add a "Builds" section showing recent artifacts and their status. - Missing — scheduler controls (Spec §8). No UI for
scheduler_enabled,scheduler_target_service_id, orscheduler_mode. The spec explicitly says scheduler is a role/capability and that v1 should expose it. Add to environment settings tab and surface "Scheduler runs on: " on the environment overview. - Missing — migration policy controls (Spec §18).
migration_mode,migration_timing,migration_commandare spec fields on a service. The UI has only a one-offMigratebutton (environments/Show.vue:77-91); there is no form to inspect/change defaults per service. - Partial — environment header buttons are crowded.
resources/js/pages/applications/Show.vue:123-211packs Open / Deploy / Migrate / Env / Worker / Attach into a single card row. On md screens this overflows. Move secondary actions into a dropdown. - Missing — environment delete. Spec implies environments are mutable units (§2); UI has no delete.
6. Services (Spec §2 Service, §7, §9, §11)
Service list / show
- Missing — no service-by-environment scoping.
services/Show.vuedoes not show its parent environment (onlyserver+service). Reaching a service from an environment requiresservice.server_idto be set (environments/Show.vue:138-153); environments where the service is server-less (replicas only) cannot be opened. Show environment breadcrumb when present. - Missing — replica detail view.
services/Show.vue:62-79lists replicas but they are inert. Spec §2 ServiceReplica hascpu_limit,memory_limit_mb,container_id,internal_host,internal_port,public_port,image_digest,health_status. Tap-through to a replica detail with logs/restart action is missing. - Missing — start/stop/restart actions on replicas. Status badges show
statusandhealth_status(services/Show.vue:73-77) but no buttons. - Missing — endpoint listing.
app/Models/ServiceEndpoint.phpexists and Spec §14 defines an endpoint model (scope: docker_network/private_network/public, hostname/ip/port/priority). UI never renders endpoints. Add an "Endpoints" card onservices/Show.vue. - Missing — compose preview / generated artifact view. Spec §16 establishes generated Compose under
/home/keystone/services/<service-id>/compose.yml. There is no UI to inspect/render it. Add a "Compose" tab onservices/Show.vue(read-only, syntax-highlighted). - Missing — process_roles editor.
Servicehasprocess_rolesJSON (spec §2). Used by scheduler role attachment (§8). No UI exposes it.
Service edit (services/Edit.vue)
- Partial — only name, desired_replicas, default_cpu_limit, default_memory_limit_mb editable. Missing:
deploy_policy,version_track,available_image_digest(acknowledge available update),configoverrides (migration_mode/timing/command per §18),schedulerflags for app services. - Missing — health-check / health-path override. Spec §7 defaults health path to
/up. No UI surfaces or overrides.
Service create
- Missing — builder service category in practice.
ServiceCategory::BUILDERexists and Spec §6 says "A dedicated builder is represented as aServicewith categorybuilder". The Create flow shows the BUILDER radio (it loops over the enum) butservices/Create.vue:111-122only listsservices[form.category]fromconfig('keystone.services')— there is no entry for builder there, so selectingbuildershows an empty type list with no message. Either removeBUILDERfrom the radio set or wire builder driver options. - Missing — selecting category doesn't surface deploy_policy defaults. Spec §2 defines deploy_policy defaults per category. The form does not show or let the user accept them.
Stateful service updates (Spec §11)
- Partial — update form exists but exposes raw digest.
resources/js/pages/services/updates/Create.vue:74-82requires the user to paste an image digest. The available digest is pre-filled fromservice.available_image_digest, but Postgres/Valkey users will not know how to obtain a different digest. Replace with a "latest minor" resolver and a manual override (spec §9: "resolving image tags to digests"; §11 implies guided update). - Partial — backup checkbox visible only when
backup_enabledconfig flag is set. Spec §11 step 3 says "Optional backup checkbox appears only if backup capability exists" — current code matches the letter, but the UI never lets the user enable backups in the first place, so the checkbox is unreachable. - Missing — downtime acknowledgement. Spec §11 step 2 says "Keystone warns about downtime and data risk." Current warning is generic. Show a hard confirmation step ("type the service name to confirm").
7. Slices & Attachments (Spec §12, §13)
- Missing — slice index per service.
services/Show.vue:81-95lists slices withname + typeonly — no operations, no credentials view, no detail page, no create from service-detail (spec §12: "Advanced users can select existing slices or create slices manually from service detail pages"). - Missing — slice create UI. No
slices.createroute or page. Spec §12 explicitly requires this for advanced users. - Missing — slice operations are not independent in the UI. Spec §12: "Slice operations should be independent from service container deployments." Backend distinguishes
slice_provision/slice_configureoperations (§3), but UI only shows them mixed into the service's operations list (services/Show.vue:97-117). - Missing — env-var preview for attachments. Spec §13 enumerates
DB_*/REDIS_*exports. The attachment form (environment-attachments/Create.vue) shows only "Generated " with no preview of what variables will be written. Add a preview block. - Missing — attachment edit/detach.
environments/Show.vue:184-204lists attachments inertly — no detach button, no edit. Recovering from a wrong attachment requires DB intervention. - Partial — attachment form's role/service compatibility is hardcoded in JS.
environment-attachments/Create.vue:37-48keeps role-to-service-type mapping client-side. If the backend adds queue support via Postgres listen/notify or storage via Caddy, this map drifts. Push the compatibility matrix from the controller. - Missing —
is_primarysemantics aren't explained. A checkbox labeled "Primary attachment" with no helper text; users don't know when to uncheck.
8. Environment Variables (Spec §13)
- Partial — variables UI is add-only.
environment-variables/Create.vueonly POSTs. There is no edit, no delete, no value reveal, no bulk import (.envpaste). Managed values show as badges (environments/Show.vue:206-235) but cannot be inspected or overridden. - Missing —
overridabletoggle. Spec §2 EnvironmentVariable hasoverridable. The UI never surfaces it; all user-created variables silently becomeoverridable: true(EnvironmentVariableController::store). - Missing — source/slice provenance display. Managed/system variables should "show their source and whether they are overridable" per spec §13. Currently rendered as
<source>text only; no link back to the slice/attachment that generated them. - Missing — secret vs. plain value distinction. No marker, no masking, no copy button.
9. Servers (Spec §4)
- Broken —
<template>block has dangling fallback.resources/js/pages/servers/Show.vue:217reads<template> Something else </template>outside anyv-if/v-else-ifchain. This is an unconditional Vue template whose text child renders alongside the rest of the page, not a real status fallback. Clean up or convert to<template v-else>. - Partial — provisioning UI is decorative.
servers/Show.vue:27-39cycles through fake messages on an interval. No actual progress, no association to the runningserver_provisionoperation (spec §3 OperationKind). Tie the cycling messages to realoperation_stepsevents. - Missing — server delete / decommission. Not wired anywhere; only
index/show/create/storeroutes registered (routes/web.php:43-47). - Missing — firewall-rule UI.
app/Models/FirewallRule.phpandServer::firewallRules()exist. Spec §4 step 8 says UFW with SSH open, but additional rules (e.g. for Caddy 80/443, private network) are not surfaced. Add a Firewall tab onservers/Show.vue. - Missing — credential persistence/regen. "WILL NOT BE SHOWN AGAIN" (
servers/Show.vue:219-224) appears via flash only; if the user navigates away without copying, the only credential they have is the SSH key Keystone manages. Acceptable, but should explicitly say "Keystone uses an SSH key for all subsequent operations; this password is informational." - Missing — re-provision/heal action. If provisioning fails there is no retry button on the show page.
- Missing — service add gated on server
activestatus.servers/Show.vue:75-94only renders the Add button when status isactive, but duringprovisioningthere is no informative message about why services can't be added (the cycling messages run but the section disappears entirely). Show a disabled "Add" with tooltip. - Missing — operations list does not show parent-child structure.
servers/Show.vue:138-196shows steps under each operation but flat. Spec §3 emphasises parent-child (environment_deploy → service_deploy → replica_deploy). Render as a tree.
10. Operations & Logs (Spec §3)
- Partial — step log dialog only on server show.
servers/Show.vue:226-245is the only place a user can read full step logs. Service Show and Environment Show both list operations without log expansion. Promote the log dialog to a shared component and use it everywhere operations appear. - Missing — operation detail page. Spec §3 implies operations are first-class. There is no
operations.showpage. Cannot view secrets used, parent op, retry, cancel, or download logs. - Missing — retry / abort actions. Failed operations are terminal in the UI; spec doesn't forbid retry. Add at least a "Re-run operation" button on the operation detail page.
- Missing — operation hash / kind / target column.
Operation::hashis generated but never displayed; useful for support and correlation with server-side/home/keystone/operations/<operation-hash>/directories (spec §16). - Missing — live progress. Operations require a refresh to update. Inertia v2 supports polling, and this app already uses
WhenVisiblefor deferred organisation settings data (organisations/Show.vue:126); apply polling/deferred refresh patterns to operations.
11. Build Artifacts & Registry (Spec §6)
- Missing — no build artifact UI.
BuildArtifactmodel +PlanBuildArtifact/BuildApplicationArtifactactions exist, but there is no listing per environment or per registry. Users cannot see whether a build is pending, building, available, or failed. - Missing — registry usage indicator. Spec §19: "If an environment spans more than one server and no registry exists, deployment should be blocked with a registry setup prompt." UI does not surface this precondition anywhere — deploy button is always live on
applications/Show.vue:139-153. Add a pre-deploy check. - Missing — build strategy selector. Spec §6:
target_server/dedicated_builder/external_registry. There is no UI to choose. Currently the strategy lives inBuildArtifact.metadata['build_strategy']only. - Missing — registry detail page. No way to see which artifacts have been pushed where.
12. Gateway / Caddy (Spec §15)
- Missing — domain / route configuration UI. Caddy attachment is supported (
environment-attachments/Create.vue:39-48) but the form does not collect a domain, TLS preference, or path prefix. Spec §15 requires explicit gateway routes; spec §12 says "Caddy/domain attachment: Create route slice. Wire gateway route to environment web service." There is no domain input anywhere in the UI. - Missing — TLS / certificate status view. No surface to see whether Caddy has issued a cert.
- Missing — Caddyfile preview. Similar to compose preview — spec §16 places it at
/home/keystone/gateway/Caddyfile. Should be viewable. - Missing — cutover visualisation. Spec §15 lays out the cutover sequence (render → health → upstream add → reload → drain → stop). UI has no visualisation; users get a generic deploy progress only.
13. Networking (Spec §14)
- Missing — endpoint surface entirely. Spec defines an endpoint model with
scope/hostname/ip_address/port/priority/health_status. The model class exists (app/Models/ServiceEndpoint.php) but is never rendered. - Missing — private-network membership view.
Networkmodel andServer::network()exist; spec §14 prefers same-provider private IPs. UI never shows which servers share which networks.
14. Dashboard & Welcome
- Partial — Dashboard is a single card.
Dashboard.vue:27-44lists organisations only. Once an org is picked, no summary of pending operations, recent deploys, or failing services on the main dashboard. Add "Recent operations" + "Unhealthy services" panels. - Missing — no aggregated health. Organisation Show (
organisations/Show.vue:65-123) shows counts but not health (provisioning servers, failed last deploy, locked attachments).
15. Visual & UX Polish
- Inconsistent — script tags mix
<script setup lang="ts">and<script setup>. E.g.pages/environments/Show.vue:1is plain JS whilepages/applications/Show.vue:1is TypeScript. Pick a default and apply. - Inconsistent — typed props. Several Show pages declare
defineProps({ application: { type: Object, required: true }, ... })with no TS interfaces. New pages should usedefineProps<{...}>()shapes. - Inconsistent — breadcrumb depth. Service Show breadcrumb (
services/Show.vue:18-33) goes Servers → server → service, but an environment-scoped service should also show the environment in the trail. - Accessibility — radio button groups in Create flows.
servers/Create.vueandservices/Create.vueuseRadioButtonbut render viav-forwith no:keyon the radios. Visual-only impact today, but a11y-wise the labelling could be tightened (associate description text witharia-describedby). - Accessibility — colour-only status.
ServiceCard.vue:38-58uses small dots + colour classes for status with no text alternative beyond the status string. Verify contrast in light mode. - Empty states — Applications/Servers indexes have none. A new organisation hits a blank grid. Render an illustration + CTA pointing to onboarding.
16. Routes & Controllers Backing the UI
These backend gaps directly produce the UI gaps listed above. Filling the UI will require new routes/controllers (or destroy actions on existing ones):
providers.create/store/destroy(organisation provider mgmt)registries.index/edit/update/destroysource-providers.index/edit/update/destroyapplications.edit/update/destroyenvironments.create/store/edit/update/destroyenvironments.scheduler(settings sub-resource)services.destroyand service-level slice mgmt (services/{service}/slices.*)service-replicas.show/restartenvironment-variables.update/destroy/indexenvironment-attachments.destroy/updateoperations.index/show/retrybuild-artifacts.index/showservers.destroy,servers.firewall-rules.*domains.*/gateway.routes.*for Caddy
17. Suggested Priorities
To bring the UI in line with spec without inflating scope:
- Make environments the primary surface (spec §20 Phase 6). Sidebar entry, environment overview tab, environment edit page covering branch + scheduler + build config + migration policy.
- Fix the deploy preconditions and visibility loop. Block deploy when no registry + multi-server (§19). Show build artifact + commit + image digest after deploy.
- Promote operations to first-class.
operations.index,operations.show, log dialog reused across pages, parent-child tree, retry. - Round out CRUD for org-level resources (providers, registries, source providers, members). Currently all "configured once via DB" surfaces.
- Slice + attachment maintenance. Edit/detach/preview env-var exports.
- Gateway/domain UX. Domain input on Caddy attachment, route slice view, Caddyfile preview.
- Polish: fix
servers/Show.vuedangling<template>, fixapplications/Index.vue:key, add empty states, unify script lang.
18. Progress Tracker
This tracker is the working checklist for closing the review. It is intentionally
conservative: an item is only Done when there is current code evidence and at
least targeted verification.
Status key:
Done- implemented and targeted verification exists.Partial- meaningful UI/code exists, but the review item is not fully satisfied.In progress- code has been started but is not yet verified or finalized.Open- no convincing implementation evidence found yet.Needs audit- likely implemented, but needs an item-level pass before closing.
Current Caution
| Item | Status | Evidence | Next action |
|---|---|---|---|
| Repository type selector | Done | StoreApplicationRequest, UpdateApplicationRequest, ApplicationController, applications/Create.vue, and applications/Edit.vue validate, persist, and display repository_type; ApplicationControllerTest and CrudUiTest cover create/update. |
Final audit only. |
| Overall completion | Done | All tracker rows are done, targeted verification is logged below, and the full test suite passes. | Final audit complete. |
Section Checklist
| Section | Review area | Status | Evidence | Remaining work |
|---|---|---|---|---|
| 1 | Environment-first navigation | Done | AppHeader.vue and AppSidebar.vue both expose Environments, Applications, Servers, Operations, and conditional Onboarding; EnvironmentIndexController and environments/Index.vue provide the environment-first index; NavigationUiTest covers shared navigation context and environment listing. |
Final audit only. |
| 1 | Organisation switcher parity | Done | AppSidebarHeader.vue provides organisation/application/environment switchers and HandleInertiaRequests shares organisation/application context with applications/environments loaded. |
Final audit only. |
| 1 | Operations index | Done | routes/web.php has operations.index; resources/js/pages/operations/Index.vue; tests/Feature/OperationsUiTest.php. |
Final audit only. |
| 1 | Global empty/help state | Done | organisations/Show.vue shows a primary Continue onboarding CTA for incomplete organisations; applications/Index.vue, servers/Index.vue, and environments/Index.vue include empty states and CTAs/help text for fresh resources. |
Final audit only. |
| 2 | Onboarding reachable from primary nav | Done | OnboardingController sends nextStep; onboarding/Show.vue renders it; AppHeader.vue and AppSidebar.vue include Onboarding while setup counts are incomplete. |
Final audit only. |
| 2 | Provider onboarding step opens usable add flow | Done | ProviderController, provider create route/page, onboarding/provider links. |
Final audit only. |
| 2 | Registry/source/server default/precondition handling | Done | OnboardingController gates provider/source/registry/server/application/deploy-key steps; OnboardingControllerTest covers next-step progression; EnvironmentDeploymentController blocks multi-server deploy without a registry and app/environment deploy surfaces show registry CTAs. |
Final audit only. |
| 2 | Deploy-key install onboarding step | Done | OnboardingController includes a deploy-key step that targets the first app with deploy_key_installed_at null and marks complete when none remain. |
Final audit only. |
| 3 | Provider management | Done | providers.create/store/destroy, provider page/tests. |
Final audit only. |
| 3 | Registry/source provider lists/edit/delete | Done | Registry/source provider index/edit/update/destroy routes/pages/tests exist. | Final audit only. |
| 3 | Organisation member management | Done | OrganisationInvitation model/migration/factory, member/invitation routes, OrganisationMemberController, organisation-members/Index.vue, and OrganisationMemberControllerTest cover existing-member add/update/remove plus pending invitation create/update/cancel. |
Final audit only. |
| 3 | Registry credential rotation | Done | registries.edit/update present. |
Final audit only. |
| 4 | Deploy key always visible, fingerprint, verify, rotate | Done | Application show/controller routes/tests include deploy key rotate and verification. | Final audit only. |
| 4 | Source provider association on applications | Done | source_provider_id migration/model/forms/controller/tests. |
Final audit only. |
| 4 | Repository type selector | Done | Code validates/persists/displays selector; targeted app CRUD tests pass. | Final audit only. |
| 5 | Application edit/delete | Done | applications.edit/update/destroy, applications/Edit.vue, tests. |
Final audit only. |
| 5 | Environment create UI | Done | environments.create/store, create page/routes. |
Final audit only. |
| 5 | Applications index key and empty state | Done | applications/Index.vue uses :key="application.id" and has an empty-state card with a create CTA. |
Final audit only. |
| 5 | Application overview deploy metadata | Done | Application show renders last deploy/current commit/image digest from services/build artifacts. | Final audit only. |
| 5 | Environment settings | Done | environments/Edit.vue, update request/controller for branch/status/scheduler/build config. |
Final audit only. |
| 5 | Branch change / deploy specific commit | Done | StoreEnvironmentDeploymentRequest, target_commit, environment deploy form, controller/job tests. |
Final audit only. |
| 5 | Build artifact view per environment | Done | build-artifacts.index/show, environment builds section, tests. |
Final audit only. |
| 5 | Scheduler controls | Done | Environment edit and show scheduler fields. | Final audit only. |
| 5 | Migration policy controls | Done | Service edit exposes migration mode/timing/command and environment show summarizes. | Final audit only. |
| 5 | Crowded environment actions | Done | applications/Show.vue keeps primary Open/Deploy visible, moves secondary environment actions into a More menu, and wraps action groups for responsive layouts. |
Final audit only. |
| 5 | Environment delete | Done | environments.destroy route/controller/page action. |
Final audit only. |
| 6 | Service-by-environment scoping | Done | environment-services.show, service breadcrumb supports environment, tests. |
Final audit only. |
| 6 | Replica detail and lifecycle actions | Done | ServiceReplicaController, replica show/start/stop/restart routes/pages/tests. |
Final audit only. |
| 6 | Endpoint listing | Done | services/Show.vue endpoint card. |
Final audit only. |
| 6 | Compose preview | Done | services/Show.vue compose path/preview card. |
Final audit only. |
| 6 | Process roles editor | Done | services/Edit.vue, UpdateServiceRequest, controller update. |
Final audit only. |
| 6 | Service edit missing fields | Done | Deploy policy, version track, available digest, migration config, health path, backup fields added. | Final audit only. |
| 6 | Builder category and deploy policy default display | Done | services/Create.vue empty state/default deploy policy display. |
Final audit only. |
| 6 | Stateful update resolver, backup, acknowledgement | Done | ServiceUpdateController::resolve, update create page hard confirmation, tests. |
Final audit only. |
| 7 | Slice index/detail/create/operations | Done | service-slices.index/create/store/show, service-slices/Index.vue, service-slices/Show.vue, and ResourceDetailUiTest cover list/detail/create plus independent operations. |
Final audit only. |
| 7 | Attachment env-var preview | Done | Attachment create/edit preview blocks. | Final audit only. |
| 7 | Attachment edit/detach | Done | environment-attachments.edit/update/destroy, pages/tests. |
Final audit only. |
| 7 | Compatibility matrix from backend | Done | Attachment controller supplies compatibility matrix. | Final audit only. |
| 7 | Primary attachment semantics | Done | Helper text added. | Final audit only. |
| 8 | Environment variables index/edit/delete/import | Done | EnvironmentVariableController, create/index/edit pages/tests. |
Final audit only. |
| 8 | Overridable/source/slice provenance | Done | Variable forms/list expose overridable and source/slice. | Final audit only. |
| 8 | Secret/plain masking and copy | Done | Variable index reveal/copy controls. | Final audit only. |
| 9 | Server dangling fallback | Done | servers/Show.vue no longer has unconditional "Something else". |
Final audit only. |
| 9 | Provisioning tied to real operations | Done | servers/Show.vue renders OperationTimeline for active server_provision operations and only uses cycling copy as a fallback when no provision operation exists. |
Final audit only. |
| 9 | Server delete/decommission | Done | servers.destroy route/controller/UI. |
Final audit only. |
| 9 | Firewall-rule UI | Done | Server show lists firewall_rules and includes add/remove controls; servers.firewall-rules.store/destroy routes and ServerControllerTest cover create/delete/validation. |
Final audit only. |
| 9 | Credential persistence wording | Done | servers/Show.vue flash credential copy says Keystone uses its managed SSH key later and the password is informational for initial access only. |
Final audit only. |
| 9 | Re-provision/heal action | Done | servers.heal, controller/test/UI. |
Final audit only. |
| 9 | Service add gating explanation | Done | servers/Show.vue disables Add service during provisioning with title="Services can be added after provisioning completes.". |
Final audit only. |
| 9 | Operations parent-child structure | Done | servers/Show.vue uses shared OperationTimeline for service/server operations; OperationTimeline.vue renders child operation counts and child operation links. |
Final audit only. |
| 10 | Shared operation logs | Done | components/operations/OperationTimeline.vue used across pages. |
Final audit only. |
| 10 | Operation detail page | Done | operations.show, page/tests. |
Final audit only. |
| 10 | Retry/cancel/download logs | Done | OperationController retry/cancel/logs routes/pages/tests. |
Final audit only. |
| 10 | Operation hash/kind/target columns | Done | Operation pages show hash/kind/target. | Final audit only. |
| 10 | Live progress | Done | Operations index/show use Inertia polling. | Final audit only. |
| 11 | Build artifact UI | Done | Build artifact pages and registry artifact usage. | Final audit only. |
| 11 | Registry usage/pre-deploy block | Done | Multi-server deploy blocked without registry; app and environment deploy surfaces both expose the precondition before deploy. | Final audit only. |
| 11 | Build strategy selector | Done | Environment edit exposes build strategy. | Final audit only. |
| 11 | Registry detail page | Done | registries.show page/tests. |
Final audit only. |
| 12 | Domain / route configuration UI | Done | Gateway attachment create/edit has domain/path/TLS fields; deploy route rendering uses those values through CaddyRouteRenderer; dedicated gateway.routes.index/create/store/edit/update/destroy routes/pages manage domain route slices directly. |
Final audit only. |
| 12 | TLS / certificate status view | Done | Route config stores certificate status; gateway cutover operations now include a Check TLS certificate status runtime step; shared OperationTimeline.vue displays per-step statuses. |
Final audit only. |
| 12 | Caddyfile preview | Done | CaddyRouteRenderer feeds both deploy route scripts and gatewayRoutePreviews on environments/Show.vue; EnvironmentControllerTest covers rendered domain/path/upstream preview. |
Final audit only. |
| 12 | Cutover visualization | Done | environments/Show.vue gateway cutover badges now match the actual operation sequence; DeployEnvironmentJobTest verifies route configure and gateway cutover child operations and step names. |
Final audit only. |
| 13 | Endpoint surface | Done | Service endpoint card exists. | Final audit only. |
| 13 | Private-network membership view | Done | ServerController@index now supplies organisation networks with attached servers; servers/Index.vue renders private-network membership; ServerControllerTest covers network/server membership props. |
Final audit only. |
| 14 | Dashboard recent ops/unhealthy services | Done | Dashboard controller/page includes recent operations and unhealthy services. | Final audit only. |
| 14 | Aggregated organisation health | Done | Organisation show health cards and roster/manage link. | Final audit only. |
| 15 | Script tag consistency | Done | Page-level scripts converted to lang="ts" based on prior search; rg -n "<script setup(?! lang=\"ts\")" resources/js/pages resources/js/components -P now returns no matches. |
Final audit only. |
| 15 | Typed props | Done | rg -n "<script setup(?! lang=\"ts\")" resources/js/pages resources/js/components -P returns no matches after converting ServerSelector.vue; page/component setup scripts are now TypeScript. |
Final audit only. |
| 15 | Breadcrumb depth | Done | Environment-scoped service breadcrumb added. | Final audit only. |
| 15 | Radio a11y | Done | RadioButton.vue supports aria-describedby; servers/Create.vue and services/Create.vue now attach explicit description IDs for radio options with descriptive copy. |
Final audit only. |
| 15 | Colour-only status | Done | ServiceCard.vue renders status text alongside the color dot and now uses stronger light/dark status text colors. |
Final audit only. |
| 15 | Application/server empty states | Done | applications/Index.vue and servers/Index.vue both render empty-state cards with primary CTAs. |
Final audit only. |
| 16 | Backing routes/controllers list | Done | php artisan route:list --path=environments shows scheduler settings are covered through environments.edit/update; registry/source-provider index routes and server firewall-rule routes are covered; php artisan route:list --name=gateway.routes shows six dedicated gateway route CRUD routes. |
Final audit only. |
Suggested Next Queue
No implementation gaps remain in this tracker. Keep future work to fresh manual UI review findings or new product requirements.
Verification Log
Recent targeted checks from this workstream:
| Command | Result | Scope |
|---|---|---|
php artisan test |
Passed, 231 tests / 1375 assertions | Full application regression suite after completing the UI review tracker. |
php artisan test tests/Feature/NavigationUiTest.php |
Passed, 3 tests / 38 assertions | Environment-first navigation context, environment index, and provider onboarding route. |
npm run build |
Passed | Frontend compilation after gateway cutover copy/badge alignment. |
php artisan test tests/Feature/DeployEnvironmentJobTest.php --filter='gateway' |
Passed, 1 test / 13 assertions | Gateway cutover sequence including TLS certificate status step. |
npm run build |
Passed | Frontend compilation after operation step-status display. |
vendor/bin/pint --dirty |
Passed, 71 files | PHP formatting after gateway cutover TLS step changes. |
npm run build |
Passed | Frontend compilation after ServerSelector.vue typed-props conversion. |
rg -n "<script setup(?! lang=\"ts\")" resources/js/pages resources/js/components -P |
No matches | Verified page/component setup scripts are TypeScript. |
php artisan test tests/Feature/OnboardingControllerTest.php |
Passed, 4 tests / 45 assertions | Onboarding next-step progression, registry/source/server/application gates, and deploy-key gate. |
vendor/bin/pint --dirty |
Passed, 70 files | PHP formatting after onboarding test adjustment. |
php artisan test tests/Feature/OrganisationMemberControllerTest.php |
Passed, 4 tests / 47 assertions | Organisation member roster plus pending invitation create/update/cancel. |
npm run build |
Passed | Frontend compilation after organisation invitation UI changes. |
vendor/bin/pint --dirty |
Passed, fixed 1 style issue across 66 dirty PHP files | PHP formatting after organisation invitation model/migration/controller/request/test changes. |
php artisan test tests/Feature/ServerControllerTest.php |
Passed, 4 tests / 62 assertions | Server heal/firewall coverage plus organisation-level private-network membership on servers index. |
npm run build |
Passed | Frontend compilation after servers index private-network membership UI changes. |
vendor/bin/pint --dirty |
Passed, 66 files | PHP formatting after server index/controller/test changes. |
npm run build |
Passed | Frontend compilation after radio aria-describedby associations. |
php artisan test tests/Feature/EnvironmentControllerTest.php |
Passed, 3 tests / 25 assertions | Environment show, including rendered Caddyfile preview for gateway attachments. |
php artisan test tests/Feature/DeployEnvironmentJobTest.php --filter='gateway' |
Passed, 1 test / 13 assertions | Gateway deploy script still creates route configure and cutover operations after shared Caddy renderer change. |
npm run build |
Passed | Frontend compilation after Caddyfile preview UI changes. |
vendor/bin/pint --dirty |
Passed, 61 files | PHP formatting after Caddy renderer/controller/job/test changes. |
npm run build |
Passed | Frontend compilation after ServiceCard.vue typed props and status contrast changes. |
php artisan test tests/Feature/ResourceDetailUiTest.php --filter='creates and shows service slices' |
Passed, 1 test / 41 assertions | Dedicated service slice index, create, detail, and independent operations coverage. |
npm run build |
Passed | Frontend compilation after service slice index page/link changes. |
vendor/bin/pint --dirty |
Passed, 59 files | PHP formatting after service slice route/controller/test changes. |
php artisan route:list --path=environments |
Passed, 25 environment-related routes shown | Confirmed scheduler settings are covered by environment edit/update rather than a separate scheduler sub-resource. |
php artisan route:list --name=gateway.routes |
Passed, 6 routes shown | Confirmed dedicated gateway route CRUD route surface. |
php artisan test tests/Feature/EnvironmentAttachmentControllerTest.php |
Passed, 4 tests / 100 assertions | Managed attachments plus dedicated gateway route create/list/edit/update/delete coverage. |
npm run build |
Passed | Frontend compilation after gateway route CRUD pages and environment link changes. |
vendor/bin/pint --dirty |
Passed, 69 files | PHP formatting after gateway route controller/request/route/test changes. |
php artisan test tests/Feature/RegistryControllerTest.php tests/Feature/CrudUiTest.php |
Passed, 8 tests / 121 assertions | Registry and source-provider index routes plus CRUD coverage. |
php artisan test tests/Feature/ServerControllerTest.php |
Passed, 3 tests / 46 assertions | Server heal and firewall-rule create/delete/validation. |
php artisan test tests/Feature/ApplicationControllerTest.php tests/Feature/CrudUiTest.php |
Passed, 11 tests / 111 assertions | Repository type selector validation/persistence and application CRUD. |
php artisan test tests/Feature/EnvironmentDeploymentControllerTest.php |
Passed, 4 tests / 22 assertions | Registry precondition and target commit deployment. |
php artisan test tests/Feature/ServiceControllerTest.php tests/Feature/EnvironmentVariableControllerTest.php |
Passed, 18 tests / 134 assertions | Environment-scoped services and variable management. |
npm run build |
Passed in recent slices | Frontend compilation after Vue changes. |
vendor/bin/pint --dirty |
Passed in recent slices | PHP formatting. |