Files
PiCloud/examples/cms-poc/scripts/workflow/pipeline_run.rhai
MechaCat02 813bc46640
Some checks failed
CI / Rust — fmt, clippy, test (push) Failing after 39m53s
CI / Dashboard — check (push) Successful in 10m15s
docs(examples): add the CMS proof-of-concept dogfooding artifact
A WordPress-inspired CMS whose entire backend is PiCloud Rhai scripts
deployed with pic apply, plus a SvelteKit frontend. Built to dogfood the
project tool, CLI, and SDK; exercises docs/kv/files/users, docs+queue+cron
+pubsub triggers, the transactional-outbox notification chain, a docs
before-interceptor, set_if CAS, SSE, per-app CORS, env overlays, and a
durable Workflow (validate -> enrich || seo -> publish -> finalize) started
with workflow::start and polled with workflow::run_status, visualized live
with Svelte Flow.

FINDINGS.md / SECURITY.md capture every gap, surprise, and security issue
found (each tagged [PiCloud] vs [CMS]); the platform fixes for the
actionable ones ship in the preceding commit.

Also folds in the read-only `pic` allowlist entries added to
.claude/settings.json during the session (fewer-permission-prompts).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-19 20:15:29 +02:00

42 lines
1.6 KiB
Plaintext

// GET /cms/admin/workflow/runs/:id — one run's overall + per-step status, read
// straight from the platform via workflow::run_status (F-038). Replaces the
// former app-side `wfruns` KV tracking — the SDK is app-scoped, so a run from
// another app resolves to () (404) here.
import "auth" as auth;
let g = auth::guard(ctx, ["admin", "author"]);
if !g.ok { return g.response; }
let run_id = ctx.request.params.id;
let st = workflow::run_status(run_id);
if st == () { return #{ statusCode: 404, body: #{ error: "no such run" } }; }
let engine = st.status; // pending|running|succeeded|failed
let terminal = engine == "succeeded" || engine == "failed";
// Normalize per-step status for the UI. A DAG step absent from the run — its
// `when` gate was false — shows as skipped once the run is terminal, else
// pending; the engine's "ready" (queued) also maps to pending.
let steps = #{};
for name in ["validate", "enrich", "seo", "publish", "finalize"] {
let s = st.steps[name];
if s == () {
s = if terminal { "skipped" } else { "pending" };
} else if s == "ready" {
s = "pending";
}
steps[name] = #{ status: s };
}
// CMS-level overall: "blocked" when the gate stopped publish, else mirror the
// engine's terminal state (skip != fail, so the engine itself reports
// "succeeded" even when publish was gated out — F-039).
let overall_status = if !terminal {
"running"
} else if steps.publish.status == "succeeded" {
"completed"
} else {
"blocked"
};
#{ statusCode: 200, body: #{ run_id: run_id, overall: #{ status: overall_status }, steps: steps } }