Skip to content

Commit 0bf0218

Browse files
committed
feat: Add QA tickets management with new TicketList component and API integration
1 parent f4378c5 commit 0bf0218

6 files changed

Lines changed: 729 additions & 148 deletions

File tree

backend/agents.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,13 +34,13 @@
3434
from datetime import datetime
3535
from typing import Literal, Optional
3636

37+
# Ensure operations register before we request LangChain tools
38+
import operations # noqa: F401
3739
# Local - Import operations registry for automatic tool discovery
3840
from api_decorators import get_langchain_tools
39-
4041
# Third-party - LangChain and LangGraph
4142
from langchain_openai import ChatOpenAI
4243
from langgraph.prebuilt import create_react_agent
43-
4444
# Third-party - Pydantic for validation
4545
from pydantic import BaseModel, Field, field_validator
4646

backend/app.py

Lines changed: 88 additions & 144 deletions
Original file line numberDiff line numberDiff line change
@@ -28,15 +28,17 @@
2828

2929

3030
# Import unified operation system
31-
from api_decorators import operation
3231
from mcp import handle_mcp_request
33-
from ollama_service import ChatRequest, ChatResponse, ModelListResponse, OllamaService
32+
from ollama_service import ChatRequest
33+
from operations import (op_create_task, op_delete_task, op_get_task,
34+
op_get_task_stats, op_list_ollama_models,
35+
op_list_tasks, op_ollama_chat, op_update_task,
36+
task_service)
3437
from pydantic import ValidationError
3538
from quart import Quart, jsonify, request, send_from_directory
3639
from quart_cors import cors
37-
3840
# Import Pydantic models and service
39-
from tasks import Task, TaskCreate, TaskFilter, TaskService, TaskStats, TaskUpdate
41+
from tasks import Task, TaskCreate, TaskFilter, TaskStats, TaskUpdate
4042

4143
# ============================================================================
4244
# APPLICATION SETUP
@@ -45,9 +47,7 @@
4547
app = Quart(__name__)
4648
app = cors(app, allow_origin="*")
4749

48-
# Service instances
49-
task_service = TaskService()
50-
ollama_service = OllamaService()
50+
# Service instances live in operations.py so every interface shares them
5151

5252

5353
# ============================================================================
@@ -59,144 +59,10 @@ def format_datetime(dt: datetime) -> str:
5959
return dt.isoformat()
6060

6161

62-
# ============================================================================
62+
# =========================================================================
6363
# UNIFIED OPERATIONS
64-
# Define once with Pydantic types, use for both REST and MCP!
65-
# ============================================================================
66-
67-
@operation(
68-
name="list_tasks",
69-
description="List all tasks with optional filtering by completion status",
70-
http_method="GET",
71-
http_path="/api/tasks"
72-
)
73-
async def op_list_tasks(filter: TaskFilter = TaskFilter.ALL) -> list[Task]:
74-
"""
75-
List tasks with optional filtering.
76-
77-
This operation serves BOTH:
78-
- REST API: GET /api/tasks?filter=...
79-
- MCP tool: list_tasks(filter=...)
80-
81-
Pydantic's TaskFilter enum automatically generates MCP schema!
82-
"""
83-
return task_service.list_tasks(filter)
84-
85-
86-
@operation(
87-
name="create_task",
88-
description="Create a new task with validation",
89-
http_method="POST",
90-
http_path="/api/tasks"
91-
)
92-
async def op_create_task(data: TaskCreate) -> Task:
93-
"""
94-
Create a new task.
95-
96-
Pydantic automatically:
97-
- Validates title is not empty
98-
- Trims whitespace
99-
- Generates JSON schema for MCP
100-
101-
Returns the created Task model.
102-
"""
103-
return task_service.create_task(data)
104-
105-
106-
@operation(
107-
name="get_task",
108-
description="Retrieve a specific task by its unique identifier",
109-
http_method="GET",
110-
http_path="/api/tasks/{task_id}"
111-
)
112-
async def op_get_task(task_id: str) -> Task | None:
113-
"""
114-
Get task by ID.
115-
116-
Returns None if not found - caller handles 404.
117-
"""
118-
return task_service.get_task(task_id)
119-
120-
121-
@operation(
122-
name="update_task",
123-
description="Update an existing task's properties",
124-
http_method="PUT",
125-
http_path="/api/tasks/{task_id}"
126-
)
127-
async def op_update_task(task_id: str, data: TaskUpdate) -> Task | None:
128-
"""
129-
Update task with validation.
130-
131-
TaskUpdate has all optional fields - only provided fields are updated.
132-
Pydantic validates any provided values automatically.
133-
134-
Returns None if task not found.
135-
"""
136-
return task_service.update_task(task_id, data)
137-
138-
139-
@operation(
140-
name="delete_task",
141-
description="Delete a task permanently by its identifier",
142-
http_method="DELETE",
143-
http_path="/api/tasks/{task_id}"
144-
)
145-
async def op_delete_task(task_id: str) -> bool:
146-
"""
147-
Delete task.
148-
149-
Returns True if deleted, False if not found.
150-
"""
151-
return task_service.delete_task(task_id)
152-
153-
154-
@operation(
155-
name="get_task_stats",
156-
description="Get summary statistics for all tasks",
157-
http_method="GET",
158-
http_path="/api/tasks/stats"
159-
)
160-
async def op_get_task_stats() -> TaskStats:
161-
"""
162-
Get task statistics.
163-
164-
Returns Pydantic TaskStats model with total, completed, pending counts.
165-
"""
166-
return task_service.get_stats()
167-
168-
169-
@operation(
170-
name="ollama_chat",
171-
description="Generate a chat completion using local Ollama LLM",
172-
http_method="POST",
173-
http_path="/api/ollama/chat"
174-
)
175-
async def op_ollama_chat(request: ChatRequest) -> ChatResponse:
176-
"""
177-
Chat with Ollama LLM.
178-
179-
Supports conversation history and configurable temperature.
180-
Pydantic automatically validates message format and parameters.
181-
182-
Returns the generated response with metadata.
183-
"""
184-
return await ollama_service.chat(request)
185-
186-
187-
@operation(
188-
name="list_ollama_models",
189-
description="List all available Ollama models on the local system",
190-
http_method="GET",
191-
http_path="/api/ollama/models"
192-
)
193-
async def op_list_ollama_models() -> ModelListResponse:
194-
"""
195-
List available Ollama models.
196-
197-
Returns list of models with name, size, and modification time.
198-
"""
199-
return await ollama_service.list_models()
64+
# Defined once in operations.py so REST, MCP, and agents share logic.
65+
# =========================================================================
20066

