98 Commits
Author SHA1 Message Date
saqib mirandClaude Sonnet 5 20e5493798 docs(016-load-concurrency-testing): polish — findings, task completion
Documents implementation-time findings in the requirements checklist: all
three suspected races were confirmed real then fixed, the ticket-status
mechanism needed no fix, a real pre-existing test-infrastructure issue
(throwaway DB ticket-code collisions at high accumulated volume) was found
and resolved by resetting the throwaway database and replaying its full
migration history, two full-suite-only integration failures were confirmed
as pre-existing cross-file contamination (not a regression), and the
load-test tooling surfaced a real Anthropic API cost consideration for
ticket creation itself. All 23 tasks marked complete.

Full quality gate green: typecheck, lint, architecture check, full unit
suite (119/119), full integration suite against a freshly reset throwaway
database (122/124 — the 2 failures are the project's own already-accepted
MinIO baseline), and all 6 concurrency test files (11/11).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-10 12:14:16 +05:30
saqib mirandClaude Sonnet 5 8400a8db84 feat(016-load-concurrency-testing): US5 — autocannon load-test tooling
tests/load/autocannon.config.ts is a thin shared wrapper over autocannon's
programmatic API producing this feature's own report shape (throughput,
latency p50/p90/p99, non-2xx, rate-limited count) — printed and written to
tests/load/reports/ (gitignored) for every run. No pass/fail threshold is
applied (FR-009): throughput/latency targets are an OPEN BUSINESS DECISION
per the roadmap's own convention, never invented.

Three scripts cover the named critical endpoint groups: ticket-creation
(pure DB path), admin-reporting (015-reporting-dashboards, pure DB path),
and ai-support-flow (005-ai-support's real Anthropic API calls — clearly
flagged as real, billed cost, run only at a small bounded amount rather than
an open-ended duration). All three were run once at a small scale against the
real dev server to confirm the tooling works end-to-end and cleans up fully
after itself (verified via direct DB checks, not just script exit codes).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-10 11:50:12 +05:30
saqib mirandClaude Sonnet 5 cd8e408d7e test(016-load-concurrency-testing): US4 — prove ticket status optimistic concurrency
tests/concurrency/ticket-status-race.test.ts fires 20 genuinely concurrent
TicketsRepository.updateStatus calls from the same starting version against
real Postgres. Passes on the first run, confirming (rather than assuming)
003-ticketing's existing atomic version-checked updateMany already holds
under real concurrency — no implementation change needed (research.md §4).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-10 11:19:24 +05:30
saqib mirandClaude Sonnet 5 c7aac460b7 test(016-load-concurrency-testing): US3 — prove escalation idempotency holds
tests/concurrency/escalation-idempotency.test.ts fires the same escalation
trigger (escalationService.handleBreach) concurrently more than once for the
same ticket against real Postgres, asserting exactly one EscalationEvent and
one current Assignment result every time — verified across 10 repeated runs
(SC-003). The database-level unique-violation is visibly caught and absorbed
in the logs, confirming the fix (previous commit) actually engages under a
genuine race rather than being untested code.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-10 11:17:31 +05:30
saqib mirandClaude Sonnet 5 93d6fe8b94 fix(016-load-concurrency-testing): US3 — finish escalation idempotency plumbing
Completes the escalation-event repository/service changes from the prior
commit: normalizes the exactOptionalPropertyTypes mismatch in the
findFirst fallback lookup, and updates every existing unit test
(sla-pause-resume, sla-breach-detection, sla-compliance-metric,
escalation-rule-match) to the new SlaRunRepository.updateWithVersion and
EscalationEventRepository.create({event, wasNewlyCreated}) signatures.
Full typecheck/lint/architecture-check clean.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-10 11:13:46 +05:30
saqib mir 794e16f349 create the specf document 2026-09-09 17:39:12 +05:30
saqib mirandClaude Sonnet 5 0e3543bb01 fix(016-load-concurrency-testing): US2 — version-guard SLA pause/resume/sweep
SlaRunRepository.updateWithVersion replaces the old unguarded update(),
mirroring TicketsRepository.updateStatus's exact atomic-updateMany pattern.
pause/resume/complete now retry (bounded) against fresh state on a version
conflict; the breach sweep skips a run that lost the race to a concurrent
pause/resume/complete rather than clobbering it, deferring to the next
scheduled pass. Verified against real Postgres: concurrent pause/resume/sweep
activity against the same run now always leaves it in one
internally-consistent state, across repeated runs.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-09 17:17:09 +05:30
saqib mirandClaude Sonnet 5 58d0a98134 fix(016-load-concurrency-testing): US1 — retry assignment creation on race conflict
AssignmentRepository.createAssignment now catches the
assignments_one_current_per_ticket unique-violation and retries the whole
supersede-then-create transaction (bounded, with jitter) instead of
propagating a raw P2002 to the caller. Verified against real Postgres: before
this fix, 20 genuinely concurrent assignment attempts on the same ticket
reliably threw an unhandled unique-constraint error; after it, exactly one
current assignment results every time across 10 repeated runs.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-09 17:10:10 +05:30
saqib mirandClaude Sonnet 5 1e332143bd build(016-load-concurrency-testing): T001-T002 setup + concurrency-guard migration
Adds autocannon as a devDependency for the load-test tooling (T001), and the
shared schema migration T002 blocks: SLARun.version for optimistic
concurrency, plus two Postgres partial unique indexes
(assignments_one_current_per_ticket, escalation_events_ticket_rule_unique)
guarding against the assignment and escalation races research.md documents.
Applied directly to both the real dev DB and the throwaway test DB.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-09 17:03:37 +05:30
saqib mirandClaude Sonnet 5 2fb5b7ac73 tasks(016-load-concurrency-testing): break down into 23 tasks across 5 stories
Foundational phase (T002) covers the one shared schema migration US1/US2/US3
depend on; US4 (proof-only, no schema change) and US5 (load-test tooling)
have no dependency on it and can proceed independently.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-09 16:57:09 +05:30
saqib mirandClaude Sonnet 5 015ef62b71 plan(016-load-concurrency-testing): design assignment/SLA/escalation race fixes
research.md nails down the exact mechanism for each real race the audit
found: a partial unique index for assignment double-assignment, a
Ticket-style version counter for SLA pause/resume/sweep, and a partial
unique index for escalation-rule idempotency — each traced to the specific
repository/service code that has the gap today. data-model.md and plan.md
carry the resulting schema and repository-contract changes; quickstart.md
defines the real-infra verification steps for each user story.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-09 16:55:32 +05:30
saqib mirandClaude Sonnet 5 9f52d51003 spec(016-load-concurrency-testing): specify concurrency-safety and load testing scope
Five user stories: assignment double-assignment race, SLA pause/resume race,
escalation idempotency, ticket optimistic-concurrency proof, and HTTP
load/throughput testing tooling. Scoped from a targeted audit of existing
concurrency guarantees rather than guesswork — see spec.md's Assumptions.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-09 16:51:00 +05:30
saqib mirandClaude Sonnet 5 7106753ed3 fix(015-reporting-dashboards): count humanEscalated by Assignment existence, not status
ManagementRepository/ProductReportRepository.countEverEscalatedToHuman checked
a list of terminal statuses that ticket-state-machine.ts's own transition
table shows are reachable from BOTH the AI-resolved path and the
human-escalation path once they converge (RESOLUTION_PENDING_CUSTOMER,
RESOLVED, CLOSED, REOPENED). Every AI-resolved ticket was being double-counted
as human-escalated too — confirmed live against real seeded dev data
(humanEscalated: 34 out of totalCases: 34, an impossible 100%).

Fixed by keying off assignments: { some: {} } instead, since
orchestrationService.handleHumanEscalation is the only code path that ever
creates an Assignment row. Updated management-dashboard.test.ts's own
human-resolved fixture to create a real Assignment row, since it previously
relied on the now-fixed buggy status-based signal without one.

Found via manual verification against a real running dev server while
building supporthub-web's 002-reporting-dashboards-ui, not by any existing
automated test.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-09 16:31:13 +05:30
saqib mirandClaude Sonnet 5 d65683641a feat(015-reporting-dashboards): four real reporting/analytics endpoints
Wires the pre-scaffolded, unused platform/reports module (ReportsService
.generateSummaryReport previously returned {}) into four real, admin-
gated dashboards matching docs/09-testing-observability-cicd.md's own
table:

