Skip to content

HOMEWORK 2 - #2

Open
borysenko-oleksandr wants to merge 1 commit into
mainfrom
homework-2
Open

HOMEWORK 2#2
borysenko-oleksandr wants to merge 1 commit into
mainfrom
homework-2

Conversation

@borysenko-oleksandr

@borysenko-oleksandr borysenko-oleksandr commented May 10, 2026

Copy link
Copy Markdown
Owner

Related issues:

  • TASKS.md — Homework 2: Intelligent Customer Support System

✅ Summary

Intelligent Customer Support System — complete REST API for ticket management with multi-format import (CSV/JSON/XML), automatic issue categorization & priority assignment, and comprehensive test suite (65 tests, 92.3% line coverage, 88.41% statements). Built with Node.js + Express, in-memory store, Jest testing.

Endpoints

Method Endpoint Description
POST /tickets Create new ticket (with optional auto-classification)
GET /tickets List all tickets (filterable by category, priority, status)
GET /tickets/:id Retrieve specific ticket
PUT /tickets/:id Update ticket (auto-populate resolved_at on status change)
DELETE /tickets/:id Delete ticket
POST /tickets/import Bulk import from CSV/JSON/XML with detailed summary
POST /tickets/:id/auto-classify Re-classify single ticket with confidence & reasoning

What's inside

Task 1 — Multi-Format Ticket Import API

Implemented 7 REST endpoints in src/routes/tickets.js for complete ticket lifecycle management:

  • Full CRUD operations with validation (src/models/ticket.js)
  • Bulk import with 3 format parsers (CSV, JSON, XML) + error recovery (src/services/importer.js)
  • Returns detailed import summary: {total, successful, failed, errors[]}
  • HTTP status codes: 201 (created), 400 (validation / unsupported format / parse error), 404 (not found), 200 (import summary — includes per-row errors in failed[] array without aborting the batch)
  • In-memory store with UUID keys (src/utils/store.js)

Task 2 — Auto-Classification

Implemented intelligent ticket categorization & priority assignment (src/services/classifier.js):

  • Categories: account_access | technical_issue | billing_question | feature_request | bug_report | other
  • Priorities: urgent | high | medium | low
  • Scoring: Returns confidence score (0–1), matched keywords, and reasoning
  • Trigger: ?auto_classify=true on creation, or POST /tickets/:id/auto-classify anytime
  • Rules-based matching (20+ keywords across priorities/categories)

Task 3 — AI-Generated Test Suite

65 comprehensive tests across 8 files covering all layers:

  • API tests (13) — CRUD, filtering, error handling
  • Model validation (12) — field constraints, enum values, email format
  • Import parsers (16) — CSV, JSON, XML with malformed file handling
  • Categorization (14) — rule matching, edge cases, confidence scoring
  • Integration (5) — end-to-end workflows, concurrent operations (20+ simultaneous GETs/POSTs)
  • Performance (5) — latency benchmarks, throughput under load

Overall coverage: 92.3% lines, 88.41% statements (exceeds 85% threshold)

Task 4 — Multi-Level Documentation

4 docs + 1 README with 5 Mermaid diagrams for different audiences:

  • README.md — Architecture overview, setup, quick start (1 diagram: system components)
  • API_REFERENCE.md — All endpoints with cURL examples, request/response shapes, error formats
  • ARCHITECTURE.md — Component descriptions, data flow, design decisions (3 diagrams: layers, flows, decision tree)
  • TESTING_GUIDE.md — Test pyramid, how to run, benchmarks table, manual checklist (1 diagram)

Project structure

homework-2/
├── src/
│   ├── app.js                          ← Express app setup
│   ├── server.js                       ← Entry point
│   ├── models/
│   │   └── ticket.js                   ← Data model + validation rules
│   ├── routes/
│   │   └── tickets.js                  ← 7 REST endpoints (CRUD + import + classify)
│   ├── services/
│   │   ├── importer.js                 ← CSV/JSON/XML parsers
│   │   └── classifier.js               ← Auto-categorization engine
│   └── utils/
│       ├── store.js                    ← In-memory ticket storage
│       └── logger.js                   ← Logging utility
├── tests/
│   ├── test_ticket_api.test.js         ← 13 API endpoint tests
│   ├── test_ticket_model.test.js       ← 12 validation tests
│   ├── test_import_csv.test.js         ← 6 CSV parsing tests
│   ├── test_import_json.test.js        ← 5 JSON parsing tests
│   ├── test_import_xml.test.js         ← 5 XML parsing tests
│   ├── test_categorization.test.js     ← 14 classification tests
│   ├── test_integration.test.js        ← 5 end-to-end tests
│   ├── test_performance.test.js        ← 5 performance benchmarks
│   └── fixtures/
│       ├── sample_tickets.csv          ← 50 valid tickets
│       ├── sample_tickets.json         ← 20 valid tickets
│       ├── sample_tickets.xml          ← 30 valid tickets
│       ├── invalid_tickets.csv         ← Malformed (unclosed quote)
│       ├── invalid_tickets.json        ← Invalid syntax
│       └── invalid_tickets.xml         ← Mismatched tags
├── docs/
│   ├── API_REFERENCE.md                ← All endpoints + cURL examples
│   ├── ARCHITECTURE.md                 ← Design & diagrams
│   ├── TESTING_GUIDE.md                ← Test pyramid & benchmarks
│   └── screenshots/                    ← Coverage reports & screenshots
├── coverage/                           ← Jest coverage HTML report
├── package.json                        ← Dependencies: express, csv-parse, xml2js, jest, supertest
└── README.md                           ← Overview + quick start

