Skip to main content
Back to projects
Production

AI-Powered ITSM Ticket Follow-up Assistant

Autonomous ticket follow-up system built solo over 6 months. 66-node n8n workflow + 70 nodes per team sub-workflow. 15-minute cycle, 0 manual intervention. 6-step pipeline: Collect (iTop) → Enrich (Supabase) → Filter (16-combination anti-spam matrix) → Anonymize (GDPR) → Analyze (Vertex AI) → Notify (Teams). Smart routing based on agent availability. Running in production across all services.

n8nGoogle Vertex AIMicrosoft Graph APISupabasePostgreSQLiTop ITSMOAuth 2.0JavaScript
66
Main workflow nodes
70
Nodes per sub-workflow
15min
Execution cycle
0
Manual intervention

Managers opening tickets one by one. Team meetings producing obsolete status updates.

I spent 6 months building something different: a system that runs every 15 minutes, analyzes every open ticket, and sends follow-ups to the right person automatically.

Intelligent 3-Branch Routing

System automatically detects ticket state and routes accordingly

Assigned to agent DM agent, CC manager
Assigned to team only Post to team channel
Agent out of office Auto-escalate to manager

Key Insight: Each team has its own thresholds, its own priorities, its own implicit rules. A system that doesn't reflect that reality ends up being ignored. That's why each team gets its own 70-node sub-workflow with custom configuration.

6-Step Pipeline: Collect → Enrich → Filter → Anonymize → Analyze → Notify

5 APIs. Multi-provider OAuth. Webhooks. All working together.

01
Collect
iTop REST
02
Enrich
Supabase
03
Filter
Anti-Spam
04
Anonymize
GDPR
05
Analyze
Vertex AI
06
Notify
Graph API

Collect

iTop REST API with OQL queries. Handles both UserRequests and Incidents with dynamic field mapping.

iTop RESTOQLPagination

Enrich

42-column PostgreSQL schema tracking full ticket lifecycle. PostgREST for fast batch queries.

SupabasePostgRESTUPSERTJSONB

Filter

Status × priority matrix. 4 statuses, 4 priority levels, 16 combinations, each with its own trigger logic.

Anti-SpamPriority Matrix16 combinations

Anonymize

Complete anonymization engine before every AI call. Names → AGENT_002, companies → ORG_001, IPs → IP_001.

GDPRRegex EngineMapping Table

Analyze

Gemini analyzes anonymized ticket. Blockage detection, risk level. AI ALWAYS prepares 2 messages (agent + manager).

Vertex AIService AccountStructured Output

Notify

Teams messaging, presence detection, manager hierarchy lookup. Azure AD app with delegated permissions.

Graph APIOAuth 2.0Presence APIChat API

Anti-Spam Matrix: 16 Combinations

The workflow runs every 15 minutes. Without filtering, each ticket would get followed up dozens of times a day.

Concrete Examples

P1 unread Follow-up after 15 min
P1 waiting for client Follow-up after 4 hours
P4 waiting for client Follow-up after 10 days
Agent out of office Auto-escalate to manager

Why 10 days for a P4? An agent with 15 tickets will prioritize P1s. Following up a P4 every 4h just creates noise. But after 10 days, even a P4 becomes a problem.

15-Minute Cycle

Cron trigger every 15 minutes. Business hours filtering.

Presence-Aware Routing

Availability check via Graph API. If isOutOfOffice = true, auto-escalate to manager.

The decision that simplified everything: AI always prepares two messages

The AI agent always prepares two messages at once: one for the agent, one for the manager. Not because both are always sent, but because the AI can't know at analysis time whether the agent is available or out of office. That check happens after, via Microsoft Graph. The workflow then picks which message to send.

Why it works: This saved me a huge amount of conditional logic on the AI side. Sometimes the right technical decision is to make the AI do more, so the rest of the pipeline stays simple.

anonymization.js
// Before anonymization Contact: [email protected]\nServer 192.168.1.45 is down.\nJohn asked for update yesterday. // After anonymization Contact: EMAIL_001\nServer IP_001 is down.\nPERSON_001 asked for update. // Mapping table (internal) { "EMAIL_001": "[email protected]", "IP_001": "192.168.1.45", "PERSON_001": "John" }

Invisible work: This invisible work is what allowed the project to ship. The anonymization engine, invisible to the end user, is what got the project validated internally and passed to production.

Real bugs found and fixed across 5 integrated systems