- GET /admin/reports/management: total cases, AI-resolved, human-
  escalated, resolved/open, SLA compliance/breaches, escalation count,
  average response/resolution time.
- GET /admin/reports/product/:externalProductId: support volume,
  problem-category breakdown, recurring problems, AI-resolution/human-
  escalation rate, top error codes.
- GET /admin/reports/support: current per-agent workload, SLA at-risk/
  breached counts, escalation count, response/resolution performance.
- GET /admin/reports/ai: AI resolution/human-handoff rate, failed-
  troubleshooting-then-escalated rate, knowledge-match rate, confidence
  distribution (reusing 005-ai-support's own decideConfidenceBand),
  tool invocation success/failure.

Every rate/average is number|null -- null means no qualifying data in
range, never a computed NaN or a misleading 0. Adds one new durable
table, ErrorCodeLookup, since 014-full-observability's own equivalent
metric is a process-lifetime Prometheus counter unusable for a
historical "top errors" report.

Verified end-to-end against real Postgres/Redis: every figure checked
against hand-computed expected values, including a no-activity range
(all-zero counts, all-null rates) and cross-product isolation.

Also fixes a real regression the new ErrorCodeLookup FK caused in the
pre-existing known-issues.test.ts (its afterAll deleted ErrorCode rows
before the now-referencing lookup rows).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-09 11:59:38 +05:30
saqib mirandClaude Sonnet 5 814d9d7b17 docs(015-reporting-dashboards): task breakdown
28 tasks across a shared Foundational phase (schema, config, shared
rate/date-range helpers, module scaffolding) and 4 independently-testable
dashboard user stories.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-09 11:15:22 +05:30
saqib mirandClaude Sonnet 5 4a159725c2 docs(015-reporting-dashboards): plan, research, data model, contract, quickstart
Documents the exact Prisma query per dashboard figure, the one new
durable table this feature needs (ErrorCodeLookup — 014's own equivalent
metric is process-lifetime, unusable for a historical report), the
"no data -> null, never NaN" convention, and why the AI dashboard's
confidence distribution deliberately uses the system-default threshold
rather than resolving a per-diagnosis policy (AIDiagnosis has no
reliable FK back to which policy applied).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-09 11:14:29 +05:30
saqib mirandClaude Sonnet 5 c4a2faa6e3 docs(015-reporting-dashboards): feature spec and quality checklist
Phase 11's third sub-area (reporting/analytics dashboards), per explicit
user direction. Backend-first scope (four read-only aggregation
endpoints wiring up the pre-scaffolded platform/reports module),
following the same backend-before-frontend pattern already established
for 010/011/014 this session — a supporthub-web dashboard UI is a
separate, not-yet-started follow-on.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-09 11:10:00 +05:30
saqib mirandClaude Sonnet 5 ea50e3596a test(014-full-observability): fix cross-file contamination + polish
business-metrics.test.ts's "human resolution" case drove a ticket
through a real HUMAN_ESCALATION transition via ticketsService.updateStatus,
which triggers the real orchestration subscriber's default ROUND_ROBIN
auto-assignment against every agent in the shared throwaway database —
reproduced deterministically landing on agent-ticket-queue.test.ts's own
dedicated agent. Fixed by driving the intermediate transitions directly
through ticketsRepository.updateStatus (no domain-event publish),
reserving the real, event-publishing call for only the final RESOLVED
transition the metric subscriber needs to observe.

Also documents (checklist Notes), without fixing, a separate pre-existing
issue confirmed unrelated to this feature via git checkout to the clean
013-auth-hardening tip: nearly every integration test file's product ID
collapses to the same 4-letter ticket-code prefix ("TEST"), so enough
concurrent TEST_*-prefixed files can exceed the fixed retry ceiling on
ticket-code generation and surface as a real 500 — a 003-ticketing
concern, out of scope here.

Marks all 30 tasks.md items complete.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-08 16:27:56 +05:30
saqib mirandClaude Sonnet 5 de5915a8c1 feat(014-full-observability): remaining business metrics (first response, resolution, SLA, errors, tools)
Completes User Story 4's eleven named metrics: first-response-time
(messages.service.ts's post(), guarded against double-counting a
ticket's second agent message), SLA compliance (sla.service.ts's
complete()/runBreachDetectionSweep(), with a guard so a run already
breached by the sweep is never also counted "met" when it later
resolves), most-common-errors (error-codes.service.ts, counted only
once a code is confirmed real), and tool-failure-rate/knowledge-
effectiveness (tools.service.ts's single executeTool call site).

Verified end-to-end against real Postgres/Redis by scraping the real
/metrics endpoint before and after driving each metric's actual
underlying event through the real service layer — including a genuine
tool-execution failure (a nonexistent ticket ID) rather than a
simulated one.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-08 15:57:47 +05:30
saqib mirandClaude Sonnet 5 f75589d9ce feat(014-full-observability): real distributed tracing + first 5 business metrics
User Story 3: initializes a real OpenTelemetry TracerProvider (previously
inert — getTracer() returned a no-op tracer with nothing ever exported).
Adds ticket.create, ai.escalation, and orchestration.assignment spans
covering both FR-006 cross-module paths, verified via a real, in-memory
test exporter that confirms actual trace/parent-span nesting, not mocked.

Also registers an AsyncLocalStorageContextManager
(@opentelemetry/context-async-hooks) — without one, OTel's context API is
a no-op that doesn't propagate across the await boundaries this feature's
own event-bus subscribers rely on for span nesting; caught by the first
version of the tracing integration test actually failing on real
parent/child assertions, not assumed.

Graceful degradation (FR-007) verified against a real, deliberately
unreachable OTLP endpoint: the SDK's own background export path (what
production actually exercises) never produces an unhandled rejection.

Starts on the 11 named business-health metrics: AI session
resolved/escalated outcomes (session.repository.ts, the single choke
point every branch in session.service.ts funnels through), human-vs-AI
resolution + resolution-time (a new TICKET_UPDATED/RESOLVED subscriber),
escalation rate (a new subscriber on ESCALATION_TRIGGERED, published
unconditionally since 008 but never previously consumed), and recurring
problems (tickets.service.ts's existing problem-creation call site).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-08 11:32:14 +05:30
saqib mirandClaude Sonnet 5 acd3843aaf feat(014-full-observability): per-request access log + live request-duration metric
User Stories 1-2: every completed request (including 404s and early
replies from other hooks) now emits exactly one structured access-log
line, and every log line produced during that request's handling shares
its requestId/correlationId via a new AsyncLocalStorage-backed Pino mixin
— with zero changes to any existing log call site. The previously-dead
supporthub_http_request_duration_seconds histogram now actually receives
observations, so error rate and latency per route are computable from
/metrics alone.

Also bumps @opentelemetry/sdk-trace-base 1.x -> 2.x to align with the two
new tracing dependencies added in this same branch (exporter-trace-otlp-http,
resources) onto one consistent major version — npm had otherwise installed
two incompatible OTel core/resources majors side by side, which also
happened to resolve a moderate DoS advisory in @opentelemetry/core <2.8.0.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-08 11:12:14 +05:30
saqib mirandClaude Sonnet 5 0135e4ca05 docs(014-full-observability): task breakdown
30 tasks across 4 independently-testable user stories plus a shared
foundational phase (ALS request-context store + new OTel dependencies).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-08 10:52:26 +05:30
saqib mirandClaude Sonnet 5 5a0fe9f847 docs(014-full-observability): plan, research, data model, contract, quickstart
Documents the exact hook point chosen for each of the 3 dead observability
primitives (access log, request-duration histogram, tracer provider) and
the 11 named business-health metrics, verified against the real current
code rather than assumed — including a pre-existing SLA-run status data
quality gap surfaced along the way (documented, not fixed here).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-08 10:51:22 +05:30
saqib mirandClaude Sonnet 5 09ba56d3af docs(014-full-observability): feature spec and quality checklist
Phase 11's second sub-area (full observability), per explicit user
direction. Scopes wiring the already-scaffolded logging/metrics/tracing
into something actually functional, explicitly bounded away from the
separate, not-yet-started reporting/analytics dashboards sub-area.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-07 21:31:38 +05:30
saqib mirandClaude Sonnet 5 79bc2ef25b feat(013-auth-hardening): password reset, password strength policy, login rate-limiting
Closes the two gaps 010-identity-auth explicitly deferred (password reset,
login rate-limiting), plus a shared password-strength validator both the
reset-consume endpoint and admin account creation now depend on.

- Password reset: single-use, paired-Redis-key tokens (never in Postgres),
  identical response regardless of account existence, stubbed delivery via
  a structured log line (no email infrastructure exists yet).
- Password strength: one validatePasswordStrength() call site, wired into
  both POST /admin/users and the reset-consume flow.
- Login rate-limiting: checkRateLimit keyed by submitted email, checked
  before any credential verification.

Also fixes tests/helpers/auth.ts's shared loginAs() helper, which reused
two fixed accounts across the whole integration suite via upsert — now
rate-limited per email, that collided across ~30 files sharing one budget.
Each call now gets a unique email; no call sites needed to change.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-07 21:22:49 +05:30
saqib mirandClaude Sonnet 5 3bdccc901f test(011-agent-ticket-queue): harden afterAll against wildcard SLA policy contamination
Same class of cross-file test-isolation gap already fixed in
orchestration-flow.test.ts and sla-escalation-flow.test.ts (010's own
regression work): a wildcard (non-product-scoped) SLA policy from
another suite can match this file's own tickets too, leaving a real
sla_run row that RESTRICTs the ticket delete. Also cleaned up several
orphaned wildcard SLA policies that had accumulated in the shared
throwaway test database from earlier runs.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-07 17:33:52 +05:30
saqib mirandClaude Sonnet 5 65175a85b5 docs(013-auth-hardening): task breakdown
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-07 17:27:27 +05:30
saqib mirandClaude Sonnet 5 52f1fa3db0 docs(013-auth-hardening): plan, research, data model, contract, quickstart
Reset tokens live only in Redis as a paired key shape (mirrors 010's own
revocation-denylist pattern) - never in Postgres, never storing the raw
token. Password-strength policy is one shared validator called from both
the new reset-consume endpoint and 010's existing POST /admin/users.
Login rate-limiting reuses the existing checkRateLimit helper from
002's own inbound trust boundary, keyed by submitted email, checked
before any credential verification.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-07 17:26:49 +05:30
saqib mirandClaude Sonnet 5 b016e77b70 docs(013-auth-hardening): spec for password reset, password policy, login rate-limiting
Phase 11's "security hardening pass" (docs/10-implementation-roadmap.md),
first slice, per explicit user direction. Closes the two concrete gaps
010-identity-auth's own Assumptions named as out of its scope. MFA is
intentionally excluded as its own larger follow-up feature. Email
delivery for password-reset is stubbed (server-side log) per explicit
user decision, since this codebase has no email infrastructure at all
today.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-07 17:23:49 +05:30
saqib mirandClaude Sonnet 5 700daf4104 feat(012-admin-list-views): GET /admin/escalation-policies now includes each policy's rules
Follow-up to 012-admin-list-views, discovered while building
supporthub-web's own escalation admin screen (001-agent-admin-ui User
Story 5): the list endpoint returned bare policies with no way to read
back which rules (trigger type, target node) already existed under
each one.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-07 16:42:25 +05:30
saqib mirandClaude Sonnet 5 249e7cd0ce feat(012-admin-list-views): GET /admin/business-calendars/:id now includes holidays
Follow-up to 012-admin-list-views, discovered while building
supporthub-web's own SLA/calendar admin screen (001-agent-admin-ui User
Story 4): holidays could only be added or removed, never read back -
GET /admin/business-calendars/:id returned the bare calendar with no
way to display what holidays were already on file. The repository
already had findByIdWithHolidays; it just wasn't wired to this route.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-07 16:40:00 +05:30
saqib mirandClaude Sonnet 5 2034966d6d docs(012-admin-list-views): note the knowledge-governance follow-up
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-07 16:35:47 +05:30
saqib mirandClaude Sonnet 5 7948182988 feat(012-admin-list-views): add GET /admin/products/:id/knowledge for governance
Follow-up to 012-admin-list-views, discovered while building supporthub-
web's own knowledge-governance screen (001-agent-admin-ui User Story 7):
GET /knowledge/retrieve only ever returns published entries (its own
AI-consumption purpose), so a governance screen that needs to see and
publish a draft entry had no endpoint to list it. Adds a small
admin-list-views-style read query scoped to the knowledge module itself.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-07 16:35:25 +05:30
saqib mirandClaude Sonnet 5 3bd068b031 feat(012-admin-list-views): SLA-run, escalation-event, and product-catalog list endpoints
Adds GET /admin/sla-runs (filterable by status), GET /admin/escalation-
events (capped, most-recent-first), and GET /admin/products (with
integration status joined in, never the full ProductIntegration row).
None of these existed as a single query before - only per-ticket or
per-integration-id lookups did.

