docs(release): update contracts and docs for functional-completion changes
Add the new endpoints to contracts/openapi.yaml and docs/05-api-contract.md (return-preview, the four rule-specific data-quality resolution endpoints, search, integration status, scheduled-scan), document the role matrix and the audit before/after exposure in docs/12-security-and-audit.md, document each rule type's actual resolution flow in docs/07-data-quality.md (including the deliberate evidence-fingerprint simplification and the reopened_from/previous_decision recurrence link), document the preview/ commit relationship in docs/08-return-workflow.md, and update README.md's scope/integration-status/quality-gate sections to match what's actually implemented and verified now. Also drops docs/05-api-contract.md's mention of GET /api/v1/system/status, which was never implemented.
This commit is contained in:
@@ -16,14 +16,21 @@ All people, companies, vehicles, bookings and documents are synthetic. The workf
|
|||||||
|
|
||||||
The PoC implements:
|
The PoC implements:
|
||||||
|
|
||||||
- operations dashboard;
|
- operations dashboard with a truthful aggregate n8n/MCP integration-status card;
|
||||||
- vehicle and booking views;
|
- vehicle and booking views with working search, filters and pagination;
|
||||||
- one complete vehicle-return workflow;
|
- server-backed session lifecycle (refresh-safe, central 401 handling);
|
||||||
- five deterministic data-quality checks;
|
- a role matrix enforced server-side and mirrored in the UI (see
|
||||||
|
`docs/12-security-and-audit.md`);
|
||||||
|
- vehicle return capture → authoritative server-evaluated review → commit → result;
|
||||||
|
- five deterministic data-quality checks, each with a bounded resolution flow, plus a
|
||||||
|
manual scan action;
|
||||||
- human review and customer merge;
|
- human review and customer merge;
|
||||||
- audit trail;
|
- audit trail with human-readable before/after evidence and safe entity links;
|
||||||
|
- role-aware global search across vehicles, bookings and (Operations Manager) issues;
|
||||||
|
- safe, confirmed demo reset;
|
||||||
- RAGcore-backed knowledge assistant with citations;
|
- RAGcore-backed knowledge assistant with citations;
|
||||||
- one n8n return-processing workflow;
|
- two n8n workflows: return processing, and a scheduled data-quality scan with
|
||||||
|
crash-recoverable outbox delivery leases;
|
||||||
- four read-only MCP tools through ITWorx MCP Hub;
|
- four read-only MCP tools through ITWorx MCP Hub;
|
||||||
- deterministic demo reset and five-minute showcase.
|
- deterministic demo reset and five-minute showcase.
|
||||||
|
|
||||||
@@ -33,18 +40,26 @@ It is not an ERP, CRM, accounting package, public booking site, payment system o
|
|||||||
|
|
||||||
- **n8n**: fully implemented and verified against a real n8n instance, including
|
- **n8n**: fully implemented and verified against a real n8n instance, including
|
||||||
degraded mode (n8n stopped mid-flow → return still commits, event stays `pending`
|
degraded mode (n8n stopped mid-flow → return still commits, event stays `pending`
|
||||||
with backoff, self-heals once n8n returns) and the failed-delivery manual-retry path.
|
with backoff, self-heals once n8n returns), the failed-delivery manual-retry path,
|
||||||
|
stale-delivery-lease recovery after a simulated crash, and a second (scheduled
|
||||||
|
quality-scan) workflow live-verified end to end against a real n8n instance.
|
||||||
|
`GET /api/v1/integrations/status` reports a truthful aggregate state from outbox
|
||||||
|
delivery counts, not just the most recent event.
|
||||||
- **RAGcore**: the demo `KnowledgeProvider` (deterministic TF-IDF extractive retrieval
|
- **RAGcore**: the demo `KnowledgeProvider` (deterministic TF-IDF extractive retrieval
|
||||||
over the local procedure documents) is what satisfies the knowledge-assistant
|
over the local procedure documents) is what satisfies the knowledge-assistant
|
||||||
acceptance criteria and is fully verified. A `RAGcoreKnowledgeProvider` HTTP adapter is
|
acceptance criteria and is fully verified. A `RAGcoreKnowledgeProvider` HTTP adapter is
|
||||||
implemented and unit-tested, including its unavailable-degradation path, but was never
|
implemented and unit-tested, including its unavailable-degradation path, but was never
|
||||||
exercised against a live RAGcore instance in this environment.
|
exercised against a live RAGcore instance in this environment.
|
||||||
- **ITWorx MCP Hub**: the four read-only provider endpoints are implemented, tested, and
|
- **ITWorx MCP Hub**: the four read-only provider endpoints are implemented, tested, and
|
||||||
directly `curl`-verified with correct auth enforcement and audit logging. No live Hub
|
directly `curl`-verified with correct auth enforcement and audit logging.
|
||||||
instance was reachable in this environment to verify an actual Hub round trip.
|
`MCP_HUB_REGISTRATION_ENABLED` is now actually wired into `Settings` (it was previously
|
||||||
|
declared in `.env.example` but silently dropped) and reported honestly by the
|
||||||
|
integration-status endpoint. No live Hub instance was reachable in this environment to
|
||||||
|
verify an actual Hub round trip.
|
||||||
|
|
||||||
See `artifacts/final-acceptance/summary.md` for full verification evidence and exact
|
See `artifacts/functional-completion/final-summary.md` for the functional-completion
|
||||||
commands.
|
audit evidence (supersedes the design-validation summary below for integration status),
|
||||||
|
and `artifacts/final-acceptance/summary.md` for the original M0–M7 acceptance evidence.
|
||||||
|
|
||||||
## Repository map
|
## Repository map
|
||||||
|
|
||||||
@@ -60,6 +75,8 @@ commands.
|
|||||||
- `frontend/` — React/TypeScript/Vite web app, including the Playwright end-to-end suite (`frontend/e2e/`).
|
- `frontend/` — React/TypeScript/Vite web app, including the Playwright end-to-end suite (`frontend/e2e/`).
|
||||||
- `artifacts/evidence/` — final acceptance evidence (screenshots, architecture, `final-summary.md`).
|
- `artifacts/evidence/` — final acceptance evidence (screenshots, architecture, `final-summary.md`).
|
||||||
- `artifacts/design-validation/` — baseline audit, Stitch direction references and implemented responsive captures.
|
- `artifacts/design-validation/` — baseline audit, Stitch direction references and implemented responsive captures.
|
||||||
|
- `docs/functional-completion/` — the functional-completion audit and pre-work server baseline.
|
||||||
|
- `artifacts/functional-completion/` — functional-completion acceptance evidence.
|
||||||
|
|
||||||
## Quickstart
|
## Quickstart
|
||||||
|
|
||||||
@@ -83,9 +100,9 @@ All defaults are configurable via `.env` (see `.env.example`).
|
|||||||
## Quality gates
|
## Quality gates
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
make test # backend: pytest (66 tests)
|
make test # backend: pytest (117 tests)
|
||||||
make lint # backend: ruff + mypy (strict, zero errors)
|
make lint # backend: ruff + mypy (strict, zero errors)
|
||||||
make e2e # frontend: Playwright end-to-end (18 tests, live stack required)
|
make e2e # frontend: Playwright end-to-end (37 tests, live stack required)
|
||||||
```
|
```
|
||||||
|
|
||||||
Frontend build/typecheck: `cd frontend && npm run build` (`tsc -b && vite build`).
|
Frontend build/typecheck: `cd frontend && npm run build` (`tsc -b && vite build`).
|
||||||
|
|||||||
@@ -66,6 +66,26 @@ paths:
|
|||||||
responses:
|
responses:
|
||||||
'200':
|
'200':
|
||||||
description: Booking detail
|
description: Booking detail
|
||||||
|
/api/v1/bookings/{public_ref}/return-preview:
|
||||||
|
post:
|
||||||
|
operationId: previewVehicleReturn
|
||||||
|
description: >-
|
||||||
|
Non-mutating evaluation of what committing this return would do. Shares its
|
||||||
|
domain evaluation with the commit endpoint below so the two can never drift.
|
||||||
|
No writes, no audit event, no outbox event.
|
||||||
|
parameters:
|
||||||
|
- $ref: '#/components/parameters/PublicRef'
|
||||||
|
requestBody:
|
||||||
|
required: true
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/RegisterReturnRequest'
|
||||||
|
responses:
|
||||||
|
'200':
|
||||||
|
description: Authoritative evaluation of the resulting fleet state
|
||||||
|
'409':
|
||||||
|
description: Booking is not active
|
||||||
/api/v1/bookings/{public_ref}/return:
|
/api/v1/bookings/{public_ref}/return:
|
||||||
post:
|
post:
|
||||||
operationId: registerVehicleReturn
|
operationId: registerVehicleReturn
|
||||||
@@ -94,9 +114,17 @@ paths:
|
|||||||
/api/v1/data-quality/issues:
|
/api/v1/data-quality/issues:
|
||||||
get:
|
get:
|
||||||
operationId: listDataQualityIssues
|
operationId: listDataQualityIssues
|
||||||
|
description: Operations Manager only.
|
||||||
responses:
|
responses:
|
||||||
'200':
|
'200':
|
||||||
description: Quality issues
|
description: Quality issues
|
||||||
|
/api/v1/data-quality/scan:
|
||||||
|
post:
|
||||||
|
operationId: runDataQualityScan
|
||||||
|
description: Manual trigger for the deterministic five-rule scan. Operations Manager only.
|
||||||
|
responses:
|
||||||
|
'200':
|
||||||
|
description: Counts of newly created issues per rule type
|
||||||
/api/v1/data-quality/issues/{public_ref}/merge-customers:
|
/api/v1/data-quality/issues/{public_ref}/merge-customers:
|
||||||
post:
|
post:
|
||||||
operationId: mergeDuplicateCustomers
|
operationId: mergeDuplicateCustomers
|
||||||
@@ -107,6 +135,106 @@ paths:
|
|||||||
description: Merge completed
|
description: Merge completed
|
||||||
'409':
|
'409':
|
||||||
description: Issue no longer mergeable
|
description: Issue no longer mergeable
|
||||||
|
/api/v1/data-quality/issues/{public_ref}/provide-fields:
|
||||||
|
post:
|
||||||
|
operationId: provideMissingFields
|
||||||
|
description: >-
|
||||||
|
missing_required_field only. Resolves once nothing required remains missing;
|
||||||
|
otherwise leaves the issue open with updated evidence.
|
||||||
|
parameters:
|
||||||
|
- $ref: '#/components/parameters/PublicRef'
|
||||||
|
responses:
|
||||||
|
'200':
|
||||||
|
description: Issue after the update (may still be open)
|
||||||
|
'409':
|
||||||
|
description: Wrong rule type or issue not open
|
||||||
|
'422':
|
||||||
|
description: Disallowed field or empty value
|
||||||
|
/api/v1/data-quality/issues/{public_ref}/resolve-odometer-regression:
|
||||||
|
post:
|
||||||
|
operationId: resolveOdometerRegression
|
||||||
|
description: >-
|
||||||
|
odometer_regression only. Either retains the canonical odometer, or corrects a
|
||||||
|
related booking's reading -- a correction below the current canonical value is
|
||||||
|
rejected, since it would not resolve the regression.
|
||||||
|
parameters:
|
||||||
|
- $ref: '#/components/parameters/PublicRef'
|
||||||
|
responses:
|
||||||
|
'200':
|
||||||
|
description: Issue resolved
|
||||||
|
'409':
|
||||||
|
description: Wrong rule type or issue not open
|
||||||
|
'422':
|
||||||
|
description: Invalid booking reference or a correction below canonical
|
||||||
|
/api/v1/data-quality/issues/{public_ref}/resolve-overlap:
|
||||||
|
post:
|
||||||
|
operationId: resolveBookingOverlap
|
||||||
|
description: >-
|
||||||
|
booking_overlap only. Blocks one of the two overlapping bookings and
|
||||||
|
re-verifies no overlap remains before resolving.
|
||||||
|
parameters:
|
||||||
|
- $ref: '#/components/parameters/PublicRef'
|
||||||
|
responses:
|
||||||
|
'200':
|
||||||
|
description: Issue resolved
|
||||||
|
'409':
|
||||||
|
description: Wrong rule type, issue not open, or overlap still present
|
||||||
|
'422':
|
||||||
|
description: booking_ref not one of the overlapping bookings
|
||||||
|
/api/v1/data-quality/issues/{public_ref}/apply-recommended-status:
|
||||||
|
post:
|
||||||
|
operationId: applyRecommendedVehicleStatus
|
||||||
|
description: >-
|
||||||
|
vehicle_status_conflict only. Applies the one authoritative recommendation
|
||||||
|
function's output and re-validates before resolving.
|
||||||
|
parameters:
|
||||||
|
- $ref: '#/components/parameters/PublicRef'
|
||||||
|
responses:
|
||||||
|
'200':
|
||||||
|
description: Applied status, reason and the resolved issue
|
||||||
|
'409':
|
||||||
|
description: Wrong rule type, issue not open, or no conflict detected
|
||||||
|
/api/v1/search:
|
||||||
|
get:
|
||||||
|
operationId: search
|
||||||
|
description: >-
|
||||||
|
Bounded typed results (vehicle, booking, data_quality_issue, section).
|
||||||
|
Data-quality and manager-only sections are filtered server-side by role.
|
||||||
|
Customers are never returned -- no customer detail route exists.
|
||||||
|
parameters:
|
||||||
|
- in: query
|
||||||
|
name: q
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
minLength: 1
|
||||||
|
maxLength: 100
|
||||||
|
responses:
|
||||||
|
'200':
|
||||||
|
description: Search results
|
||||||
|
/api/v1/integrations/status:
|
||||||
|
get:
|
||||||
|
operationId: getIntegrationStatus
|
||||||
|
description: >-
|
||||||
|
Truthful aggregate n8n state derived from outbox delivery counts (not just the
|
||||||
|
most recent event), plus the actual MCP Hub registration_enabled setting.
|
||||||
|
Operations Manager only.
|
||||||
|
responses:
|
||||||
|
'200':
|
||||||
|
description: n8n and MCP Hub integration status
|
||||||
|
/api/v1/integrations/n8n/scheduled-scan:
|
||||||
|
post:
|
||||||
|
operationId: n8nScheduledScan
|
||||||
|
description: >-
|
||||||
|
Triggered by the scheduled n8n quality-scan workflow. Runs the same run_scan()
|
||||||
|
the manual UI action uses; idempotent by construction.
|
||||||
|
security:
|
||||||
|
- serviceToken: []
|
||||||
|
responses:
|
||||||
|
'200':
|
||||||
|
description: Counts of newly created issues per rule type
|
||||||
|
'401':
|
||||||
|
description: Invalid service token
|
||||||
/api/v1/knowledge/questions:
|
/api/v1/knowledge/questions:
|
||||||
post:
|
post:
|
||||||
operationId: askKnowledgeQuestion
|
operationId: askKnowledgeQuestion
|
||||||
|
|||||||
+40
-7
@@ -11,9 +11,10 @@ The demo may use signed server-issued sessions or short-lived JWTs. Demo-role bu
|
|||||||
### System and demo
|
### System and demo
|
||||||
|
|
||||||
- `GET /health`
|
- `GET /health`
|
||||||
- `GET /api/v1/system/status`
|
|
||||||
- `POST /api/v1/demo/login`
|
- `POST /api/v1/demo/login`
|
||||||
- `POST /api/v1/demo/reset` — Operations Manager only
|
- `GET /api/v1/demo/session` — confirms the current session; `Cache-Control: no-store`
|
||||||
|
- `POST /api/v1/demo/logout` — safe to call without a session
|
||||||
|
- `POST /api/v1/demo/reset` — Operations Manager only; invalidates the caller's own session
|
||||||
|
|
||||||
### Dashboard
|
### Dashboard
|
||||||
|
|
||||||
@@ -28,17 +29,37 @@ The demo may use signed server-issued sessions or short-lived JWTs. Demo-role bu
|
|||||||
|
|
||||||
- `GET /api/v1/bookings`
|
- `GET /api/v1/bookings`
|
||||||
- `GET /api/v1/bookings/{public_ref}`
|
- `GET /api/v1/bookings/{public_ref}`
|
||||||
|
- `POST /api/v1/bookings/{public_ref}/return-preview` — non-mutating; shares its domain
|
||||||
|
evaluation with the commit endpoint below so the two cannot drift apart
|
||||||
- `POST /api/v1/bookings/{public_ref}/return`
|
- `POST /api/v1/bookings/{public_ref}/return`
|
||||||
|
|
||||||
Return commands require an `Idempotency-Key` header and optimistic version where relevant.
|
Return commands require an `Idempotency-Key` header. Concurrency safety is row-lock based
|
||||||
|
(`SELECT ... FOR UPDATE` on the booking and vehicle); no optimistic-version field is
|
||||||
|
accepted or needed on top of that.
|
||||||
|
|
||||||
### Data quality
|
### Data quality
|
||||||
|
|
||||||
|
All Operations Manager only.
|
||||||
|
|
||||||
- `GET /api/v1/data-quality/issues`
|
- `GET /api/v1/data-quality/issues`
|
||||||
- `GET /api/v1/data-quality/issues/{public_ref}`
|
- `GET /api/v1/data-quality/issues/{public_ref}`
|
||||||
|
- `POST /api/v1/data-quality/scan` — manual trigger for the deterministic five-rule scan
|
||||||
- `POST /api/v1/data-quality/issues/{public_ref}/defer`
|
- `POST /api/v1/data-quality/issues/{public_ref}/defer`
|
||||||
- `POST /api/v1/data-quality/issues/{public_ref}/reject`
|
- `POST /api/v1/data-quality/issues/{public_ref}/reject`
|
||||||
- `POST /api/v1/data-quality/issues/{public_ref}/merge-customers`
|
- `POST /api/v1/data-quality/issues/{public_ref}/merge-customers` — possible_duplicate_customer
|
||||||
|
- `POST /api/v1/data-quality/issues/{public_ref}/provide-fields` — missing_required_field
|
||||||
|
- `POST /api/v1/data-quality/issues/{public_ref}/resolve-odometer-regression` — odometer_regression
|
||||||
|
- `POST /api/v1/data-quality/issues/{public_ref}/resolve-overlap` — booking_overlap
|
||||||
|
- `POST /api/v1/data-quality/issues/{public_ref}/apply-recommended-status` — vehicle_status_conflict
|
||||||
|
|
||||||
|
Each of the five rule types has exactly one bounded resolution path above (plus
|
||||||
|
defer/reject, which apply to any open issue).
|
||||||
|
|
||||||
|
### Search
|
||||||
|
|
||||||
|
- `GET /api/v1/search?q=...` — bounded typed results (vehicle, booking,
|
||||||
|
data_quality_issue, section); role-filtered server-side; customers are never returned
|
||||||
|
(no customer detail route exists in this PoC)
|
||||||
|
|
||||||
### Knowledge
|
### Knowledge
|
||||||
|
|
||||||
@@ -47,9 +68,21 @@ Return commands require an `Idempotency-Key` header and optimistic version where
|
|||||||
|
|
||||||
### Automation and audit
|
### Automation and audit
|
||||||
|
|
||||||
- `GET /api/v1/workflows`
|
- `GET /api/v1/workflows` — Operations Manager only
|
||||||
- `POST /api/v1/workflows/{event_id}/retry`
|
- `POST /api/v1/workflows/{event_id}/retry` — Operations Manager only
|
||||||
- `GET /api/v1/audit`
|
- `GET /api/v1/audit` — Operations Manager only; each event includes `before`/`after`
|
||||||
|
plus a resolved `entity_ref`/`entity_link` where the entity type supports one
|
||||||
|
- `GET /api/v1/integrations/status` — Operations Manager only; truthful aggregate n8n
|
||||||
|
state from outbox delivery counts (not just the most recent event), and the actual
|
||||||
|
MCP Hub `registration_enabled` setting
|
||||||
|
|
||||||
|
### n8n-service endpoints
|
||||||
|
|
||||||
|
Service-token protected (`X-Service-Token`, same shared secret as the return callback):
|
||||||
|
|
||||||
|
- `POST /api/v1/integrations/n8n/return-callback`
|
||||||
|
- `POST /api/v1/integrations/n8n/scheduled-scan` — triggered by the scheduled
|
||||||
|
quality-scan workflow; runs the same domain scan the manual UI action uses
|
||||||
|
|
||||||
### MCP-provider endpoints
|
### MCP-provider endpoints
|
||||||
|
|
||||||
|
|||||||
+26
-1
@@ -25,14 +25,29 @@ Merge rewires booking references, preserves the loser as a tombstone and audits
|
|||||||
|
|
||||||
Required for active customers: first name, last name and at least one of email or phone. Required for active vehicles: registration number, make, model and location.
|
Required for active customers: first name, last name and at least one of email or phone. Required for active vehicles: registration number, make, model and location.
|
||||||
|
|
||||||
|
Resolution: `POST /provide-fields` accepts only the fields the entity type actually
|
||||||
|
requires (rejects anything else), applies them, and re-runs the same missing-field check.
|
||||||
|
The issue resolves only once nothing required remains missing; a partial submission
|
||||||
|
updates the record and its evidence but leaves the issue open.
|
||||||
|
|
||||||
## DQ-03 Odometer regression
|
## DQ-03 Odometer regression
|
||||||
|
|
||||||
Flag an inspection or maintenance reading below the canonical odometer. Never lower the canonical value automatically.
|
Flag an inspection or maintenance reading below the canonical odometer. Never lower the canonical value automatically.
|
||||||
|
|
||||||
|
Resolution: `POST /resolve-odometer-regression` offers exactly two bounded decisions —
|
||||||
|
`retain_canonical` (the submitted reading is treated as erroneous; canonical is
|
||||||
|
untouched) or `correct_reading` (updates a named related booking's reading and the
|
||||||
|
vehicle's canonical odometer together). A `correct_reading` value below the current
|
||||||
|
canonical is rejected, since it would not resolve the regression, not silently applied.
|
||||||
|
|
||||||
## DQ-04 Booking overlap
|
## DQ-04 Booking overlap
|
||||||
|
|
||||||
Flag overlapping `reserved` or `active` bookings for one vehicle. Normal write APIs reject new overlaps; the seed/import path may create one controlled legacy conflict.
|
Flag overlapping `reserved` or `active` bookings for one vehicle. Normal write APIs reject new overlaps; the seed/import path may create one controlled legacy conflict.
|
||||||
|
|
||||||
|
Resolution: `POST /resolve-overlap` blocks one of the two named overlapping bookings
|
||||||
|
(minimal safe resolution, not a scheduling calendar) and re-verifies no
|
||||||
|
reserved/active overlap remains among the issue's related bookings before resolving.
|
||||||
|
|
||||||
## DQ-05 Vehicle status conflict
|
## DQ-05 Vehicle status conflict
|
||||||
|
|
||||||
Examples:
|
Examples:
|
||||||
@@ -42,6 +57,16 @@ Examples:
|
|||||||
- status `available` while critical open quality issue exists;
|
- status `available` while critical open quality issue exists;
|
||||||
- status `maintenance` with an active booking.
|
- status `maintenance` with an active booking.
|
||||||
|
|
||||||
|
Resolution: `POST /apply-recommended-status` computes a recommendation from one
|
||||||
|
authoritative function mirroring the conditions above, applies it, and re-runs the same
|
||||||
|
function to confirm the conflict is actually gone before resolving.
|
||||||
|
|
||||||
## Lifecycle
|
## Lifecycle
|
||||||
|
|
||||||
Detection is idempotent by `(rule_type, entity_type, entity_id, evidence fingerprint)` while open. Resolved issues remain historical. Reintroduced evidence creates a new issue linked to the prior issue where useful.
|
Detection is idempotent by `(rule_type, entity_type, entity_id)` while open — the CSV
|
||||||
|
seed rows don't carry a stable evidence fingerprint, so the literal
|
||||||
|
`(..., evidence fingerprint)` scheme from an earlier draft of this rule was dropped as
|
||||||
|
unworkable for seeded data; re-implementing it would need to reconcile with that. Resolved
|
||||||
|
issues remain historical. Reintroduced evidence creates a new issue whose evidence carries
|
||||||
|
`reopened_from` (the prior issue's reference) and `previous_decision` (its resolved
|
||||||
|
status), so a repeat problem is never presented as if no decision was ever made.
|
||||||
|
|||||||
@@ -1,5 +1,16 @@
|
|||||||
# Vehicle-return workflow
|
# Vehicle-return workflow
|
||||||
|
|
||||||
|
## Preview
|
||||||
|
|
||||||
|
`POST /api/v1/bookings/{public_ref}/return-preview` takes the same request body as the
|
||||||
|
commit endpoint below and runs the identical evaluation (`evaluate_return()`) with no
|
||||||
|
writes, no audit event and no outbox event — it exists so the UI's review step shows the
|
||||||
|
server's actual answer instead of guessing the outcome client-side. It returns the
|
||||||
|
canonical and submitted odometer readings, whether the submission is a regression, the
|
||||||
|
resulting vehicle status with a human-readable reason, whether a quality issue would be
|
||||||
|
created, and next-booking risk. `register_vehicle_return` (below) calls the same
|
||||||
|
`evaluate_return()` function, so preview and commit cannot drift apart.
|
||||||
|
|
||||||
## Input
|
## Input
|
||||||
|
|
||||||
- booking public reference;
|
- booking public reference;
|
||||||
|
|||||||
@@ -4,6 +4,30 @@
|
|||||||
|
|
||||||
Role buttons may create a session for a seeded demo identity. All API routes still enforce authorization. Demo reset and customer merge require Operations Manager.
|
Role buttons may create a session for a seeded demo identity. All API routes still enforce authorization. Demo reset and customer merge require Operations Manager.
|
||||||
|
|
||||||
|
The browser never treats its own cached copy of the logged-in user as authoritative:
|
||||||
|
`AuthContext` re-verifies against `GET /api/v1/demo/session` on every app load (that
|
||||||
|
response is `Cache-Control: no-store`, so a stale cached "authenticated" response can't
|
||||||
|
survive a logout), and a central 401 listener on the API client clears local auth state
|
||||||
|
from any endpoint, not just the session check. `POST /api/v1/demo/logout` and
|
||||||
|
`POST /api/v1/demo/reset` both invalidate the session cookie server-side.
|
||||||
|
|
||||||
|
## Role matrix
|
||||||
|
|
||||||
|
| Capability | Rental Employee | Operations Manager |
|
||||||
|
|---|---|---|
|
||||||
|
| Dashboard, fleet, vehicle detail, bookings, booking detail | yes | yes |
|
||||||
|
| Register a vehicle return | yes | yes |
|
||||||
|
| Knowledge assistant | yes | yes |
|
||||||
|
| Data-quality workbench (view, scan, all resolutions) | no | yes |
|
||||||
|
| Integrations / automation status and retry | no | yes |
|
||||||
|
| Audit trail | no | yes |
|
||||||
|
| Demo reset | no | yes |
|
||||||
|
|
||||||
|
Enforced server-side (every listed manager-only action returns `403` for Rental
|
||||||
|
Employee, verified by direct API tests, not just a hidden button) and mirrored in the
|
||||||
|
frontend nav (manager-only items are not rendered, not merely disabled) and route guards
|
||||||
|
(direct URL access shows a restricted message rather than partial data).
|
||||||
|
|
||||||
## Service authentication
|
## Service authentication
|
||||||
|
|
||||||
Use separate scoped credentials for:
|
Use separate scoped credentials for:
|
||||||
@@ -42,6 +66,13 @@ Required actions:
|
|||||||
|
|
||||||
Audit is append-only through the application. Provide filters by actor, action, entity and correlation ID.
|
Audit is append-only through the application. Provide filters by actor, action, entity and correlation ID.
|
||||||
|
|
||||||
|
`GET /api/v1/audit` (Operations Manager only) returns `before`/`after` for every event
|
||||||
|
(the columns already existed but were not serialized until this pass) plus a resolved
|
||||||
|
`entity_ref`/`entity_link` for vehicle, booking and data-quality-issue entities (no
|
||||||
|
customer link exists — no customer detail route). The UI shows a human-readable
|
||||||
|
before/after summary per row by default, with the raw before/after/metadata JSON behind
|
||||||
|
a `<details>` disclosure rather than shown unconditionally.
|
||||||
|
|
||||||
## Confirmation
|
## Confirmation
|
||||||
|
|
||||||
No write-capable MCP actions exist in this PoC. Destructive UI actions such as demo reset and customer merge require explicit confirmation.
|
No write-capable MCP actions exist in this PoC. Destructive UI actions such as demo reset and customer merge require explicit confirmation.
|
||||||
|
|||||||
Reference in New Issue
Block a user