Files
support_backend/package.json
T
saqib mirandClaude Sonnet 5 8d5731340d feat: implement SaaS product integration trust boundary (US1 MVP)
Implements tasks T001-T020 from specs/002-saas-integration/tasks.md
(Setup, Foundational, and User Story 1 - the P1 MVP: every inbound
request is authenticated and trusted before anything happens).
User Story 2 (admin onboarding/rotation/revocation) and User Story 3
(rate limiting) are not yet implemented (T021-T032 remain).

Schema (prisma/schema.prisma + initial migration):
- Replace the placeholder Product model (leftover starter-template
  scaffolding: code/description/ProductStatus enum) with the real
  docs/06-database-schema.md shape (externalProductId,
  supportEnabled, status).
- Add ProductIntegration (credential ref, rotation/revocation state,
  allowed scope, per-integration/per-user rate limits) and
  CustomerReference models.
- Align AuditLog to docs/06's shape (actor/actorType/entityType/
  entityId/reason/metadata) -- the placeholder shape had no fields
  to satisfy this feature's audit requirements.

Auth:
- HMAC-signed short-lived tokens (issue/verify) with jti-based replay
  defense via Redis and a bounded clock-skew tolerance.
- Credential secrets are AES-256-GCM encrypted at rest (new required
  INTEGRATION_CREDENTIAL_ENCRYPTION_KEY env var) since no secret
  manager exists in this stack yet -- see research.md "Credential
  storage".
- New product-integration-auth.plugin.ts Fastify plugin runs the
  validation order in contracts/inbound-request-contract.md and
  populates request.reqContext only on full success; every attempt
  (success or failure) is audit-logged without ever persisting the
  raw token/credential. Unregistered product and invalid credential
  return an identical response (FR-010).
- New POST /v1/support/requests endpoint exercises the boundary
  end-to-end (ticket creation itself is a future feature).

Also:
- Fix docker-compose.test.yml's container_name collisions --
  discovered while testing this change concurrently is now covered
  by an app-level regression test (separate commit).
- Fix test:unit to scope to tests/unit only (it was running the
  entire tests/** glob including integration tests) -- this feature's
  new integration test makes real Prisma/Redis calls, unlike the
  prior instantiation-only checks, so the existing glob-scoping gap
  became actually harmful.
- Update Jenkinsfile with the new required credential.

Verified: full quality gate (typecheck/lint/format/architecture/
unit tests) passes; all of User Story 1's quickstart scenarios
manually verified end-to-end against a live server + Postgres +
Redis; the new integration test suite verified against a live
database (not run as part of `npm test`, matches existing
test:integration convention).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-21 18:40:43 +05:30

88 lines
4.0 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": {
"@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
}