Discovered while planning supporthub-web's 001-agent-admin-ui User
Stories 6-7 (SLA/escalation monitoring, product catalog), the same way
011-agent-ticket-queue was discovered for User Story 1.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-07 16:31:20 +05:30
saqib mirandClaude Sonnet 5 43158ff0c4 docs(012-admin-list-views): task breakdown
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-07 16:14:52 +05:30
saqib mirandClaude Sonnet 5 2b00b6d6a1 docs(012-admin-list-views): plan, research, data model, contract, quickstart
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-07 16:14:25 +05:30
saqib mirandClaude Sonnet 5 49db40d7c1 docs(012-admin-list-views): spec for SLA-run, escalation-event, and product-catalog list endpoints
Discovered while planning supporthub-web's 001-agent-admin-ui User
Stories 6-7: no endpoint lists SLA runs or escalation events across
multiple tickets (only per-ticket), and no endpoint returns the product
catalog with integration status joined in.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-07 16:12:21 +05:30
saqib mirandClaude Sonnet 5 fb9606b6aa feat(011-agent-ticket-queue): link agents to accounts, list assigned tickets
Extends PATCH /admin/agents/:agentId with an optional userId to finally
wire Agent.userId (added in 010-identity-auth as schema-only, never
consumed by any workflow), with proactive role/duplicate-link checks
mirroring UsersService.create's own pre-check style.

Adds GET /agents/me/tickets and GET /admin/agents/:agentId/tickets,
sharing one TicketsService.listAssignedTo method, returning a dashboard-
ready summary (product, customer, priority, severity, status, SLA state)
of every ticket currently assigned to an agent — no such query existed
anywhere in the ticketing or orchestration modules before this. Backed by
a new Assignment @@index([agentId, isCurrent]).

Discovered while starting supporthub-web's 001-agent-admin-ui: its agent-
dashboard user story had no backend data source without this.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-07 13:19:13 +05:30
saqib mirandClaude Sonnet 5 d574af087a docs(011-agent-ticket-queue): task breakdown
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-07 13:00:35 +05:30
saqib mirandClaude Sonnet 5 23fadebb5c docs(011-agent-ticket-queue): plan, research, data model, contract, quickstart
Extends the existing PATCH /admin/agents/:agentId with an optional userId
to finish wiring 010's Agent.userId link, and adds GET /agents/me/tickets
+ GET /admin/agents/:agentId/tickets sharing one ticketing/tickets service
method, backed by a new Assignment @@index([agentId, isCurrent]).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-07 12:58:25 +05:30
saqib mirandClaude Sonnet 5 d58bc98c7f docs(011-agent-ticket-queue): spec for agent-user linking and assigned-ticket listing
Discovered while starting supporthub-web's 001-agent-admin-ui planning:
its agent-dashboard user story needs to list tickets currently assigned
to an agent, and no such query exists anywhere in the ticketing or
orchestration modules. Also finishes wiring Agent.userId (added in
010-identity-auth as schema-only, never consumed by any workflow) so a
logged-in session can resolve to its own agent roster row at all.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-07 12:55:41 +05:30
saqib mirandClaude Sonnet 5 40687f68fa feat(010-identity-auth): real staff login, session verification, and role gating
Replaces the no-op fastify.authenticate stub and the never-implemented
identity/auth login with real bcrypt password verification, JWT session
issuance/verification (reusing the existing JWT_SECRET), and a Redis-backed
revocation denylist for logout. Adds requireRole('ADMIN') to admin-only
configuration writes across 002-009 that previously relied on a decorator
that never actually checked anything. Adds self-identity (GET /auth/me,
re-validated against live account state) and admin-provisioned accounts
(POST /admin/users).

