Backend: - ConversationTracker: Protocol + PostgresConversationTracker for lifecycle tracking - Error handler: ErrorCategory enum, classify_error(), with_retry() exponential backoff - Wire PostgresAnalyticsRecorder + ConversationTracker into ws_handler - Rate limiting (10 msg/10s per thread), edge case hardening - Health endpoint GET /api/health, version 0.5.0 - Demo seed data script + sample OpenAPI spec Frontend (all new): - React Router with NavBar (Chat / Replay / Dashboard / Review) - ReplayListPage + ReplayPage with ReplayTimeline component - DashboardPage with MetricCard, range selector, zero-state - ReviewPage for OpenAPI classification review - ErrorBanner for WebSocket disconnect handling - API client (api.ts) with typed fetch wrappers Infrastructure: - Frontend Dockerfile (multi-stage node -> nginx) - nginx.conf with SPA routing + API/WS proxy - docker-compose.yml with frontend service + healthchecks - .env.example files (root + backend) Documentation: - README.md with quick start and architecture - Agent configuration guide - OpenAPI import guide - Deployment guide - Demo script 48 new tests, 449 total passing, 92.87% coverage
239 lines
5.8 KiB
YAML
239 lines
5.8 KiB
YAML
openapi: "3.0.3"
|
|
info:
|
|
title: "E-Commerce API"
|
|
description: "Sample e-commerce API for Smart Support demo."
|
|
version: "1.0.0"
|
|
|
|
servers:
|
|
- url: "https://api.example-shop.com/v1"
|
|
description: "Production server"
|
|
|
|
paths:
|
|
/orders/{order_id}:
|
|
get:
|
|
operationId: getOrder
|
|
summary: "Get order details"
|
|
description: "Retrieve the full details of a specific order."
|
|
parameters:
|
|
- name: order_id
|
|
in: path
|
|
required: true
|
|
schema:
|
|
type: string
|
|
responses:
|
|
"200":
|
|
description: "Order details"
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/Order"
|
|
|
|
/orders/{order_id}/cancel:
|
|
post:
|
|
operationId: cancelOrder
|
|
summary: "Cancel an order"
|
|
description: "Cancel an order that has not yet been shipped."
|
|
parameters:
|
|
- name: order_id
|
|
in: path
|
|
required: true
|
|
schema:
|
|
type: string
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
properties:
|
|
reason:
|
|
type: string
|
|
responses:
|
|
"200":
|
|
description: "Order cancelled"
|
|
"400":
|
|
description: "Order cannot be cancelled (already shipped)"
|
|
|
|
/orders/{order_id}/refund:
|
|
post:
|
|
operationId: refundOrder
|
|
summary: "Request a refund"
|
|
description: "Submit a refund request for a completed order."
|
|
parameters:
|
|
- name: order_id
|
|
in: path
|
|
required: true
|
|
schema:
|
|
type: string
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
properties:
|
|
amount:
|
|
type: number
|
|
description: "Refund amount in USD. Leave null for full refund."
|
|
reason:
|
|
type: string
|
|
responses:
|
|
"200":
|
|
description: "Refund submitted"
|
|
"400":
|
|
description: "Invalid refund request"
|
|
|
|
/customers/{customer_id}:
|
|
get:
|
|
operationId: getCustomer
|
|
summary: "Get customer profile"
|
|
description: "Retrieve customer profile and account information."
|
|
parameters:
|
|
- name: customer_id
|
|
in: path
|
|
required: true
|
|
schema:
|
|
type: string
|
|
responses:
|
|
"200":
|
|
description: "Customer profile"
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/Customer"
|
|
|
|
/customers/{customer_id}/orders:
|
|
get:
|
|
operationId: listCustomerOrders
|
|
summary: "List customer orders"
|
|
description: "Get a paginated list of orders for a customer."
|
|
parameters:
|
|
- name: customer_id
|
|
in: path
|
|
required: true
|
|
schema:
|
|
type: string
|
|
- name: page
|
|
in: query
|
|
schema:
|
|
type: integer
|
|
default: 1
|
|
- name: per_page
|
|
in: query
|
|
schema:
|
|
type: integer
|
|
default: 20
|
|
responses:
|
|
"200":
|
|
description: "List of orders"
|
|
|
|
/products/{product_id}:
|
|
get:
|
|
operationId: getProduct
|
|
summary: "Get product details"
|
|
description: "Retrieve product information including inventory status."
|
|
parameters:
|
|
- name: product_id
|
|
in: path
|
|
required: true
|
|
schema:
|
|
type: string
|
|
responses:
|
|
"200":
|
|
description: "Product details"
|
|
|
|
/support/tickets:
|
|
post:
|
|
operationId: createSupportTicket
|
|
summary: "Create support ticket"
|
|
description: "Open a new support ticket for a customer issue."
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/CreateTicketRequest"
|
|
responses:
|
|
"201":
|
|
description: "Ticket created"
|
|
|
|
/support/tickets/{ticket_id}:
|
|
get:
|
|
operationId: getSupportTicket
|
|
summary: "Get support ticket"
|
|
description: "Retrieve a support ticket and its conversation history."
|
|
parameters:
|
|
- name: ticket_id
|
|
in: path
|
|
required: true
|
|
schema:
|
|
type: string
|
|
responses:
|
|
"200":
|
|
description: "Ticket details"
|
|
|
|
components:
|
|
schemas:
|
|
Order:
|
|
type: object
|
|
properties:
|
|
order_id:
|
|
type: string
|
|
customer_id:
|
|
type: string
|
|
status:
|
|
type: string
|
|
enum: [pending, processing, shipped, delivered, cancelled, refunded]
|
|
items:
|
|
type: array
|
|
items:
|
|
$ref: "#/components/schemas/OrderItem"
|
|
total_usd:
|
|
type: number
|
|
created_at:
|
|
type: string
|
|
format: date-time
|
|
|
|
OrderItem:
|
|
type: object
|
|
properties:
|
|
product_id:
|
|
type: string
|
|
name:
|
|
type: string
|
|
quantity:
|
|
type: integer
|
|
unit_price_usd:
|
|
type: number
|
|
|
|
Customer:
|
|
type: object
|
|
properties:
|
|
customer_id:
|
|
type: string
|
|
email:
|
|
type: string
|
|
name:
|
|
type: string
|
|
tier:
|
|
type: string
|
|
enum: [standard, premium, vip]
|
|
created_at:
|
|
type: string
|
|
format: date-time
|
|
|
|
CreateTicketRequest:
|
|
type: object
|
|
required: [customer_id, subject, description]
|
|
properties:
|
|
customer_id:
|
|
type: string
|
|
subject:
|
|
type: string
|
|
description:
|
|
type: string
|
|
priority:
|
|
type: string
|
|
enum: [low, medium, high, urgent]
|
|
default: medium
|