diff --git a/03-frontend/app/app/dev/api-lab/page.tsx b/03-frontend/app/app/dev/api-lab/page.tsx index 838357ab..485d6710 100644 --- a/03-frontend/app/app/dev/api-lab/page.tsx +++ b/03-frontend/app/app/dev/api-lab/page.tsx @@ -4,7 +4,7 @@ // License: Apache-2.0 import { useState } from 'react'; -import { ARCHITOKEN_API_BASE_URL } from '@/lib/backend-api'; +import { ARCHITOKEN_API_BASE_URL, setBackendRequestContext } from '@/lib/backend-api'; import { artifactClient, type Artifact } from '@/lib/artifact-client'; import { generationClient, type GenerationJob } from '@/lib/generation-client'; import { @@ -20,12 +20,16 @@ type RunState = 'idle' | 'loading' | 'error'; function describeError(error: unknown): string { if (typeof error === 'object' && error !== null && 'error' in error) { - return String((error as { error: unknown }).error); + return JSON.stringify(error, null, 2); } return error instanceof Error ? error.message : String(error); } export default function ApiLabPage() { + const [tenantId, setTenantId] = useState('dev-tenant'); + const [projectId, setProjectId] = useState('dev-project'); + const [actor, setActor] = useState('frontend-api-lab'); + const [rolesText, setRolesText] = useState('admin'); const [capabilities, setCapabilities] = useState(null); const [job, setJob] = useState(null); const [artifacts, setArtifacts] = useState([]); @@ -38,7 +42,22 @@ export default function ApiLabPage() { setLog((current) => [`${new Date().toISOString()} ${message}`, ...current].slice(0, 12)); }; + const applyContext = () => { + setBackendRequestContext({ + tenantId, + projectId, + actor, + roles: rolesText + .split(',') + .map((role) => role.trim()) + .filter(Boolean), + requestId: `api-lab-${actor}`, + correlationId: `api-lab-${tenantId}-${projectId}`, + }); + }; + const loadCapabilities = async () => { + applyContext(); setRunState('loading'); setErrorMessage(null); try { @@ -55,6 +74,7 @@ export default function ApiLabPage() { }; const runGenerationSequence = async () => { + applyContext(); setRunState('loading'); setErrorMessage(null); try { @@ -62,31 +82,31 @@ export default function ApiLabPage() { moduleId: 'digital_twin', mode: 'model_to_lightweight_scene', prompt: 'Create a local preview lightweight scene with property index and identity map.', - actor: 'frontend-api-lab', + actor, }); appendLog(`job created: ${created.id}`); const planned = await generationClient.plan(created.id, { - actor: 'frontend-api-lab', + actor, comment: 'plan from API lab', }); appendLog(`job planned: ${planned.status}`); const run = await generationClient.run(planned.id, { - actor: 'frontend-api-lab', + actor, comment: 'run local mock generator', }); appendLog(`job run: ${run.status}`); const reviewed = await generationClient.review(run.id, { - reviewer: 'frontend-api-lab', + reviewer: actor, decision: 'approved', comment: 'review accepted in API lab', }); appendLog(`job reviewed: ${reviewed.status}`); const approved = await generationClient.approve(reviewed.id, { - actor: 'frontend-api-lab', + actor, comment: 'approve generated preview artifacts', }); setJob(approved); @@ -105,6 +125,7 @@ export default function ApiLabPage() { }; const submitViewerCommand = async () => { + applyContext(); const artifact = artifacts[0]; if (!artifact) { appendLog('viewer command skipped: run generation first'); @@ -120,12 +141,12 @@ export default function ApiLabPage() { artifactId: artifact.id, elementIds: ['architoken:demo:001'], arguments: { color: '#ff6600' }, - actor: 'frontend-api-lab', + actor, }); appendLog(`viewer command created: ${created.id}`); const acked = await viewerCommandClient.ack(created.id, { - actor: 'frontend-api-lab', + actor, status: 'executed', comment: 'dev console executed command contract', result: { rendered: false, backendContractOnly: true }, @@ -146,7 +167,7 @@ export default function ApiLabPage() {

- Phase 5 Runtime Persistence E2E + Phase 6 Durable Store + RBAC

Backend API Lab

@@ -156,6 +177,48 @@ export default function ApiLabPage() {

API base: {ARCHITOKEN_API_BASE_URL}

+
+

Request Context

+
+ + + + +
+

+ Requests send X-Tenant-Id, X-Project-Id, X-Actor, X-Roles, X-Request-Id, and + X-Correlation-Id headers through the shared backend-api client. +

+
+