Making the auth check genuinely reject invalid/missing tokens exposed that
~18 pre-existing integration test files called already-gated routes with no
Authorization header (safe against the old no-op stub, broken against a real
one) — fixed via a shared tests/helpers/auth.ts (loginAs/authHeader) and a
file-by-file pass, plus two related SLA-run cleanup races exposed once admin
setup calls in those files' own beforeAll blocks started actually succeeding.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-07 12:45:37 +05:30
saqib mirandClaude Sonnet 5 8327fafac2 tasks: task breakdown for identity and authentication feature (010)
36 tasks across 8 phases (5 user stories + setup/foundational/polish).
US1 (real login) and US2 (real route/role gating) are the P1 MVP; the
one task that touches code outside identity/* (T020, adding
requireRole('ADMIN') across 002-009's existing admin routes) is called
out explicitly to run each touched module's own test suite immediately
after, not only in the final regression pass.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-07 11:15:45 +05:30
saqib mirandClaude Sonnet 5 3b4c220a45 plan: design for identity and authentication feature (010)
Phase 0 research resolves the library choices (jsonwebtoken + bcryptjs,
chosen partly to avoid native-build friction on Windows dev
environments), the Redis-backed revocation-denylist shape (reusing
002's own jti-replay-protection pattern exactly), a 4-hour token
lifetime, and why fastify.authenticate populating the already-shared
reqContext.actorId/actorType retroactively makes every audit trail
since 007 accurate for real agent/admin actions instead of always
'unknown'.

Also surfaces and scopes a real gap found along the way: User (login
identity) and Agent (routing/skills profile) have never been linked.
Adds Agent.userId as a nullable FK now (cheap, additive) without
building the actual linking workflow, which belongs in 006's own
identity/agents admin screens as a later, separate piece of work.

Phase 1 adds data-model.md, the login/self-identity/account-creation/
logout contract, and five quickstart scenarios including a specific
requirement to re-verify at least one already-shipped admin route per
module (002-009), not just this feature's own new endpoints.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-07 11:14:42 +05:30
saqib mirandClaude Sonnet 5 a49389dc2c docs: spec for identity and authentication (010)
Not on the original roadmap -- surfaced as a genuine blocking gap while
planning supporthub-web's own agent/admin UI feature: fastify.authenticate
has been a complete no-op stub since 002, and identity/auth's login
endpoint has never taken a password. User/UserRole (two seeded-but-
passwordless demo accounts) and the AuthUser/JwtPayload types were all
already scaffolded and clearly intended for exactly this -- this finishes
that original wiring rather than inventing a new design.

Scope: real login (password hash + JWT), fastify.authenticate actually
rejecting invalid sessions, role-based route gating, a self-identity
endpoint, admin-created accounts, and logout. Password reset, MFA, and
login rate-limiting are explicitly deferred to Phase 11's own security
hardening pass.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-07 11:09:46 +05:30
saqib mir 4e0c90e2cf fix 2026-09-03 16:48:27 +05:30
saqib mir d9bd970910 have add tthe port number 2026-09-03 16:40:19 +05:30
saqib mirandClaude Sonnet 5 16daf8d32d feat: implement problem resolution (009)
Populates the five real problem-management stubs (investigation,
root-causes, solutions, verification, resolutions -- problems is
confirmed dead/unwired scaffold and stays untouched) with doc04's
sequential workflow engine:

- investigation: version-row-per-attempt (never overwritten), with a
  customer-safe read path that always strips internalNotes.
- root-causes/solutions/verification: a strict existence chain
  (investigation -> root cause -> solution -> approval -> implementation
  -> verification), each step resolve-or-409 on its own precondition,
  matching doc06's schema field-for-field with no invented columns.
- resolutions: gated on a successfully verified solution (no stored
  solutionId FK, per doc06 -- resolved via a join at write time), moving
  the ticket to RESOLUTION_PENDING_CUSTOMER; explicit customer
  confirmation and a durable auto-close sweep (the previously-unregistered
  CLEANUP queue stub, mirroring 008's breach-detection job) both resolve
  it from there.
- reopen (ticketing/tickets): two real, separately-audited transitions
  (RESOLVED|CLOSED -> REOPENED -> IN_PROGRESS), touching no prior
  problem-resolution record and no SLARun -- closes the loop 008's own
  spec.md left open.

Verification-failure escalation reuses 003/007's existing
HUMAN_ESCALATION transition directly rather than adding an eleventh
trigger type to 008's already-shipped escalation rules.

Customer-facing confirm-resolution/reopen needed a body-shape variant of
002's inbound trust boundary that didn't previously exist:
fastify.authenticateProductIntegration hard-required a full
ticket-creation-shaped body. Extracted the shared token/scope/replay
verification into verifyIntegrationIdentity and added a narrower
authenticateProductIntegrationIdentity decorator + identityOnlyRequestSchema
on top of it -- purely additive, ticket creation's own behavior is
unchanged.

Also fixes a real test-data-hygiene bug surfaced by running this
feature's suite alongside 008's: a wildcard-scoped HierarchyNode and an
intentionally-global SLAPolicy in 008's own test fixtures were silently
affecting other test files' tickets sharing the same live Postgres.

Verified against throwaway Docker Postgres/Redis: typecheck, lint,
architecture-check all clean; full regression (tests/unit +
tests/integration together, 172 tests) passes except the 2 pre-existing
MinIO-dependent attachment failures, unrelated to this feature.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-03 15:09:29 +05:30
saqib mirandClaude Sonnet 5 aaa51ef475 tasks: task breakdown for problem resolution feature (009)
49 tasks across 9 phases (6 user stories + setup/foundational/polish).
Unlike 007/008, this feature's user stories are genuinely sequential
(doc04's own investigation -> root cause -> solution -> verification ->
resolution -> reopen chain), so each story's dependency on the last is
real, not just priority-driven ordering -- called out explicitly since
User Story 4 (P2, verification) is a structural prerequisite of User
Story 5 (P1, resolution) despite the lower priority label.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-03 14:39:11 +05:30
saqib mirandClaude Sonnet 5 9ce34d8ca4 plan: design for problem resolution feature (009)
Phase 0 research resolves module placement (problem-management/problems
confirmed dead/unwired, left untouched), Investigation's version-row-per-
attempt shape, the strict investigation->root-cause->solution->
implementation->verification existence chain, why Resolution has no
solutionId FK (matches doc06 exactly), why verification-failure
escalation reuses 003/007's plain HUMAN_ESCALATION transition instead of
adding an eleventh trigger type to 008's already-shipped escalation
rules, the customer-facing route design (reusing 002's inbound trust
boundary rather than fastify.authenticate), and the auto-close sweep
design (the already-defined-but-unused CLEANUP queue, mirroring 008's
breach-detection job).

Phase 1 adds data-model.md, the admin/customer-facing contract, and six
quickstart scenarios covering the full sequential workflow through
customer confirmation, auto-close, and reopen.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-03 14:37:42 +05:30
saqib mirandClaude Sonnet 5 14c6793460 docs: spec for problem resolution feature (009)
Investigation -> Root Cause -> Solution -> Implementation ->
Verification -> Resolution, plus customer confirmation and reopen,
matching doc04 SS3-9's workflow narrative and doc06's "Domain: Problem
Resolution" schema exactly. Explicitly closes a loop 008's own spec left
open (reopen never restarts an SLA run); verification-failure escalation
reuses 003/007's existing HUMAN_ESCALATION transition rather than adding
an eleventh escalation-rule trigger type to 008's system.

Also documents a real scope-boundary finding: src/modules/problem-management/problems
is a dead, unwired duplicate scaffold for Problem (the real one has lived
in ticketing/tickets since 003) and is not touched by this feature -- only
the five investigation/root-causes/solutions/resolutions/verification
stub directories are.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-03 14:33:55 +05:30
saqib mir 7e3d2ae29f add the new feaures 2026-09-03 14:19:21 +05:30
saqib mirandClaude Sonnet 5 9357f03e1d feat: implement SLA and escalation (008)
Populates platform/business-calendars, orchestration/sla, and
orchestration/escalation (all thin stubs until now) with the real engine:

- business-calendars: a luxon-based day-by-day calendar walk
  (addBusinessMinutes/isWithinWorkingHours) excluding non-working hours,
  weekends, and holidays — replacing the naive createdAt+hours stub FR-004
  explicitly forbids.
- sla: most-specific SLAPolicy resolution (product/category/problemType/
  priority, wildcard-or-exact-match, specificity-count + updatedAt
  tiebreak), SLARun creation on the first real publish of the
  long-unused TICKET_ASSIGNED domain event, durable pause/resume via an
  absolute-timestamp shift (no in-memory state, verified across a real
  buildApp() restart), and a repeatable BullMQ breach-detection sweep
  (src/jobs/sla, itself a previously-unregistered stub) that is directly
  callable for tests, not only reachable through a running worker.
- escalation: EscalationPolicy/Rule CRUD (all 10 doc05 trigger types
  storable, only resolution_breach/first_response_breach evaluated),
  breach-triggered and manual escalation both funnel through one EscalationEvent
  + scoped re-assignment path. AssignmentEngine (007) gains
  assignToSpecificNode — a new, explicitly node-scoped entry point,
  since escalation must never let 007's general resolution re-derive a
  different node than the one a rule or a caller targeted.

Two small pre-existing scaffold gaps were closed along the way:
CategoriesRepository had no findById, and TICKET_ASSIGNED/SLA_BREACHED/
ESCALATION_TRIGGERED were defined since earlier phases but never
published by any code.

Verified against throwaway Docker Postgres/Redis (typecheck, lint,
architecture-check all clean; 148/150 relevant tests pass — the 2
failures are pre-existing, MinIO-dependent, and unrelated to this
feature).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-03 13:02:05 +05:30
saqib mirandClaude Sonnet 5 bb31e9d641 tasks: task breakdown for SLA and escalation feature (008)
48 tasks across 9 phases (6 user stories + setup/foundational/polish),
sequenced US1 (policy definition) -> US2 (calendar-aware run creation) ->
US3 (durable pause/resume, P1-complete MVP) -> US4 (breach detection) ->
US5 (breach-triggered escalation) -> US6 (manual escalation), each
dependent on the last since every story builds on the previous one's
mechanism rather than being independently orderable.

Also folds in two design refinements found while cross-checking the
existing scaffold against research.md's plan: TICKET_ASSIGNED (defined in
domain-events.ts since 007, never published) becomes the real wiring point
for SLA-run creation, and src/jobs/sla//src/jobs/escalation/ turn out to
already exist as their own stub scaffolding, reused rather than
duplicated.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-03 12:27:40 +05:30
saqib mirandClaude Sonnet 5 199bd4eb4e plan: design for SLA and escalation feature (008)
Phase 0 research resolves the business-calendar working-hours algorithm
(day-by-day walk via luxon, the first date/timezone dependency in this
codebase), the workingHours JSON shape, most-specific SLA-policy match
(reusing 005/006's resolution pattern), durable pause/resume (absolute
due-date shift, no in-memory state), and a repeatable-job breach-detection
design over per-run delayed jobs. Phase 1 adds data-model.md (one additive
refinement beyond doc06: SLARun.firstResponseBreachedAt), the admin/read
contract, and six quickstart scenarios including a genuine process-restart
boundary test for Constitution Principle VII.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-03 12:23:35 +05:30
saqib mirandClaude Sonnet 5 1ad9007e79 docs: spec for SLA and escalation feature (008)
Phase 8 of the roadmap: SLA policy engine (most-specific-match, calendar-
aware due dates), durable pause/resume and breach detection (never an
in-memory timer), and a rule-driven escalation engine that re-assigns via
007's engine scoped to a specific target node. Bounded to the two
SLA-derived trigger types this feature can compute a real signal for;
the other eight doc 05 §6 trigger types remain valid rule configuration
without a wired event source yet. First feature to give 006's
HierarchyNode.slaPolicyId/escalationPolicyId fields a real target.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-03 12:16:05 +05:30
saqib mir 3ecca06307 merged solved 2026-09-03 12:01:26 +05:30
saqib mirandClaude Sonnet 5 77928c4878 feat: implement orchestration and assignment (007) — routing, strategies, history
Phase 7 of the roadmap. On a ticket's automatic transition to
HUMAN_ESCALATION, routing resolves 006's hierarchy nodes and
capability-eligibility lookup directly (never a second matching
algorithm), and a pluggable strategy (ROUND_ROBIN, concurrency-safe via
atomic Redis INCR; LEAST_LOADED; SKILL_BASED) selects exactly one
eligible agent, persisted as a version-row-per-period Assignment plus an
append-only AssignmentHistory event log. MANUAL/DIRECT are never
auto-selected — only an explicit admin-supplied agentId reaches them.
On success the ticket moves HUMAN_ESCALATION -> IN_PROGRESS through
003's existing state machine. A ticket's "required skill" comes from
its most recent AI diagnosis's problemType (005) when one exists,
unioned with any matching hierarchy node's skills (006); when neither
exists, there's no skill constraint (every active agent eligible),
never zero.

Found and fixed two real, latent bugs in the shared event-bus
infrastructure while building this feature's own tests: (1)
EventBus.publish was built on EventEmitter.emit(), which never awaits
async listeners, so a caller had no guarantee any subscriber (005's
AI-session-ending hook, now also this feature's orchestration hook) had
actually finished — rewritten to track subscribers directly and await
them via Promise.all, same per-handler error isolation as before. (2)
registerDomainEventHandlers() was only called from server.ts's
production startup path, never from buildApp() — meaning every
integration test in this codebase had zero domain-event subscribers
registered at all. Now called (idempotently) from buildApp() itself,
since domain-event wiring is synchronous application behavior, not a
background-worker concern like the queue.

Adds 8 unit tests (each strategy's pure selection/tie-break logic), a
dedicated round-robin concurrency test verifying no two concurrent
selections collide under real parallel load, and 2 integration test
files covering all five user stories. Full regression (every
pre-existing 002-006 integration test plus every new 007 test) run
together against real Postgres/Redis/MinIO: 124 passed, 9 skipped
(005's AI-key-gated tests, unrelated), 0 failed.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-03 11:58:17 +05:30
saqib mirandClaude Sonnet 5 d3d57b9954 docs: correct 007-orchestration-assignment design on required-skill sourcing
Neither Ticket nor Problem carries a skill/problem-type field — the
only real signal is AIDiagnosis.problemType (005), and only for
tickets that went through AI support first. Resolves this before
implementation: use that diagnosis when available, fall back to no
skill constraint (not zero eligible agents) otherwise, matching FR-004's
explicit "rather than failing" and 006's own empty-scope-matches-
everything convention.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-03 11:32:49 +05:30
saqib mirandClaude Sonnet 5 67eee83ff0 docs: task breakdown for orchestration and assignment feature
34 tasks across setup, foundational schema work, and five user stories
(automatic resolution, pluggable strategies with a dedicated concurrency
test, durable history, manual assignment, and re-escalation
verification). Notes the T021/T017 sequencing exception where an
implementation dependency crosses story-priority order.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-03 11:31:30 +05:30
saqib mirandClaude Sonnet 5 846b9e8dca docs: plan and design artifacts for orchestration and assignment feature
Maps the feature onto the three existing orchestration/{routing,
assignments,orchestration} scaffold stubs. Key decisions: Assignment
refined as a version-row-per-period model (paired with a separate
append-only AssignmentHistory event log), round-robin concurrency
safety via atomic Redis INCR (reusing existing infra, not a new one),
LEAST_LOADED/SKILL_BASED tie-breaks falling back to that same cursor,
currentLoad read but never mutated by this feature, and the escalation
trigger reusing 005's existing domain-event bus rather than a new
notification path.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-03 11:30:23 +05:30
saqib mirandClaude Sonnet 5 e437711c2a docs: spec for orchestration and assignment feature (007)
Phase 7 of the roadmap: the orchestration engine (resolving 006's
hierarchy nodes and capability-eligibility lookup against an escalated
ticket), pluggable assignment strategies (ROUND_ROBIN/LEAST_LOADED/
SKILL_BASED/MANUAL/DIRECT) with concurrency-safe round robin, and
durable assignment history. Explicitly excludes SLA/escalation-policy
execution (Phase 8). Triggered via 005's existing domain-event
publishing rather than a new notification path.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-03 11:27:19 +05:30
saqib mirandClaude Sonnet 5 a0c1a9aa33 feat: implement support organization (006) — teams, agents, hierarchy, capability lookup
Phase 6 of the roadmap. Populates the identity/teams and
orchestration/hierarchy module directories (previously empty or
near-empty scaffold stubs) and replaces identity/agents' pre-existing
placeholder, which queried a generic User/UserRole model unrelated to
this system's real architecture (nothing since 002-saas-integration's
CustomerReference has used it).

Teams and agents: active/inactive CRUD, never hard deletion; team
deactivation never cascades to its agents. Skills: compound-unique
upsert on (agentId, skillTag), never duplicates. Availability: a single
current record per agent, deliberately last-write-wins rather than
optimistic-locked — operational telemetry, not a durable business
record. The dynamic hierarchy: a nestable, orderable HierarchyNode tree
with every field (scope, assignment strategy reference, entry/exit
conditions) stored as opaque admin-set data; cycle detection runs only
on reparenting edits (a new node can't form a cycle); every
create/edit/activate/deactivate is audited via AuditLog, reusing
002's existing writer pattern. A capability-eligibility read path
composes hierarchy scope with caller-supplied skills for the future
orchestration/assignment phase (Phase 7) to call, deliberately
excluding availability per doc 05's own capability-before-availability
ordering.

Found and fixed a real bug before it reached tests: the initial
availability upsert reset currentLoad to 0 on every update, not just
creation.

Adds 11 unit tests (cycle detection, capability matching) and 4
integration test files covering all four user stories. Full regression
(every pre-existing 002-005 integration test plus all new ones) run
against real Postgres/Redis/MinIO: 107 passed, 9 skipped (005's
AI-key-gated tests, unrelated), 0 failed.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-02 18:12:26 +05:30
saqib mirandClaude Sonnet 5 e703f826de docs: task breakdown for support organization feature
33 tasks across setup, foundational schema work, and four user stories
(teams/agents, skills/availability, the dynamic hierarchy tree, and a
capability-eligibility read path for the future orchestration phase).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-02 17:53:30 +05:30
saqib mirandClaude Sonnet 5 c18e203ad1 docs: plan and design artifacts for support organization feature
Reuses the existing identity/teams, identity/agents, and
orchestration/hierarchy scaffold directories per doc 07's documented
module placement. Key decisions: last-write-wins availability (not
optimistic locking — operational telemetry, not a durable record),
compound-unique skill upsert, cycle detection only on reparenting edits
(not creation, which can't form a cycle), and a capability-eligibility
read path that composes hierarchy scope with caller-supplied skills
while deliberately excluding availability per doc 05's own ordering.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-02 17:52:33 +05:30
saqib mirandClaude Sonnet 5 e1983438b9 docs: spec for support organization feature (006)
Phase 6 of the roadmap: Team/Agent/AgentSkill/AgentAvailability models,
dynamic HierarchyNode configuration, and a capability-eligibility read
path for the future orchestration phase to call. Supersedes the
pre-existing identity/agents scaffold stub (which queried a generic
User/UserRole model unrelated to this system's real architecture);
leaves identity/customers and identity/auth untouched as out of scope.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-02 17:49:50 +05:30
saqib mirandClaude Sonnet 5 82d02bcdcd feat: implement AI support agent (005) — diagnosis, tools, runbooks, verification
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>
2026-09-02 17:44:52 +05:30
saqib mirandClaude Sonnet 5 49eaa4bc58 docs: task breakdown for AI support agent feature
53 tasks across setup, foundational schema/env/LLM-client work, and five
user stories (diagnosis+confidence policy, clarification loop, gated tool
system, runbook engine, evidence-based verification), plus the two
constitution-required standing E2E scenarios in Polish.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-02 16:56:42 +05:30
saqib mirandClaude Sonnet 5 eceb00632d docs: correct 005-ai-support design to reuse the existing ticket state machine
003-ticketing's ticket-state-machine.ts already defines AI_ANALYZING/
AI_TROUBLESHOOTING/AI_VERIFYING/AI_RESOLVED/HUMAN_ESCALATION ticket
statuses, clearly authored anticipating this feature. Corrects the plan
before implementation: AISupportSession.status now drives Ticket.status
through the existing ticketsService.updateStatus (reusing its optimistic
concurrency), instead of an isolated status field the rest of the system
never sees. Also clarifies that knowledge retrieval is an in-process
service call through knowledge's index.ts, not an HTTP loopback.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-02 16:55:01 +05:30
saqib mirandClaude Sonnet 5 72dddcdf74 docs: plan and design artifacts for AI support agent feature
Two-call reasoning design (structured-output diagnosis, then a separate
knowledge-grounded reasoning/tool call), confidence-band policy as a DB-
configurable gate applied by app code, a deterministic tool-policy gate
that never reads AI free text, an app-owned runbook step index, and a
fail-closed placeholder verification tool mirroring the existing
malware-scanner precedent. Real Anthropic Claude integration per explicit
product decision.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-02 16:50:16 +05:30
saqib mirandClaude Sonnet 5 9586b872b7 docs: spec for AI support agent feature (005)
Phase 4 of the roadmap: AI session/diagnosis, confidence-band policy,
permission/risk-gated tool system, runbook execution, and evidence-based
verification. Per explicit decision, reasoning integrates a real LLM
provider (Anthropic Claude) rather than a mock.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-02 16:43:51 +05:30
saqib mirandClaude Sonnet 5 e33d86081f feat: implement product knowledge management & retrieval (004)
Implements 26 of 28 tasks from specs/004-product-knowledge/tasks.md
across all three user stories -- Phase 3 of the roadmap. First
feature to populate src/modules/ai-support/ (doc 07 places
`knowledge` there; only that submodule is built, matching this
codebase's convention of not pre-building unneeded submodules).

Schema (prisma/schema.prisma + migration):
- KnowledgeEntry, ErrorCode, KnownIssue, Runbook per docs/06,
  refining its conceptual flat `version` field into an explicit
  version-history mechanism: each edit inserts a new row
  (isCurrentVersion flag, compound unique on (code, version) /
  (key, productId, version)) instead of overwriting in place -- the
  only way "prior versions remain retrievable" (FR-004/FR-009) is
  actually true rather than aspirational.

User Story 1 -- knowledge entry authoring/publish/version (P1, MVP):
- draft -> published -> unpublished lifecycle; publish only takes
  effect from its effectiveDate.
- Editing uses the same conditional-update-then-insert optimistic
  concurrency pattern as 003-ticketing's Ticket.version (409 on a
  stale expectedVersion).
- Full version history readable via GET .../versions.

User Story 2 -- error codes, known issues, runbooks (P2):
- ErrorCode + KnownIssue with direct lookup-by-error-code.
- Runbook steps stored as an ordered JSON array, preserved exactly;
  same version-on-edit mechanism as knowledge entries; inactive
  runbooks are indistinguishable from nonexistent ones on lookup.

User Story 3 -- filtered retrieval (P3):
- GET /knowledge/retrieve: product-scoped, excludes draft/
  unpublished/not-yet-effective entries, validated entries ranked
  ahead of unvalidated. Deliberately NOT semantic/vector search --
  doc 11 gap B1 explicitly defers embedding-model choice to the
  future AI-support feature; this is real, usable structured
  filtering a semantic layer can sit in front of later.

Found and fixed one real bug before it reached tests: the retrieval
endpoint initially queried by the raw external product id instead of
resolving it to the internal Product.id first (every other endpoint
in this feature does that resolution) -- would have silently
returned zero results for every caller. Fixed with a lenient
tryResolveProductId (empty array, not 404, for an unregistered
product -- matches the "no matches, never an error" contract).

Deliberately skipped (not forgotten, see checklist notes): the two
planned mock-repository unit-test tasks (T004, T019) -- unlike
003-ticketing's state machine, this feature has no pure-logic
surface to isolate from Prisma; coverage comes entirely from
integration tests instead.

All 13 integration test files in the repo (36 tests, spanning this
feature and every prior one) verified passing together against a
real Postgres/Redis/MinIO -- no regressions. Full quality gate
(typecheck/lint/format/architecture/unit tests) passes.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-02 15:55:18 +05:30
saqib mirandClaude Sonnet 5 e10736d82a docs: task breakdown for product knowledge feature
/speckit-tasks output for 004-product-knowledge: 28 tasks across 6
phases. MVP scope is Setup+Foundational+US1 (T001-T010) -- knowledge
entries authored, published, and versioned correctly, before
structured error codes/runbooks/retrieval exist.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-02 15:31:36 +05:30
saqib mirandClaude Sonnet 5 e947ac44b8 docs: plan and design artifacts for product knowledge feature
/speckit-plan output for 004-product-knowledge: technical context and
constitution gate check (all PASS), Phase 0 research (6 decisions:
new-row-per-version instead of in-place overwrite to satisfy history
retention, conditional-update-then-insert concurrency reusing
003-ticketing's optimistic-locking pattern, structured (non-semantic)
filtered retrieval per doc 11 gap B1, known-issue lookup by error
code, creating the ai-support module group for the first time with
only its knowledge submodule populated, and admin auth consistent
with prior features), Phase 1 data model (KnowledgeEntry/ErrorCode/
KnownIssue/Runbook, refining doc 06's conceptual schema with an
explicit version-history mechanism), the admin CRUD + retrieval
contract, and a 6-scenario quickstart.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-02 15:30:46 +05:30
saqib mirandClaude Sonnet 5 cbe783cbdf docs: spec for product knowledge management & retrieval feature
/speckit-specify output for 004-product-knowledge (roadmap Phase 3):
3 user stories (authoring/versioning/publishing knowledge entries,
structured error-code/known-issue/runbook records, filtered
retrieval), 14 functional requirements. Full semantic/vector
retrieval is explicitly deferred to the future AI-support feature
(doc 11 gap B1) -- this feature's retrieval is structured filtering,
a real usable contract rather than a placeholder. Quality checklist
passes with no NEEDS CLARIFICATION markers.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-02 15:28:08 +05:30
saqib mirandClaude Sonnet 5 2edfbacf82 feat: implement ticket creation, messages & attachments (003-ticketing)
Implements all 39 tasks from specs/003-ticketing/tasks.md across all
three user stories -- Phase 5 of the roadmap.

Schema (prisma/schema.prisma + migration):
- Ticket (code, status, version for optimistic concurrency,
  idempotencyKey, customerId FK), Problem, TicketMessage,
  TicketAttachment per docs/06, with Product/Category/
  CustomerReference back-relations.

User Story 1 -- ticket/problem creation (P1, MVP):
- Explicit 12-state lifecycle adjacency table
  (ticket-state-machine.ts), not "any transition allowed."
- Ticket code generation (<PRODUCT_CODE>-<YEAR>-<SEQUENCE>) scoped
  by the actual code prefix, not productId -- see the collision bug
  fixed below.
- Idempotency-key enforcement via atomic create-then-catch-conflict
  (never a read-then-write race), completing the FR-012 placeholder
  from 002-saas-integration.
- Explicit-reference-only recurring-problem linking (no fuzzy
  matching -- that's a future AI-support concern).
- POST /v1/support/requests (002-saas-integration) now creates a
  real ticket instead of echoing context back.
- PATCH /tickets/:id/status with expectedVersion-based optimistic
  concurrency (409 on stale version, 400 on an invalid transition).

User Story 2 -- typed messages (P2):
- Message type -> visibleToCustomer mapping is a fixed constant map,
  never caller-supplied; customer-scoped reads filter at the query
  layer so an internal note is never fetched, not just hidden.
- POST/GET /tickets/:id/messages (customer-scoped) and
  GET /agent/tickets/:id/messages (agent-scoped).

User Story 3 -- attachment pipeline (P3):
- Presigned-PUT upload (new getPresignedUploadUrl on the existing
  storageService) -- file bytes never transit this API.
- A MalwareScanner interface with a fail-closed placeholder
  (UnimplementedPlaceholderScanner) since no scanner exists in this
  stack -- it always reports 'infected', never silently 'clean'.
- The existing attachments-queue job stub now actually calls the
  scanner and updates scanStatus; registerAttachmentWorker() is
  wired into bootstrapQueue() (previously defined but never called).
- Downloads are gated on scanStatus === 'clean' -- currently always
  refused until a real scanner replaces the placeholder.
- MinIO added to docker-compose.{test,development}.yml for local/CI
  S3-compatible storage, matching doc 04's explicit guidance.

Two real bugs found and fixed via integration testing against a
live Postgres/Redis/MinIO (not just typechecked):
- Ticket codes could collide across different products: the
  sequence counter was scoped by internal productId, but the code
  column's uniqueness is global, and deriveProductCode's 4-character
  truncation means different products can share a prefix. Fixed by
  counting against the actual code prefix instead.
- Three existing 002-saas-integration integration tests' cleanup
  started failing an FK RESTRICT check once ticket creation was
  wired in (deleting a Product before the Ticket/Problem that now
  reference it). Fixed their afterAll ordering.

All 9 integration test files (24 tests, spanning this feature and
the pre-existing suite) verified passing against real Postgres,
Redis, and MinIO, including a genuine presigned-PUT/GET round trip.
Full quality gate (typecheck/lint/format/architecture/unit tests)
passes.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-02 15:21:37 +05:30
saqib mirandClaude Sonnet 5 954152bd7b docs: task breakdown for ticketing feature
/speckit-tasks output for 003-ticketing: 39 tasks across 6 phases.
MVP scope is Setup+Foundational+US1 (T001-T019) -- every trusted
inbound request producing a real, durable, idempotent,
concurrency-safe ticket, before messages or attachments exist.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-02 14:56:05 +05:30
saqib mirandClaude Sonnet 5 4751cf3164 docs: plan and design artifacts for ticketing feature
/speckit-plan output for 003-ticketing: technical context and
constitution gate check (all PASS), Phase 0 research (9 decisions:
ticket code format, explicit 12-state lifecycle transition table,
optimistic concurrency via version column, idempotency-key upsert
reusing 002's CustomerReference pattern, explicit-reference-only
recurring-problem linking, config-driven message visibility mapping,
presigned-PUT attachment pipeline, a fail-closed placeholder malware
scanner since none exists in this stack, and adding MinIO to Docker
Compose for local/test S3-compatible storage), Phase 1 data model
(Ticket/Problem/TicketMessage/TicketAttachment plus the inbound
request -> ticket creation behavior), the lifecycle/messages/
attachments contract, and a 6-scenario quickstart.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-02 14:53:53 +05:30
saqib mirandClaude Sonnet 5 be2eb9907a docs: spec for ticket creation, messages & attachments feature
/speckit-specify output for 003-ticketing (roadmap Phase 5): 3 user
stories (immediate ticket/problem creation with idempotency, typed
messages with enforced internal-note privacy, secure attachment
pipeline) and 15 functional requirements. Explicitly scoped to Phase
5 only -- investigation/root-cause/solution/resolution (Phase 9) and
AI diagnosis (Phase 4) are out of scope. Quality checklist passes
with no NEEDS CLARIFICATION markers.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-02 14:46:59 +05:30
saqib mirandClaude Sonnet 5 55253287b3 feat: per-integration and per-user rate limiting (US3) + polish
Implements tasks T026-T032 from specs/002-saas-integration/tasks.md
(User Story 3, P3 - the final piece of this feature) plus Polish.

- New bespoke Redis fixed-window counter (checkRateLimit,
  src/infrastructure/cache/rate-limiter.ts) rather than
  @fastify/rate-limit's default onRequest-stage hook -- that hook
  runs before this feature's preHandler-based auth resolves the
  integration/user identity the limit needs to key on. A second
  preHandler (checkIntegrationRateLimit) runs after
  authenticateProductIntegration on the inbound route, checking the
  integration-level limit then the per-user limit independently,
  each throwing the existing RateLimitError (429
  RATE_LIMIT_EXCEEDED) on breach.
- New integration test (inbound-rate-limit.test.ts) verifies both
  limits are enforced independently against a real Postgres/Redis:
  a throttled user doesn't affect others, and the integration cap
  throttles even when no individual user has hit their own limit.
- Docs: contracts/quickstart updated from the placeholder
  "RATE_LIMITED" code to the actual reused RATE_LIMIT_EXCEEDED code;
  cleaned up a duplicated paragraph in the admin endpoints section;
  added a "SaaS Integration" section to README.md documenting the
  inbound contract, admin routes (and their known auth-stub
  limitation), and how rate limits are configured.

All 32 tasks in tasks.md are now complete -- all three user stories
(P1 trust boundary, P2 admin lifecycle, P3 rate limiting) are
implemented and covered by integration tests verified against a
live database, in addition to unit tests for the crypto/token
primitives. Full quality gate (typecheck/lint/format/architecture/
unit tests) passes.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-02 14:42:20 +05:30
saqib mirandClaude Sonnet 5 3e2a5b97a3 feat: admin lifecycle endpoints for product integrations (US2)
Implements tasks T021-T025 from specs/002-saas-integration/tasks.md
(User Story 2, P2): an admin can register, rotate, revoke, and change
the status of a ProductIntegration, and retrieve its audit trail.

- ProductIntegrationsService: register (finds-or-creates the Product
  by external id), rotate (dual-credential transition window per
  research.md), revoke, updateStatus, getAuditTrail -- each writes
  its own AuditLog entry via a new shared
  integration-audit-log.repository.ts (extracted from the auth
  plugin, which now reuses it instead of writing to Prisma directly).
- Routes: POST /admin/products/:externalProductId/integration,
  POST/admin/integrations/:id/rotate|revoke, PATCH .../status,
  GET .../audit-trail -- gated by the existing fastify.authenticate
  (human/admin JWT) decorator.
- New integration test (product-integrations-admin.test.ts) covers
  Quickstart Scenarios 5-7 end-to-end against a real Postgres/Redis:
  register+rotate+audit-trail, and revoke-takes-effect-immediately.
  Verified passing against a live database.

Known, pre-existing limitation flagged (not fixed here, out of
scope): fastify.authenticate is currently a no-op stub with no real
JWT verification, so these admin endpoints aren't actually
access-controlled yet -- that depends on the unimplemented
identity/auth module. Documented in the contract and checklist notes
so it isn't mistaken for done.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-21 18:57:07 +05:30
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
saqib mirandClaude Sonnet 5 5444fb7ef3 fix: setErrorHandler must be registered before route modules
Fastify resolves each encapsulated child context's error handler at
the time that context is registered. app.ts called
app.setErrorHandler()/setNotFoundHandler() AFTER bootstrapRoutes()
had already registered every domain module's routes (each
app.register(someRoutes) call creates its own child context, since
none of the route modules use fastify-plugin). A handler set on the
parent afterwards does not retroactively apply to already-registered
children, so every module's routes were silently falling back to
Fastify's default {statusCode, error, message} error shape instead
of this app's {success:false, error:{code,message,details},
requestId} envelope, for any thrown error -- not specific to any one
feature. Discovered while building and manually verifying the
002-saas-integration feature's inbound endpoint.

Also fixed the generic error-handler branch to preserve a framework
error's own client-facing statusCode (e.g. 400 for malformed JSON)
instead of always reporting 500.

Added a regression test in tests/unit/app.test.ts that fails without
this fix and passes with it (verified both ways).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-21 18:40:20 +05:30
saqib mirandClaude Sonnet 5 000a8bcb6b docs: task breakdown for SaaS integration feature
/speckit-tasks output for 002-saas-integration: 32 tasks across 6
phases. Unlike 001-ci-pipeline, this feature includes test tasks as
first-class (not optional) since it's a security boundary. MVP scope
is Setup+Foundational+US1 (T001-T020) - the inbound trust boundary
alone, before admin lifecycle tooling or rate limiting exist.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-21 17:51:06 +05:30
saqib mirandClaude Sonnet 5 a7216b7531 docs: plan and design artifacts for SaaS integration feature
/speckit-plan output for 002-saas-integration: technical context and
constitution gate check (all PASS), Phase 0 research (9 decisions:
signed-token format, replay resistance via Redis jti tracking, clock
skew tolerance, rotation via previous-credential transition window,
per-integration/per-user rate limiting, strict unknown-field
rejection, non-leaking error responses, and reconciling the
placeholder Prisma schema with docs/06's real Product shape), Phase 1
data model (Product revision, ProductIntegration, CustomerReference,
AuditLog reuse for auth events), the inbound request validation
contract (9 fixed steps + admin lifecycle endpoints), and an
8-scenario quickstart.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-21 17:45:02 +05:30
saqib mirandClaude Sonnet 5 0e92faf615 docs: spec for SaaS integration & inbound request trust feature
/speckit-specify output for 002-saas-integration (roadmap Phase 2):
3 user stories (authenticate/validate inbound requests, admin
onboarding/rotation/revocation, rate limiting) and 12 functional
requirements. Reserves an idempotency-key field on the inbound
contract for the future ticketing feature (docs/11 gap A1) without
implementing dedup here. Quality checklist passes with no
NEEDS CLARIFICATION markers.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-21 17:39:25 +05:30
saqib mirandClaude Sonnet 5 38148a97f9 docs: add architect's additions doc (gaps & recommendations)
Production concerns not covered by the original spec (00-10):
idempotency on ticket creation, bi-directional webhook callbacks,
row-level-security tenant isolation, AI prompt-injection defense,
optimistic concurrency on shared mutable state, RAG implementation
specifics, AI cost/token governance, knowledge effectiveness
feedback, CSAT capture, data retention/PII, API versioning/error
contract, localization, and a lower-urgency list. Indexed in
docs/00-INDEX.md as doc 11.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-21 17:35:32 +05:30
saqib mirandClaude Sonnet 5 2dffe58496 feat: implement CI pipeline (Jenkinsfile) for 001-ci-pipeline
Implements tasks T001-T016, T018-T022, T024-T026 from
specs/001-ci-pipeline/tasks.md (T017/T023 need a real Jenkins
instance to verify and are left for manual follow-up).

- Add Jenkinsfile: checkout -> install -> environment validation
  -> typecheck -> lint (+ architecture check) -> format check ->
  unit -> integration -> E2E -> build -> Docker build -> publish
  -> deploy, matching the constitution's required stage order.
  Secrets are always injected from Jenkins credentials at runtime,
  never read from a repo-committed file. Publish/Deploy are skipped
  (not failed) on branches with no resolved deploy target.
- Fix docker-compose.test.yml: remove fixed container_name on
  app/postgres/redis, which would have made concurrent CI runs
  collide (FR-009). Verified locally that two runs under different
  -p project names no longer share container/volume/network names.
- Document the pipeline and local .env setup in README.md.
- Mark completed tasks in specs/001-ci-pipeline/tasks.md and record
  the container_name/compose-down-env-file findings in the spec's
  requirements checklist notes.

Locally verified passing: Dockerfile build, typecheck, lint,
architecture check, format check, unit test suite, and the edited
docker-compose.test.yml bringing up postgres/redis with isolated
per-project container names.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-21 17:25:46 +05:30
saqib mirandClaude Sonnet 5 dd2d803c93 docs: task breakdown for CI pipeline feature
/speckit-tasks output for 001-ci-pipeline: 26 tasks across 5 phases
(Setup, Foundational, US1 validate/build, US2 publish/deploy, Polish),
with the MVP scope being US1 alone (T001-T017).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-21 17:15:46 +05:30
saqib mirandClaude Sonnet 5 414f336704 docs: spec, plan, and design artifacts for CI pipeline feature
/speckit-specify + /speckit-plan output for 001-ci-pipeline: feature
spec with 2 user stories and 10 functional requirements, requirements
quality checklist, implementation plan with constitution gate check,
Phase 0 research (6 decisions incl. secrets-from-credentials-store),
Phase 1 data model, pipeline stage contract, and a 5-scenario
quickstart validation guide. No Jenkinsfile yet — that's the
implementation step after /speckit-tasks.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-21 16:22:29 +05:30
saqib mirandClaude Sonnet 5 f475a55a53 docs: add product and engineering specification
Full system blueprint (docs 01-10): product vision, integration &
security, AI support architecture, ticketing & problem management,
orchestration/SLA/escalation, database schema, backend/frontend
architecture, testing/observability/CI-CD, and the implementation
roadmap. This is the pre-implementation design reference the codebase
is being built against.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-21 16:22:21 +05:30
saqib mirandClaude Sonnet 5 c61b78fcd1 chore: install GitHub Spec Kit tooling
Adds the specify CLI's .specify/ scaffolding (templates, PowerShell
automation scripts, constitution memory) and the .claude/skills/speckit-*
slash commands for spec-driven development (constitution, specify,
clarify, plan, tasks, checklist, analyze, implement, converge).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-21 16:22:13 +05:30
saqib mirandClaude Sonnet 5 2093898198 fix: stop tracking .env files with committed secrets
.env.development had a real Postgres/Redis password and JWT secret
committed in plain text; .env.test and .env.prod were tracked too.
Untrack all .env* files going forward and add .env.example as the
onboarding template instead.

Note: the exposed dev credentials are still in git history and must
be rotated separately.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-21 16:10:32 +05:30
saqib mir e7886b40d1 add the env 2026-08-19 19:03:45 +05:30
saqib mir 51993f576f add the build command and also added the docker commands 2026-08-19 18:31:34 +05:30
saqib mir c31a76631a add the env 2026-08-19 17:48:35 +05:30
saqib mir dd3f3720df add the env 2026-08-19 17:13:17 +05:30
saqib mir 5e4ed9d64a first commit 2026-08-19 16:29:17 +05:30