Real Anthropic Claude integration per explicit product decision: a ticket's AI session diagnoses the problem via a structured-output call, applies a DB-configurable confidence-band policy (FR-005), and on "proceed" reasons and acts through a small permission/risk-gated tool system (FR-011/FR-012), optionally walking a matching runbook step by step with the application — never the model — owning the step index (FR-015/FR-016). Resolution requires real tool evidence, never customer claims alone (FR-018) — verifyProductResolution is a documented fail-closed placeholder mirroring the existing malware-scanner precedent, since no real per-product operational signal exists yet. AISupportSession.status mirrors onto Ticket.status through 003-ticketing's existing AI_ANALYZING/AI_TROUBLESHOOTING/AI_VERIFYING/AI_RESOLVED/ HUMAN_ESCALATION state machine, discovered during planning to have been built anticipating this exact feature. Two circular module dependencies (escalation<->sessions, tools<->sessions) were designed around rather than found as bugs: escalation is a pure summary formatter with no state dependencies of its own, and tools stays a clean leaf module with zero dependency on ai-support/sessions. Ticket creation enqueues the first diagnosis turn via the existing queue infrastructure (off the hot path of the inbound SaaS integration endpoint); a human actor changing ticket status ends the AI session via the event-bus scaffold that existed in this codebase but had never been wired to anything. A real Prisma limitation was found and fixed before it reached tests: compound-unique upsert rejects null for a nullable key column, so AIConfidencePolicy uses find-then-update/create instead, same fix class 004 already used for the same underlying limitation. Adds 9 unit tests (confidence-band, tool-policy-gate, runbook-step- advance) and 6 integration test files, including the two constitution- required standing E2E scenarios. AI-independent tests were run against real Postgres/Redis/MinIO (88 passed, 0 failed across the full suite, including every pre-existing 002/003/004 test). The AI-dependent tests compile and skip cleanly via describe.skipIf but were not run against a live model — no ANTHROPIC_API_KEY was available in this session; a real key must be supplied before this feature can actually run. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
89 lines
4.1 KiB
JSON
89 lines
4.1 KiB
JSON
{
|
|
"name": "supporthub-api",
|
|
"version": "1.0.0",
|
|
"description": "SupportHub API — Production Enterprise Modular Monolith API",
|
|
"main": "dist/server.js",
|
|
"scripts": {
|
|
"dev": "tsx watch --env-file=.env.development src/server.ts",
|
|
"development": "tsx watch --env-file=.env.development src/server.ts",
|
|
"dev:env": "tsx watch --env-file=.env.development src/server.ts",
|
|
"build": "prisma generate && tsc -p tsconfig.build.json && tsc-alias -p tsconfig.build.json",
|
|
"build:development": "prisma generate && tsc -p tsconfig.build.json && tsc-alias -p tsconfig.build.json",
|
|
"build:test": "prisma generate && tsc -p tsconfig.build.json && tsc-alias -p tsconfig.build.json",
|
|
"build:prod": "prisma generate && tsc -p tsconfig.build.json && tsc-alias -p tsconfig.build.json",
|
|
"start": "node dist/src/server.js",
|
|
"start:dev": "node --env-file=.env.development dist/src/server.js",
|
|
"start:test": "node --env-file=.env.test dist/src/server.js",
|
|
"start:prod": "node --env-file=.env.prod dist/src/server.js",
|
|
"typecheck": "tsc --noEmit",
|
|
"architecture:check": "tsx scripts/check-architecture.ts",
|
|
"lint": "eslint \"src/**/*.ts\" \"tests/**/*.ts\" \"scripts/**/*.ts\"",
|
|
"lint:fix": "eslint \"src/**/*.ts\" \"tests/**/*.ts\" \"scripts/**/*.ts\" --fix",
|
|
"format": "prettier --write \"src/**/*.ts\" \"tests/**/*.ts\" \"scripts/**/*.ts\" \"prisma/**/*.ts\"",
|
|
"format:check": "prettier --check \"src/**/*.ts\" \"tests/**/*.ts\" \"scripts/**/*.ts\" \"prisma/**/*.ts\"",
|
|
"test": "npm run test:unit",
|
|
"test:unit": "vitest run tests/unit",
|
|
"test:watch": "vitest",
|
|
"test:env": "vitest run --env-file=.env.test",
|
|
"test:integration": "vitest run tests/integration",
|
|
"test:e2e": "vitest run tests/e2e",
|
|
"test:concurrency": "vitest run tests/concurrency",
|
|
"test:coverage": "vitest run --coverage",
|
|
"prisma:generate": "prisma generate",
|
|
"prisma:migrate": "prisma migrate dev",
|
|
"prisma:deploy": "prisma migrate deploy",
|
|
"prisma:seed": "tsx prisma/seed/index.ts",
|
|
"openapi:generate": "tsx scripts/generate-openapi.ts",
|
|
"docker:up:dev": "docker compose --env-file .env.development -f docker-compose.development.yml up -d",
|
|
"docker:down:dev": "docker compose --env-file .env.development -f docker-compose.development.yml down",
|
|
"docker:up:test": "docker compose --env-file .env.test -f docker-compose.test.yml up -d",
|
|
"docker:down:test": "docker compose --env-file .env.test -f docker-compose.test.yml down",
|
|
"docker:up:prod": "docker compose --env-file .env.prod -f docker-compose.prod.yml up -d",
|
|
"docker:down:prod": "docker compose --env-file .env.prod -f docker-compose.prod.yml down",
|
|
"docker:build:dev": "docker compose --env-file .env.development -f docker-compose.development.yml build",
|
|
"docker:build:test": "docker compose --env-file .env.test -f docker-compose.test.yml build",
|
|
"docker:build:prod": "docker compose --env-file .env.prod -f docker-compose.prod.yml build"
|
|
},
|
|
"dependencies": {
|
|
"@anthropic-ai/sdk": "^0.123.0",
|
|
"@aws-sdk/client-s3": "^3.556.0",
|
|
"@aws-sdk/s3-request-presigner": "^3.556.0",
|
|
"@fastify/cors": "^9.0.1",
|
|
"@fastify/helmet": "^11.1.1",
|
|
"@fastify/rate-limit": "^9.1.0",
|
|
"@fastify/swagger": "^8.14.0",
|
|
"@fastify/swagger-ui": "^3.0.0",
|
|
"@opentelemetry/api": "^1.8.0",
|
|
"@opentelemetry/sdk-trace-base": "^1.22.0",
|
|
"@prisma/client": "^5.12.1",
|
|
"bullmq": "^5.7.1",
|
|
"dotenv": "^16.4.5",
|
|
"fastify": "^4.26.2",
|
|
"fastify-plugin": "^4.5.1",
|
|
"ioredis": "^5.3.2",
|
|
"pino": "^8.20.0",
|
|
"pino-pretty": "^11.0.0",
|
|
"prom-client": "^15.1.1",
|
|
"zod": "^3.22.4"
|
|
},
|
|
"devDependencies": {
|
|
"@types/node": "^20.12.7",
|
|
"@typescript-eslint/eslint-plugin": "^7.6.0",
|
|
"@typescript-eslint/parser": "^7.6.0",
|
|
"eslint": "^8.57.0",
|
|
"eslint-config-prettier": "^9.1.0",
|
|
"husky": "^9.0.11",
|
|
"lint-staged": "^15.2.2",
|
|
"prettier": "^3.2.5",
|
|
"prisma": "^5.12.1",
|
|
"tsc-alias": "^1.9.2",
|
|
"tsx": "^4.7.2",
|
|
"typescript": "^5.4.5",
|
|
"vitest": "^1.5.0"
|
|
},
|
|
"engines": {
|
|
"node": ">=20.0.0"
|
|
},
|
|
"private": true
|
|
}
|