20167

20268
# ============================================================================
@@ -301,6 +167,84 @@ async def rest_list_ollama_models():
301167

302168

303169

170+
# ============================================================================
171+
# QA TICKETS ENDPOINT
172+
# ============================================================================
173+
174+
@app.route("/api/qa-tickets", methods=["GET"])
175+
async def get_qa_tickets():
176+
"""Get QA tickets that need escalation."""
177+
# Mock data - will be replaced with real database later
178+
tickets = [
179+
{
180+
"id": "INC-1001",
181+
"title": "Login page nicht erreichbar",
182+
"status": "Open",
183+
"priority": "High",
184+
"assignee": None,
185+
"createdAt": "2025-12-09T08:30:00Z",
186+
"updatedAt": "2025-12-09T08:30:00Z",
187+
"escalationNeeded": True,
188+
"description": "Benutzer können sich nicht anmelden. Die Login-Seite gibt einen 500-Fehler zurück. Betrifft alle Umgebungen.",
189+
"category": "QA",
190+
"reporter": "M. Schmidt",
191+
},
192+
{
193+
"id": "INC-1002",
194+
"title": "Performance-Problem im Dashboard",
195+
"status": "Open",
196+
"priority": "Medium",
197+
"assignee": None,
198+
"createdAt": "2025-12-09T10:15:00Z",
199+
"updatedAt": "2025-12-09T10:15:00Z",
200+
"escalationNeeded": True,
201+
"description": "Dashboard lädt sehr langsam (>10 Sekunden). API-Aufrufe scheinen blockiert zu sein.",
202+
"category": "QA",
203+
"reporter": "A. Müller",
204+
},
205+
{
206+
"id": "INC-1003",
207+
"title": "Datenverlust beim Speichern",
208+
"status": "Open",
209+
"priority": "Critical",
210+
"assignee": None,
211+
"createdAt": "2025-12-09T14:45:00Z",
212+
"updatedAt": "2025-12-09T14:45:00Z",
213+
"escalationNeeded": True,
214+
"description": "Formulardaten werden nicht gespeichert. Validierung schlägt fehl ohne Fehlermeldung.",
215+
"category": "QA",
216+
"reporter": "T. Weber",
217+
},
218+
{
219+
"id": "INC-1004",
220+
"title": "Export-Funktion fehlerhaft",
221+
"status": "Open",
222+
"priority": "Low",
223+
"assignee": None,
224+
"createdAt": "2025-12-10T09:00:00Z",
225+
"updatedAt": "2025-12-10T09:00:00Z",
226+
"escalationNeeded": True,
227+
"description": "CSV-Export generiert leere Dateien. Excel-Export funktioniert korrekt.",
228+
"category": "QA",
229+
"reporter": "L. Fischer",
230+
},
231+
{
232+
"id": "INC-1005",
233+
"title": "Notification-Service offline",
234+
"status": "Open",
235+
"priority": "High",
236+
"assignee": None,
237+
"createdAt": "2025-12-10T11:30:00Z",
238+
"updatedAt": "2025-12-10T11:30:00Z",
239+
"escalationNeeded": True,
240+
"description": "E-Mail-Benachrichtigungen werden nicht versendet. Queue läuft voll.",
241+
"category": "QA",
242+
"reporter": "K. Becker",
243+
},
244+
]
245+
return jsonify({"tickets": tickets})
246+
247+
304248
# ============================================================================
305249
# NON-TASK ENDPOINTS
306250
# ============================================================================

0 commit comments

Comments
 (0)