diff --git a/src/Web/StellaOps.Web/AGENTS.md b/src/Web/StellaOps.Web/AGENTS.md index 7adfec816..adc2e90d5 100644 --- a/src/Web/StellaOps.Web/AGENTS.md +++ b/src/Web/StellaOps.Web/AGENTS.md @@ -87,6 +87,17 @@ Design and build the StellaOps web user experience that surfaces backend capabil - 4. Coordinate doc updates, tests, and cross-guild communication whenever contracts or workflows change. - 5. Revert to `TODO` if you pause the task without shipping changes; leave notes in commit/PR descriptions for context. +## No Mockups Convention (MANDATORY) + +All UI components **must** connect to real backend API endpoints. Never use `window.confirm()`, mock data services, or stub implementations unless explicitly requested by the product owner. + +**Rules:** +- Every button, form submission, and action handler must call a real API endpoint +- If the backend endpoint doesn't exist yet, mark the task `BLOCKED` — do not create a mock +- The in-memory mock clients (e.g., `InMemoryApprovalClient`) exist ONLY for `ng serve` without backends, never as production implementations +- Error states from API failures must be surfaced to the user (never silently swallow errors) +- If an API returns 404/500, show the error in a banner or toast — don't pretend the action succeeded + ## Destructive Action Convention (MANDATORY) All destructive actions (delete, revoke, purge, reset) **must** use `` — never `window.confirm()` or unguarded inline handlers. diff --git a/src/Web/StellaOps.Web/src/app/core/api/approval.client.ts b/src/Web/StellaOps.Web/src/app/core/api/approval.client.ts index f3686f45f..37352ecfb 100644 --- a/src/Web/StellaOps.Web/src/app/core/api/approval.client.ts +++ b/src/Web/StellaOps.Web/src/app/core/api/approval.client.ts @@ -32,8 +32,8 @@ export interface ApprovalApi { @Injectable() export class ApprovalHttpClient implements ApprovalApi { private readonly http = inject(HttpClient); - private readonly queueBaseUrl = '/api/v2/releases/approvals'; - private readonly detailBaseUrl = '/api/v1/approvals'; + private readonly queueBaseUrl = '/api/v1/release-orchestrator/approvals'; + private readonly detailBaseUrl = '/api/v1/release-orchestrator/approvals'; listApprovals(filter?: ApprovalFilter): Observable { const params: Record = {}; @@ -78,20 +78,16 @@ export class ApprovalHttpClient implements ApprovalApi { } approve(id: string, comment: string): Observable { - return this.http.post(`${this.detailBaseUrl}/${id}/decision`, { - action: 'approve', + return this.http.post(`${this.detailBaseUrl}/${id}/approve`, { comment, - actor: 'ui-operator', }).pipe( map(row => this.mapV2ApprovalDetail(row)) ); } reject(id: string, comment: string): Observable { - return this.http.post(`${this.detailBaseUrl}/${id}/decision`, { - action: 'reject', + return this.http.post(`${this.detailBaseUrl}/${id}/reject`, { comment, - actor: 'ui-operator', }).pipe( map(row => this.mapV2ApprovalDetail(row)) ); diff --git a/src/Web/StellaOps.Web/src/app/features/releases/releases-activity.component.ts b/src/Web/StellaOps.Web/src/app/features/releases/releases-activity.component.ts index 6026d28af..8efb64d2a 100644 --- a/src/Web/StellaOps.Web/src/app/features/releases/releases-activity.component.ts +++ b/src/Web/StellaOps.Web/src/app/features/releases/releases-activity.component.ts @@ -72,7 +72,7 @@ function deriveOutcomeIcon(status: string): string { @if (pendingApprovals().length > 0 && viewMode() !== 'approvals') { -
+