🛠️ AI Tools Used

Tool: GitHub Copilot CLI (claude-sonnet-4.6) via the VS Code extension

Workflow

  1. Planning first — used [[PLAN]] mode to analyze TASKS.md and produce a step-by-step plan; reviewed structure and asked clarifying questions (tech stack, storage, test framework, port) before writing a single line of code
  2. Incremental feature delivery — each layer delivered as its own cycle: model + store → routes → classifier + importer → test suite → fixtures → documentation
  3. Live verification — ran npm test after each phase to catch regressions; manually verified endpoint shapes by inspecting route handler return values against the spec
  4. Bug-finding through analysis — cross-checked implementation against TASKS.md requirements (HTTP status codes, bulk import error handling, resolved_at auto-set, UUID server-side generation)

Prompts used (representative sample)

Intent Prompt
Initial build "According to this file create a project. Divide your work into a few steps, ask question before each step like 'which language do you want to use?'"
Model + store "Implement ticket validation and data model with in-memory storage"
Routes + services "Build all 7 REST endpoints plus classifier and importer services"
Test suite "Generate comprehensive Jest tests for all components (>85% coverage)"
Fixtures "Generate 50 CSV tickets, 20 JSON tickets, 30 XML tickets, plus invalid files for negative tests"
Documentation "Create 4 documentation files with Mermaid diagrams for developers, API users, and QA engineers"
PR template "@example.md використовуй цей приклад створи шаблон PR_DESCRIPTION.md щоб я міг його перевикористовувати"

What I verified myself

  • Reviewed every generated file before accepting changes (routes, model, importer, classifier, all 8 test files)
  • Confirmed the app.js + server.js split was the right pattern — Supertest requires app without a bound port, so the listen call lives only in server.js
  • Validated that bulk import truly never aborts — checked the for loop in tickets.js collects errors per row and always returns {total, successful, failed}
  • Verified resolved_at is auto-set only on resolved transition (not closed) by reading store.js directly

⚠️ Challenges Encountered

1. Import route shadowed by parameterized route

Problem: In Express, POST /tickets/import was being matched by the /:id handler because it was registered after router.post('/:id/auto-classify', ...). The literal segment import was treated as an :id value, causing the handler to look up a ticket with id "import" and return 404.

Solution: Moved the /import route registration to before any /:id routes in tickets.js so Express matches the static segment first.


2. XML tags unwrapping with xml2js

Problem: xml2js with explicitArray: false returns tags as { tag: "value" } for a single child or { tag: ["a", "b"] } for multiple children — not a plain array. The ticket model expects string[].

Solution: Added explicit unwrapping in importXml() — checks for the .tag sub-property, normalises single values to [value], falls back to |-split for legacy string encoding.


3. CSV flat format vs. nested metadata object

Problem: CSV is inherently flat; csv-parse reads metadata as a raw JSON string and tags as a pipe-delimited string. The model validator rejects a string where an object is expected.

Solution: Added post-parse deserialization in importCsv() — attempts JSON.parse on metadata, falls back to {} on failure; splits tags on | if JSON.parse fails.


📸 Screenshots

AI tool interaction — planning & implementation

1 · Initial Copilot question asking about tech stack, storage, and test framework

Copilot asking setup questions before scaffolding
first_promt_question

2 · Jest coverage report — 92.3% line coverage across all source files

Jest coverage report showing 92.3% line coverage
test_coverage


Live demo results

POST /tickets?auto_classify=true — create ticket with automatic classification

{
  "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "customer_id": "cust-001",
  "customer_email": "alice@example.com",
  "customer_name": "Alice Smith",
  "subject": "Can't access account — login blocked",
  "description": "I keep getting a security error when trying to login with my password.",
  "category": "account_access",
  "priority": "urgent",
  "status": "new",
  "created_at": "2026-05-10T18:00:00.000Z",
  "updated_at": "2026-05-10T18:00:00.000Z",
  "resolved_at": null,
  "assigned_to": null,
  "tags": [],
  "metadata": { "source": "api", "browser": "", "device_type": "desktop" },
  "confidence": 0.95,
  "reasoning": "Matched keywords: [can't access, security, login, password]. Assigned priority=\"urgent\", category=\"account_access\".",
  "keywords": ["can't access", "security", "login", "password"]
}

GET /tickets?category=account_access&priority=urgent — filtered list

[
  {
    "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "subject": "Can't access account — login blocked",
    "category": "account_access",
    "priority": "urgent",
    "status": "new"
  }
]

POST /tickets/import (CSV, 50 rows, 2 invalid) — bulk import summary

{
  "total": 50,
  "successful": 48,
  "failed": [
    { "row": 3, "errors": [{ "field": "customer_email", "message": "customer_email must be a valid email address" }] },
    { "row": 17, "errors": [{ "field": "description", "message": "description is required and must be 10-2000 characters" }] }
  ]
}

400 Validation error on POST /tickets

{
  "errors": [
    { "field": "customer_email", "message": "customer_email must be a valid email address" },
    { "field": "subject", "message": "subject is required and must be 1-200 characters" }
  ]
}

🔗 Related

  • docs/ai-prompts.md — Full AI conversation log: every prompt and generated response
  • HOWTORUN.md — Terminal setup instructions
  • demo/test_coverage.png — Jest coverage screenshot

@Alexey-Popov Alexey-Popov left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please structure PR properly, following the requirements (read them carefully)

HW not approved

@borysenko-oleksandr

Copy link
Copy Markdown
Owner Author

@Alexey-Popov description was updated

@Alexey-Popov Alexey-Popov left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the updates.

HW approved

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants