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:
NuklearRabbit
2026-08-02 07:10:37 +02:00
parent e115031a57
commit c981aad2a3
6 changed files with 266 additions and 21 deletions
+30 -13
View File
@@ -16,14 +16,21 @@ All people, companies, vehicles, bookings and documents are synthetic. The workf
The PoC implements:
- operations dashboard;
- vehicle and booking views;
- one complete vehicle-return workflow;
- five deterministic data-quality checks;
- operations dashboard with a truthful aggregate n8n/MCP integration-status card;
- vehicle and booking views with working search, filters and pagination;
- server-backed session lifecycle (refresh-safe, central 401 handling);
- 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;
- 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;
- 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;
- 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
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
over the local procedure documents) is what satisfies the knowledge-assistant
acceptance criteria and is fully verified. A `RAGcoreKnowledgeProvider` HTTP adapter is
implemented and unit-tested, including its unavailable-degradation path, but was never
exercised against a live RAGcore instance in this environment.
- **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
instance was reachable in this environment to verify an actual Hub round trip.
directly `curl`-verified with correct auth enforcement and audit logging.
`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
commands.
See `artifacts/functional-completion/final-summary.md` for the functional-completion
audit evidence (supersedes the design-validation summary below for integration status),
and `artifacts/final-acceptance/summary.md` for the original M0M7 acceptance evidence.
## Repository map
@@ -60,6 +75,8 @@ commands.
- `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/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
@@ -83,9 +100,9 @@ All defaults are configurable via `.env` (see `.env.example`).
## Quality gates
```bash
make test # backend: pytest (66 tests)
make test # backend: pytest (117 tests)
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`).
+128
View File
@@ -66,6 +66,26 @@ paths:
responses:
'200':
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:
post:
operationId: registerVehicleReturn
@@ -94,9 +114,17 @@ paths:
/api/v1/data-quality/issues:
get:
operationId: listDataQualityIssues
description: Operations Manager only.
responses:
'200':
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:
post:
operationId: mergeDuplicateCustomers
@@ -107,6 +135,106 @@ paths:
description: Merge completed
'409':
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:
post:
operationId: askKnowledgeQuestion
+40 -7
View File
@@ -11,9 +11,10 @@ The demo may use signed server-issued sessions or short-lived JWTs. Demo-role bu
### System and demo
- `GET /health`
- `GET /api/v1/system/status`
- `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
@@ -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/{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`
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
All Operations Manager only.
- `GET /api/v1/data-quality/issues`
- `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}/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
@@ -47,9 +68,21 @@ Return commands require an `Idempotency-Key` header and optimistic version where
### Automation and audit
- `GET /api/v1/workflows`
- `POST /api/v1/workflows/{event_id}/retry`
- `GET /api/v1/audit`
- `GET /api/v1/workflows` — Operations Manager only
- `POST /api/v1/workflows/{event_id}/retry` — Operations Manager only
- `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
+26 -1
View File
@@ -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.
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
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
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
Examples:
@@ -42,6 +57,16 @@ Examples:
- status `available` while critical open quality issue exists;
- 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
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.
+11
View File
@@ -1,5 +1,16 @@
# 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
- booking public reference;
+31
View File
@@ -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.
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
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.
`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
No write-capable MCP actions exist in this PoC. Destructive UI actions such as demo reset and customer merge require explicit confirmation.