fix: post-review followups on slug-vs-UUID refactor

Addresses every finding from the four-agent review of commit aa493b9.

Dashboard — honor redirect_to on subtab loadApp() (closes the silent
historical-slug redirect UX gap):

  - queues/+page.svelte
  - queues/[name]/+page.svelte
  - files/+page.svelte
  - dead-letters/+page.svelte

  After a rename, the URL bar now reflects the canonical slug instead
  of silently rendering the renamed app's data under the stale URL.
  Mirrors the established pattern at apps/[slug]/+page.svelte:619-623.

manager-core:
  - queues_api.rs IntoResponse now uses the JSON envelope shape
    `{"error": "..."}` consistent with every sibling admin api file.
  - triggers_api::delete_trigger reordered: cap check fires BEFORE the
    trigger load, closing the 404-vs-403 existence side channel an
    unauthorized caller could otherwise probe.
  - InMemoryAppRepo mocks in topics_api + triggers_api now implement
    get_by_slug + get_by_slug_or_history (previously
    `unimplemented!()`), unblocking handler-level slug-input tests.
  - Added 4 slug-acceptance tests to topics_api and 2 to triggers_api
    (slug-resolves, unknown-slug-404, historical-slug-resolves,
    create-via-slug). Also added delete-without-cap-is-forbidden test
    pinning the new cap-first order.

e2e:
  - navigation/tabs.spec.ts split per-tab so a regression on one tab
    no longer masks regressions on the others.
  - Negative assertion widened: captures every /api/v1/admin/apps/*
    response and fails on any 4xx/5xx — not just the literal "Cannot
    parse" string. Catches a broader regression shape.
  - networkidle replaced with `expect(<main>).toBeVisible()` —
    networkidle is officially discouraged for SPAs and was at risk of
    timing out behind the queues auto-refresh.
  - Cleanup registration moved BEFORE the create-app API call so a
    flaky create still gets swept up.
  - Queue drilldown route /queues/[name] now covered.
  - Stable `data-testid="queues-empty-state"` replaces fragile
    UI-copy substring match for the positive assertion.
  - Header comment now spells out what this spec does and doesn't
    catch.

docs:
  - serverless_cloud_blueprint.md: slug-history described as
    "200 OK + redirect_to" JSON envelope rather than "301 redirect"
    — matches what apps_api actually implements (SPA can't honor a
    mid-tree HTTP redirect).

Unit-test gap (acknowledged): queues_api, files_api, secrets_api,
dead_letters_api have zero in-process tests. Adding them properly
needs a shared mock-repo helper crate — the standalone trait surface
(QueueRepo + TriggerRepo + ScriptRepository + AuthzRepo + repo-
specific) is ~30 methods per file. Documented inline in queues_api.rs
near the resolver. Integration coverage via crates/picloud/tests/ and
the new e2e spec cover the same paths end-to-end.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
MechaCat02
2026-06-09 20:03:10 +02:00
parent c42a8406b4
commit a1b7569d05
9 changed files with 399 additions and 90 deletions

View File

@@ -989,7 +989,7 @@ CREATE TABLE app_slug_history (
Slug lookup order:
1. `apps.slug = {slug}` → render the page directly.
2. `app_slug_history.slug = {slug}``301` redirect to `/admin/apps/{current_app.slug}/<rest>`.
2. `app_slug_history.slug = {slug}`the API returns `200 OK` with the renamed app's data and a `redirect_to: <current_slug>` field in the response envelope of `GET /admin/apps/{slug}`. The dashboard's per-app pages mirror the `goto({replaceState: true})` pattern documented in `dashboard/src/routes/apps/[slug]/+page.svelte::loadApp` to update the URL bar. (Originally specified as a server-issued `301`, but a client-routed SPA cannot honor an HTTP redirect mid-tree; the JSON-flag pattern lets each subtab page redirect to its own equivalent path under the new slug.)
3. Neither → `404`.
Slug claim order (create or rename to a slug `S`):