Bug: Data Serialization
Timestamp stored as [object Object]
SQL inserts were failing silently. Root cause: n8n node was returning a wrapper object instead of the raw ISO string. Fix: generate timestamp directly in consuming node with new Date().toISOString() instead of referencing upstream node output.
Bug: API Response Parsing
Dynamic ticket type detection
iTop returns different key structures for Incidents vs UserRequests. Same workflow needs to handle both. Built dynamic detection: check for Incident:: prefix first, fallback to UserRequest::, map fields accordingly.
Bug: AI Agent Memory
Chatbot forgetting context between turns
User asks "give me the link" but agent forgot which ticket was discussed. Solution: parse AI response history, extract last mentioned ticket ID via regex, inject into system prompt before each query.
Bug: Graph API Auth
Presence check returning 403
App had User.Read but not Presence.Read.All. Azure AD app permissions needed update + admin consent. Added proper scope handling and token refresh logic.

Key Features

Intelligent 3-Branch Routing

Agent assigned → DM + CC manager. Team assigned → team channel. Agent OOO → auto-escalate manager. Automatic ticket state detection.

16-Combination Anti-Spam Matrix

4 statuses × 4 priorities. Each combination with its own logic. P1 unread = 15 min. P4 waiting = 10 days. Adapted per team.

2-Message AI Architecture

AI ALWAYS prepares an agent message AND a manager message. Workflow chooses which to send based on availability. Simplifies overall logic.

Complete GDPR Anonymization

Anonymization engine before every AI call. Names, emails, IPs, URLs masked with unique codes. Mapping table for re-identification.

Presence-Aware Routing

Availability check via Graph API before sending. If isOutOfOffice = true, auto-escalate to manager. No notifications to void.

Chat with Tickets Agent

Secondary conversational agent that managers can query directly: "Which agents have the most overdue tickets?" Natural language to SQL.

Tech Stack

n8n Orchestration

66-node main workflow. 70 nodes per team sub-workflow. Code nodes for complex logic.

Google Vertex AI LLM

Gemini for ticket analysis. Structured JSON output. Prompt engineering.

Microsoft Graph Integration

Teams messaging. Presence API for isOutOfOffice. Azure App Registration.

Supabase Database

PostgreSQL. 42-column schema for ticket tracking. PostgREST for batch queries.

iTop ITSM Source

REST API with OQL queries. UserRequests + Incidents. Dynamic field mapping.

JavaScript Backend

Anonymization engine. Anti-spam matrix. Data transformation in code nodes.

Results & Metrics

Technical Performance

66 nodes
Main Workflow
Complete architecture
70 nodes
Sub-Workflow
Per team
15 min
Cycle
Periodic execution
0
Intervention
Fully automated

Business Impact

6 months
Development
Solo project
All services
Coverage
Company-wide
16
Combinations
Anti-spam matrix
Active
Production
Running for months

Security & Compliance

Compliant
GDPR
Anonymization before AI
Applied
Zero-Trust
No PII to AI
5
APIs
Multi-provider OAuth
42 cols
DB Schema
Complete traceability

Technical Challenges & Solutions

Timestamp [object Object] Serialization

Problem
SQL inserts were failing silently. n8n node was returning a wrapper object instead of the raw ISO string.
Solution
Generate timestamp directly in consuming node with new Date().toISOString() instead of referencing upstream node output.

Dynamic Incident vs UserRequest Detection

Problem
iTop returns different key structures for Incidents vs UserRequests. Same workflow needs to handle both.
Solution
Dynamic detection: check Incident:: prefix first, fallback to UserRequest::, then map fields accordingly.

Chatbot Memory Between Turns

Problem
User asks "give me the link" but agent forgot which ticket was discussed.
Solution
Parse AI response history, extract last mentioned ticket ID via regex, inject into system prompt before each query.

403 Presence Graph API Error

Problem
App had User.Read but not Presence.Read.All. Presence check was failing.
Solution
Azure AD app permissions update + admin consent. Added proper scope handling and token refresh logic.

Demonstrated Skills

Workflow Orchestration

n8n Multi-WorkflowSub-Workflow PatternCron Scheduling (15min)Switch RoutingError Handling

API Orchestration

5 Integrated APIsMulti-Provider OAuthRate LimitingBatch ProcessingWebhooks

AI/LLM Integration

Google Vertex AIPrompt EngineeringStructured JSON Output2-Message ArchitectureRe-identification

Privacy Engineering

GDPR AnonymizationPII DetectionMapping TablesZero-Trust AIAudit Trail

Multi-System Debugging

Data SerializationAPI Response ParsingAgent MemoryOAuth Permissions

Interested in this project?

Contact me to discuss similar projects or for more information.