UI-SP3 — Infrastructure & Governance (Executors / Audit / Quota / Settings)#21
Merged
Conversation
…/ Settings) Additive: 2 read endpoints (searchAuditLog already declared; new listExecutors in new file to satisfy lint_no_bearer_on_executor_routes) + 4 frontend pages (Settings is frontend-only). Zero migration; all 'designed-only' features (drain/restart, executor metrics history, HF-token rotate, license CRUD, quota usage history, real-time tail, ML forecast, chargeback PDF) explicitly deferred & documented. Inherits all UI-SP1/SP2 locked decisions. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
M1 backend (1 openapi extend+add, 2 endpoints w/ tests, gate), M2 frontend foundation (types, format utils, 3 composables, gate), M3 components (4 visual), M4 i18n parity + 4 pages + router/nav + full gate + headed smoke + docs. Complete code, no placeholders; grounded in verified on-disk contract + lint-rule placement constraints. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…review - Backend B1: policy.csv grants for /api/v1/audit* + /api/v1/executors* (tenant_admin/operator/viewer GET) — without these all auth'd tests 403 - Backend B2: src/dlw/main.py router-include is inside create_app() with `from dlw.api.X import router as X_router` — plan now spells exact patches - Contract sync: also extend openapi.yaml searchAuditLog response with the additive `next_cursor` field so static contract matches runtime DTO - Frontend BL-1: QuotaCard.spec.ts ran before i18n add → en.quotaPage was undefined → TypeError; inline expected key-path strings - Frontend IM-1: widen el-radio-group @update:model-value param to the full emit union to satisfy vue-tsc strict - Frontend IM-3: add :step=1 :precision=0 to el-input-number actor filter Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…ponse+searchAuditLog next_cursor) + policy.csv grants for audit/executors
…LiveResource seam
- HIGH: Audit "Load older" reused page-1's next_cursor → duplicate rows on the second click. Added an `olderCursor` ref watched off the live query's next_cursor (immediate=true) and advanced after each fetchOlderAudit; button gated by it; reset() clears it. Added a 3-row regression test that clicks twice and asserts cursor advances + button disappears at exhaustion. - MEDIUM: useAuditLog.buildQuery actor guard hardened from `!== null` to `typeof === 'number' && Number.isFinite(...)` so a stray undefined from el-input-number's clear path can't become `actor_user_id=undefined`. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Web UI sub-project 3 of 5 (after UI-SP1 = PR #19 and UI-SP2 = PR #20
de9573a). Full-stack but additive, zero Alembic migration (all columns already existed; onlypolicy.csvandopenapi.yamlextended additively).GET /api/v1/audit/log— tenant-scoped audit search (filters: action prefix, actor_user_id, from/to time range; cursor-paginated). Implements the already-declaredsearchAuditLogcontract (with an additivenext_cursorsynced intoopenapi.yaml).GET /api/v1/executors— browser-facing executor list (own-tenant + shared-infra;system_admin/is_servicesees all). Lives in a new modulesrc/dlw/api/executors_read.pybecause the existingapi/executors.pyis mTLS-only pertools/lint_invariants.py:check_no_bearer_on_executor_routes.openapi.yamlextendsExecutorReadadditively (4 required fields preserved + 7 nullable additions) and addsExecutorListResponse.policy.csv: 6 newtenant_matchGET grants for/api/v1/audit*and/api/v1/executors*across tenant_admin/operator/viewer./executors(host-grouped list + status filter),/audit(filterable + cursor pagination),/quota(3 cards over the existing/quota/current),/settings(frontend-only: principal info fromstores/session.ts, theme/locale toggles,/health/activewidget). All polling flows through the singleuseLiveResourceseam (with the SP2-addedenabledoption). No new runtime dep.policy.csvgrants;main.pyrouter-include idiom mismatch); final opus review caught 1 HIGH (Audit "Load older" cursor not advancing → duplicates on 2nd click) and 1 MEDIUM (actor_user_id undefined guard) — both fixed pre-merge with a new regression test.Verification
--max-warnings=0, vite build ok; en/zh locale parity test green.:8011controller (current SP3 code): 3 endpoints (audit/log, executors, quota/current) returned 200 with real data; all 4 pages rendered correctly with zh-CN locale, reallocal-host-worker-1 healthyexecutor, host grouping, Settings showed principal (user=1, tenant=1, role=tenant_admin), theme switch + locale radio + system section.Known follow-ups (non-blocking)
el-date-pickervalue-format="YYYY-MM-DDTHH:mm:ss[Z]"produces a literalZon a locally-rendered time → off-by-tz filter; acceptable for v1, proper tz-aware picker tracked./quota/usage; ML forecast; chargeback PDF; real-time audit tail (UI-SP5).Test plan
🤖 Generated with Claude Code