From f0508ba953a40526a1159fc9962562cf4249e47e Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Wed, 3 Dec 2025 18:07:45 +0000
Subject: [PATCH 1/7] Initial plan
From 930e189c5a9ff461d1c38614e318ca96022cd956 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Wed, 3 Dec 2025 18:15:40 +0000
Subject: [PATCH 2/7] Initial plan for admin groups management feature
Co-authored-by: TheRealSeber <111927572+TheRealSeber@users.noreply.github.com>
---
logs/combined.log | 15 +++++++++++++++
logs/error.log | 5 +++++
2 files changed, 20 insertions(+)
create mode 100644 logs/combined.log
create mode 100644 logs/error.log
diff --git a/logs/combined.log b/logs/combined.log
new file mode 100644
index 0000000..607014a
--- /dev/null
+++ b/logs/combined.log
@@ -0,0 +1,15 @@
+{"level":"info","message":"Tool call received: getSwaggerDefinition","service":"swagger-mcp","timestamp":"2025-12-03 18:11:17"}
+{"level":"info","message":"Tool arguments: {\"url\":\"http://localhost:8000/swagger/doc.json\",\"saveLocation\":\"/home/runner/work/frontend/frontend\"}","service":"swagger-mcp","timestamp":"2025-12-03 18:11:17"}
+{"level":"info","message":"Calling swaggerService.getSwaggerDefinition()","service":"swagger-mcp","timestamp":"2025-12-03 18:11:17"}
+{"level":"info","message":"Query parameters: {\"url\":\"http://localhost:8000/swagger/doc.json\",\"saveLocation\":\"/home/runner/work/frontend/frontend\"}","service":"swagger-mcp","timestamp":"2025-12-03 18:11:17"}
+{"level":"info","message":"Fetching Swagger definition from http://localhost:8000/swagger/doc.json","service":"swagger-mcp","timestamp":"2025-12-03 18:11:17"}
+{"level":"error","message":"Swagger API error: ","service":"swagger-mcp","timestamp":"2025-12-03 18:11:17"}
+{"level":"error","message":"Error in getSwaggerDefinition handler: Failed to fetch Swagger definition","service":"swagger-mcp","timestamp":"2025-12-03 18:11:17"}
+{"level":"info","message":"Tool call received: getSwaggerDefinition","service":"swagger-mcp","timestamp":"2025-12-03 18:13:19"}
+{"level":"info","message":"Tool arguments: {\"saveLocation\":\"/home/runner/work/frontend/frontend\",\"url\":\"https://mini-maxit.github.io/backend/master/swagger.yaml\"}","service":"swagger-mcp","timestamp":"2025-12-03 18:13:19"}
+{"level":"info","message":"Calling swaggerService.getSwaggerDefinition()","service":"swagger-mcp","timestamp":"2025-12-03 18:13:19"}
+{"level":"info","message":"Query parameters: {\"saveLocation\":\"/home/runner/work/frontend/frontend\",\"url\":\"https://mini-maxit.github.io/backend/master/swagger.yaml\"}","service":"swagger-mcp","timestamp":"2025-12-03 18:13:19"}
+{"level":"info","message":"Fetching Swagger definition from https://mini-maxit.github.io/backend/master/swagger.yaml","service":"swagger-mcp","timestamp":"2025-12-03 18:13:19"}
+{"level":"error","message":"Invalid Swagger definition","service":"swagger-mcp","timestamp":"2025-12-03 18:13:19"}
+{"level":"error","message":"Swagger API error: Invalid Swagger definition","service":"swagger-mcp","timestamp":"2025-12-03 18:13:19"}
+{"level":"error","message":"Error in getSwaggerDefinition handler: Failed to fetch Swagger definition","service":"swagger-mcp","timestamp":"2025-12-03 18:13:19"}
diff --git a/logs/error.log b/logs/error.log
new file mode 100644
index 0000000..97379cb
--- /dev/null
+++ b/logs/error.log
@@ -0,0 +1,5 @@
+{"level":"error","message":"Swagger API error: ","service":"swagger-mcp","timestamp":"2025-12-03 18:11:17"}
+{"level":"error","message":"Error in getSwaggerDefinition handler: Failed to fetch Swagger definition","service":"swagger-mcp","timestamp":"2025-12-03 18:11:17"}
+{"level":"error","message":"Invalid Swagger definition","service":"swagger-mcp","timestamp":"2025-12-03 18:13:19"}
+{"level":"error","message":"Swagger API error: Invalid Swagger definition","service":"swagger-mcp","timestamp":"2025-12-03 18:13:19"}
+{"level":"error","message":"Error in getSwaggerDefinition handler: Failed to fetch Swagger definition","service":"swagger-mcp","timestamp":"2025-12-03 18:13:19"}
From 05403062c6b6aaf768cb7504e9c6f05b0d200e5f Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Wed, 3 Dec 2025 18:23:20 +0000
Subject: [PATCH 3/7] Add admin groups management interface with list view and
search
Co-authored-by: TheRealSeber <111927572+TheRealSeber@users.noreply.github.com>
---
.gitignore | 7 ++
logs/combined.log | 15 ---
logs/error.log | 5 -
messages/en.json | 19 +++-
messages/pl.json | 19 +++-
.../dashboard/DashboardSidebar.svelte | 6 ++
.../dashboard/admin/groups/GroupsList.svelte | 99 +++++++++++++++++++
.../dashboard/admin/groups/index.ts | 1 +
src/lib/components/dashboard/utils.ts | 3 +-
src/lib/dto/group.ts | 15 +++
src/lib/routes.ts | 1 +
src/lib/services/GroupService.ts | 53 ++++++++++
src/lib/services/index.ts | 1 +
.../dashboard/admin/groups/+page.svelte | 87 ++++++++++++++++
.../dashboard/admin/groups/groups.remote.ts | 20 ++++
15 files changed, 328 insertions(+), 23 deletions(-)
delete mode 100644 logs/combined.log
delete mode 100644 logs/error.log
create mode 100644 src/lib/components/dashboard/admin/groups/GroupsList.svelte
create mode 100644 src/lib/components/dashboard/admin/groups/index.ts
create mode 100644 src/lib/dto/group.ts
create mode 100644 src/lib/services/GroupService.ts
create mode 100644 src/routes/dashboard/admin/groups/+page.svelte
create mode 100644 src/routes/dashboard/admin/groups/groups.remote.ts
diff --git a/.gitignore b/.gitignore
index 7c6e593..05b8a8f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -28,3 +28,10 @@ vite.config.ts.timestamp-*
# Paraglide
src/lib/paraglide
+
+# Logs
+logs
+
+# Swagger MCP
+swagger.json
+.swagger-mcp
diff --git a/logs/combined.log b/logs/combined.log
deleted file mode 100644
index 607014a..0000000
--- a/logs/combined.log
+++ /dev/null
@@ -1,15 +0,0 @@
-{"level":"info","message":"Tool call received: getSwaggerDefinition","service":"swagger-mcp","timestamp":"2025-12-03 18:11:17"}
-{"level":"info","message":"Tool arguments: {\"url\":\"http://localhost:8000/swagger/doc.json\",\"saveLocation\":\"/home/runner/work/frontend/frontend\"}","service":"swagger-mcp","timestamp":"2025-12-03 18:11:17"}
-{"level":"info","message":"Calling swaggerService.getSwaggerDefinition()","service":"swagger-mcp","timestamp":"2025-12-03 18:11:17"}
-{"level":"info","message":"Query parameters: {\"url\":\"http://localhost:8000/swagger/doc.json\",\"saveLocation\":\"/home/runner/work/frontend/frontend\"}","service":"swagger-mcp","timestamp":"2025-12-03 18:11:17"}
-{"level":"info","message":"Fetching Swagger definition from http://localhost:8000/swagger/doc.json","service":"swagger-mcp","timestamp":"2025-12-03 18:11:17"}
-{"level":"error","message":"Swagger API error: ","service":"swagger-mcp","timestamp":"2025-12-03 18:11:17"}
-{"level":"error","message":"Error in getSwaggerDefinition handler: Failed to fetch Swagger definition","service":"swagger-mcp","timestamp":"2025-12-03 18:11:17"}
-{"level":"info","message":"Tool call received: getSwaggerDefinition","service":"swagger-mcp","timestamp":"2025-12-03 18:13:19"}
-{"level":"info","message":"Tool arguments: {\"saveLocation\":\"/home/runner/work/frontend/frontend\",\"url\":\"https://mini-maxit.github.io/backend/master/swagger.yaml\"}","service":"swagger-mcp","timestamp":"2025-12-03 18:13:19"}
-{"level":"info","message":"Calling swaggerService.getSwaggerDefinition()","service":"swagger-mcp","timestamp":"2025-12-03 18:13:19"}
-{"level":"info","message":"Query parameters: {\"saveLocation\":\"/home/runner/work/frontend/frontend\",\"url\":\"https://mini-maxit.github.io/backend/master/swagger.yaml\"}","service":"swagger-mcp","timestamp":"2025-12-03 18:13:19"}
-{"level":"info","message":"Fetching Swagger definition from https://mini-maxit.github.io/backend/master/swagger.yaml","service":"swagger-mcp","timestamp":"2025-12-03 18:13:19"}
-{"level":"error","message":"Invalid Swagger definition","service":"swagger-mcp","timestamp":"2025-12-03 18:13:19"}
-{"level":"error","message":"Swagger API error: Invalid Swagger definition","service":"swagger-mcp","timestamp":"2025-12-03 18:13:19"}
-{"level":"error","message":"Error in getSwaggerDefinition handler: Failed to fetch Swagger definition","service":"swagger-mcp","timestamp":"2025-12-03 18:13:19"}
diff --git a/logs/error.log b/logs/error.log
deleted file mode 100644
index 97379cb..0000000
--- a/logs/error.log
+++ /dev/null
@@ -1,5 +0,0 @@
-{"level":"error","message":"Swagger API error: ","service":"swagger-mcp","timestamp":"2025-12-03 18:11:17"}
-{"level":"error","message":"Error in getSwaggerDefinition handler: Failed to fetch Swagger definition","service":"swagger-mcp","timestamp":"2025-12-03 18:11:17"}
-{"level":"error","message":"Invalid Swagger definition","service":"swagger-mcp","timestamp":"2025-12-03 18:13:19"}
-{"level":"error","message":"Swagger API error: Invalid Swagger definition","service":"swagger-mcp","timestamp":"2025-12-03 18:13:19"}
-{"level":"error","message":"Error in getSwaggerDefinition handler: Failed to fetch Swagger definition","service":"swagger-mcp","timestamp":"2025-12-03 18:13:19"}
diff --git a/messages/en.json b/messages/en.json
index e68f2c4..184c15d 100644
--- a/messages/en.json
+++ b/messages/en.json
@@ -490,5 +490,22 @@
"admin_users_pagination_total": "{total} total users",
"admin_users_pagination_prev": "Previous",
"admin_users_pagination_next": "Next",
- "admin_users_pagination_showing_range": "Showing {from}-{to} of {total} users"
+ "admin_users_pagination_showing_range": "Showing {from}-{to} of {total} users",
+ "admin_groups_title": "Group Management",
+ "admin_groups_search_filter": "Search & Filter",
+ "admin_groups_search_placeholder": "Search by group name...",
+ "admin_groups_all_groups": "All Groups",
+ "admin_groups_showing_count": "Showing {count} of {total} groups",
+ "admin_groups_load_error": "Failed to load groups",
+ "admin_groups_no_groups_title": "No groups found",
+ "admin_groups_no_groups_description": "There are no groups in the system yet.",
+ "admin_groups_no_matching_title": "No matching groups",
+ "admin_groups_no_matching_description": "No groups match your search criteria. Try adjusting your filters.",
+ "admin_groups_column_id": "ID",
+ "admin_groups_column_name": "Name",
+ "admin_groups_column_created_by": "Created By",
+ "admin_groups_column_created_at": "Created",
+ "admin_groups_column_updated_at": "Updated",
+ "admin_groups_created_by_prefix": "User #",
+ "sidebar_admin_groups": "Groups"
}
diff --git a/messages/pl.json b/messages/pl.json
index 00e55df..fd027a8 100644
--- a/messages/pl.json
+++ b/messages/pl.json
@@ -490,5 +490,22 @@
"admin_users_pagination_total": "{total} użytkowników łącznie",
"admin_users_pagination_prev": "Poprzednia",
"admin_users_pagination_next": "Następna",
- "admin_users_pagination_showing_range": "Wyświetlanie {from}-{to} z {total} użytkowników"
+ "admin_users_pagination_showing_range": "Wyświetlanie {from}-{to} z {total} użytkowników",
+ "admin_groups_title": "Zarządzanie Grupami",
+ "admin_groups_search_filter": "Szukaj i Filtruj",
+ "admin_groups_search_placeholder": "Szukaj po nazwie grupy...",
+ "admin_groups_all_groups": "Wszystkie Grupy",
+ "admin_groups_showing_count": "Wyświetlanie {count} z {total} grup",
+ "admin_groups_load_error": "Nie udało się załadować grup",
+ "admin_groups_no_groups_title": "Nie znaleziono grup",
+ "admin_groups_no_groups_description": "W systemie nie ma jeszcze żadnych grup.",
+ "admin_groups_no_matching_title": "Brak pasujących grup",
+ "admin_groups_no_matching_description": "Żadne grupy nie pasują do kryteriów wyszukiwania. Spróbuj dostosować filtry.",
+ "admin_groups_column_id": "ID",
+ "admin_groups_column_name": "Nazwa",
+ "admin_groups_column_created_by": "Utworzony przez",
+ "admin_groups_column_created_at": "Utworzono",
+ "admin_groups_column_updated_at": "Zaktualizowano",
+ "admin_groups_created_by_prefix": "Użytkownik #",
+ "sidebar_admin_groups": "Grupy"
}
diff --git a/src/lib/components/dashboard/DashboardSidebar.svelte b/src/lib/components/dashboard/DashboardSidebar.svelte
index 92f9a14..44c56bc 100644
--- a/src/lib/components/dashboard/DashboardSidebar.svelte
+++ b/src/lib/components/dashboard/DashboardSidebar.svelte
@@ -24,6 +24,7 @@
import Globe from '@lucide/svelte/icons/globe';
import UserCircle from '@lucide/svelte/icons/user-circle';
import Users from '@lucide/svelte/icons/users';
+ import FolderOpen from '@lucide/svelte/icons/folder-open';
import Languages from '@lucide/svelte/icons/languages';
import LayoutDashboard from '@lucide/svelte/icons/layout-dashboard';
import Activity from '@lucide/svelte/icons/activity';
@@ -90,6 +91,11 @@
title: () => m.sidebar_admin_users(),
href: localizeHref(AppRoutes.AdminUsers),
icon: Users
+ },
+ {
+ title: () => m.sidebar_admin_groups(),
+ href: localizeHref(AppRoutes.AdminGroups),
+ icon: FolderOpen
}
];
diff --git a/src/lib/components/dashboard/admin/groups/GroupsList.svelte b/src/lib/components/dashboard/admin/groups/GroupsList.svelte
new file mode 100644
index 0000000..f5d4416
--- /dev/null
+++ b/src/lib/components/dashboard/admin/groups/GroupsList.svelte
@@ -0,0 +1,99 @@
+
+
+
+
+
+
+ {m.admin_groups_showing_count({
+ count: groups.length,
+ total: groups.length
+ })}
+
+
+
+
+
+
+
+
+ {m.admin_groups_column_id()}
+
+
+ {m.admin_groups_column_name()}
+
+
+ {m.admin_groups_column_created_by()}
+
+
+ {m.admin_groups_column_created_at()}
+
+
+ {m.admin_groups_column_updated_at()}
+
+
+
+
+
+ {#each groups as group (group.id)}
+
+ {group.id}
+
+
+
+
+
+
+ {group.name}
+
+
+
+
+
+
+ {m.admin_groups_created_by_prefix()}{group.createdBy}
+
+
+
+
+
+
+ {formatCreatedAt(group.createdAt)}
+
+
+
+
+
+
+
+ {formatCreatedAt(group.updatedAt)}
+
+
+
+
+ {/each}
+
+
+
diff --git a/src/lib/components/dashboard/admin/groups/index.ts b/src/lib/components/dashboard/admin/groups/index.ts
new file mode 100644
index 0000000..47bd09b
--- /dev/null
+++ b/src/lib/components/dashboard/admin/groups/index.ts
@@ -0,0 +1 @@
+export { default as GroupsList } from './GroupsList.svelte';
diff --git a/src/lib/components/dashboard/utils.ts b/src/lib/components/dashboard/utils.ts
index ba85a90..dc11c93 100644
--- a/src/lib/components/dashboard/utils.ts
+++ b/src/lib/components/dashboard/utils.ts
@@ -17,7 +17,8 @@ export function getDashboardTitleTranslationFromPathname(pathname: string): stri
[AppRoutes.Admin]: () => m.sidebar_admin(),
[AppRoutes.TeacherContests]: () => m.sidebar_admin_contests(),
[AppRoutes.TeacherTasks]: () => m.sidebar_admin_tasks(),
- [AppRoutes.AdminUsers]: () => m.admin_users_title()
+ [AppRoutes.AdminUsers]: () => m.admin_users_title(),
+ [AppRoutes.AdminGroups]: () => m.admin_groups_title()
};
// Check for dynamic routes (e.g., /dashboard/tasks/[taskId])
diff --git a/src/lib/dto/group.ts b/src/lib/dto/group.ts
new file mode 100644
index 0000000..55c2416
--- /dev/null
+++ b/src/lib/dto/group.ts
@@ -0,0 +1,15 @@
+export interface Group {
+ id: number;
+ name: string;
+ createdBy: number;
+ createdAt: string;
+ updatedAt: string;
+}
+
+export interface CreateGroupDto {
+ name: string;
+}
+
+export interface EditGroupDto {
+ name?: string;
+}
diff --git a/src/lib/routes.ts b/src/lib/routes.ts
index 5d3c2eb..86f9585 100644
--- a/src/lib/routes.ts
+++ b/src/lib/routes.ts
@@ -27,6 +27,7 @@ export enum AppRoutes {
Admin = `${AppRoutes.Dashboard}/admin`,
AdminUsers = `${AppRoutes.Admin}/users`,
+ AdminGroups = `${AppRoutes.Admin}/groups`,
Error = '/error'
}
diff --git a/src/lib/services/GroupService.ts b/src/lib/services/GroupService.ts
new file mode 100644
index 0000000..a9481d2
--- /dev/null
+++ b/src/lib/services/GroupService.ts
@@ -0,0 +1,53 @@
+import { ApiError, type ApiService } from './ApiService';
+import type { ApiResponse } from '../dto/response';
+import type { Group } from '../dto/group';
+
+export class GroupService {
+ constructor(private apiService: ApiService) {}
+
+ async listGroups(): Promise<{
+ success: boolean;
+ status: number;
+ data?: Group[];
+ error?: string;
+ }> {
+ try {
+ const response: ApiResponse = await this.apiService.get({
+ url: '/groups/'
+ });
+ return { success: true, data: response.data, status: 200 };
+ } catch (error) {
+ if (error instanceof ApiError) {
+ return {
+ success: false,
+ error: error.getApiMessage(),
+ status: error.getStatus()
+ };
+ }
+ throw error;
+ }
+ }
+
+ async getGroup(groupId: number): Promise<{
+ success: boolean;
+ status: number;
+ data?: Group;
+ error?: string;
+ }> {
+ try {
+ const response: ApiResponse = await this.apiService.get({
+ url: `/groups/${groupId}`
+ });
+ return { success: true, data: response.data, status: 200 };
+ } catch (error) {
+ if (error instanceof ApiError) {
+ return {
+ success: false,
+ error: error.getApiMessage(),
+ status: error.getStatus()
+ };
+ }
+ throw error;
+ }
+ }
+}
diff --git a/src/lib/services/index.ts b/src/lib/services/index.ts
index be1a8c5..4298c0e 100644
--- a/src/lib/services/index.ts
+++ b/src/lib/services/index.ts
@@ -5,6 +5,7 @@ export {
ContestsManagementService,
createContestsManagementService
} from './ContestsManagementService';
+export { GroupService } from './GroupService';
export { SubmissionService } from './SubmissionService';
export { TaskService, createTaskService } from './TaskService';
export { TasksManagementService } from './TasksManagementService';
diff --git a/src/routes/dashboard/admin/groups/+page.svelte b/src/routes/dashboard/admin/groups/+page.svelte
new file mode 100644
index 0000000..c009a9d
--- /dev/null
+++ b/src/routes/dashboard/admin/groups/+page.svelte
@@ -0,0 +1,87 @@
+
+
+
+
+
{m.admin_groups_title()}
+
+
+
+
{m.admin_groups_search_filter()}
+
+
+
+
+
+
+
{m.admin_groups_all_groups()}
+ {#if groupsQuery.current}
+
+ {m.admin_groups_showing_count({
+ count: filteredGroups.length,
+ total: filteredGroups.length
+ })}
+
+ {/if}
+
+
+ {#if groupsQuery.error}
+
groupsQuery.refresh()}
+ />
+ {:else if groupsQuery.loading}
+
+ {:else if groupsQuery.current && groupsQuery.current.items.length === 0}
+
+ {:else if filteredGroups.length === 0}
+
+ {:else}
+
+ {/if}
+
+
diff --git a/src/routes/dashboard/admin/groups/groups.remote.ts b/src/routes/dashboard/admin/groups/groups.remote.ts
new file mode 100644
index 0000000..91ef079
--- /dev/null
+++ b/src/routes/dashboard/admin/groups/groups.remote.ts
@@ -0,0 +1,20 @@
+import { query, getRequestEvent } from '$app/server';
+import { createApiClient } from '$lib/services/ApiService';
+import { GroupService } from '$lib/services/GroupService';
+import { error } from '@sveltejs/kit';
+
+export const getGroups = query(async () => {
+ const event = getRequestEvent();
+ const apiClient = createApiClient(event.cookies);
+ const groupService = new GroupService(apiClient);
+
+ const result = await groupService.listGroups();
+
+ if (!result.success || !result.data) {
+ error(result.status, { message: result.error || 'Failed to fetch groups.' });
+ }
+
+ return {
+ items: result.data
+ };
+});
From 537c806281dd3b9583d5026a2949b3abbfa208c2 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Wed, 3 Dec 2025 18:26:57 +0000
Subject: [PATCH 4/7] Fix count/total display in groups list to show proper
filtered vs total counts
Co-authored-by: TheRealSeber <111927572+TheRealSeber@users.noreply.github.com>
---
src/lib/components/dashboard/admin/groups/GroupsList.svelte | 5 +++--
src/routes/dashboard/admin/groups/+page.svelte | 4 ++--
2 files changed, 5 insertions(+), 4 deletions(-)
diff --git a/src/lib/components/dashboard/admin/groups/GroupsList.svelte b/src/lib/components/dashboard/admin/groups/GroupsList.svelte
index f5d4416..aa77151 100644
--- a/src/lib/components/dashboard/admin/groups/GroupsList.svelte
+++ b/src/lib/components/dashboard/admin/groups/GroupsList.svelte
@@ -9,9 +9,10 @@
interface GroupsListProps {
groups: Group[];
+ total: number;
}
- let { groups }: GroupsListProps = $props();
+ let { groups, total }: GroupsListProps = $props();
function formatCreatedAt(createdAt: string): string {
const date = new Date(createdAt);
@@ -29,7 +30,7 @@
{m.admin_groups_showing_count({
count: groups.length,
- total: groups.length
+ total: total
})}
diff --git a/src/routes/dashboard/admin/groups/+page.svelte b/src/routes/dashboard/admin/groups/+page.svelte
index c009a9d..a49f7a5 100644
--- a/src/routes/dashboard/admin/groups/+page.svelte
+++ b/src/routes/dashboard/admin/groups/+page.svelte
@@ -54,7 +54,7 @@
{m.admin_groups_showing_count({
count: filteredGroups.length,
- total: filteredGroups.length
+ total: groupsQuery.current.items.length
})}
{/if}
@@ -81,7 +81,7 @@
icon={FolderOpen}
/>
{:else}
-
+
{/if}
From 8bc2fb588d0999b68dd5d5b6c79fd6929e16af1a Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Wed, 3 Dec 2025 18:29:18 +0000
Subject: [PATCH 5/7] Add Swagger YAML to JSON conversion in setup steps and
document Swagger MCP usage
Co-authored-by: TheRealSeber <111927572+TheRealSeber@users.noreply.github.com>
---
.github/copilot-instructions.md | 81 +++++++++++++++++++++++
.github/workflows/copilot-setup-steps.yml | 14 ++++
2 files changed, 95 insertions(+)
diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md
index c8abc77..045228e 100644
--- a/.github/copilot-instructions.md
+++ b/.github/copilot-instructions.md
@@ -335,6 +335,87 @@ const taskService = new TaskService(apiClient);
- Services handle all error states - check `result.success` before accessing data
- Services return consistent response format: `{ success, status, data?, error? }`
+## Using Swagger MCP for Backend API
+
+This project has access to the **Swagger MCP server** for exploring the backend API definition. The Swagger definition is automatically downloaded and converted from YAML to JSON during the Copilot setup steps.
+
+### Pre-configured Files
+
+The setup creates:
+- `swagger.json` - The converted Swagger/OpenAPI definition
+- `.swagger-mcp` - Configuration file with the path to swagger.json
+
+### Available Swagger MCP Tools
+
+#### 1. listEndpoints
+
+Lists all available API endpoints with their HTTP methods and descriptions:
+
+```
+swagger-listEndpoints(swaggerFilePath: "/path/to/swagger.json")
+```
+
+#### 2. listEndpointModels
+
+Shows the request/response models for a specific endpoint:
+
+```
+swagger-listEndpointModels(
+ swaggerFilePath: "/path/to/swagger.json",
+ path: "/groups/",
+ method: "GET"
+)
+```
+
+#### 3. generateModelCode
+
+Generates TypeScript interfaces from Swagger model definitions:
+
+```
+swagger-generateModelCode(
+ swaggerFilePath: "/path/to/swagger.json",
+ modelName: "Group"
+)
+```
+
+#### 4. generateEndpointToolCode
+
+Generates TypeScript code for calling an API endpoint:
+
+```
+swagger-generateEndpointToolCode(
+ swaggerFilePath: "/path/to/swagger.json",
+ path: "/groups/",
+ method: "GET"
+)
+```
+
+### When to Use Swagger MCP
+
+- **Exploring new API endpoints**: Use `listEndpoints` to discover available APIs
+- **Understanding request/response formats**: Use `listEndpointModels` and `generateModelCode`
+- **Creating new services**: Reference the generated TypeScript interfaces for DTOs
+- **Verifying API contracts**: Ensure your service implementations match the backend API
+
+### Example Workflow
+
+1. List all endpoints to find the one you need:
+ ```
+ swagger-listEndpoints(swaggerFilePath: "swagger.json")
+ ```
+
+2. Get the models for that endpoint:
+ ```
+ swagger-listEndpointModels(swaggerFilePath: "swagger.json", path: "/groups/", method: "GET")
+ ```
+
+3. Generate TypeScript interface for the model:
+ ```
+ swagger-generateModelCode(swaggerFilePath: "swagger.json", modelName: "Group")
+ ```
+
+4. Use the generated interface to create your DTO in `/src/lib/dto/`
+
## Internationalization (i18n)
This project uses **Paraglide** for internationalization with support for **English (en)** and **Polish (pl)**.
diff --git a/.github/workflows/copilot-setup-steps.yml b/.github/workflows/copilot-setup-steps.yml
index ebeb561..4b424c3 100644
--- a/.github/workflows/copilot-setup-steps.yml
+++ b/.github/workflows/copilot-setup-steps.yml
@@ -43,6 +43,20 @@ jobs:
npm run build
echo "Swagger MCP server built successfully"
+ - name: Download and convert Swagger definition
+ run: |
+ # Download YAML swagger definition from backend docs
+ curl -s "https://mini-maxit.github.io/backend/master/swagger.yaml" -o /tmp/swagger.yaml
+
+ # Convert YAML to JSON using Python (available on ubuntu-latest)
+ python3 -c "import yaml, json; print(json.dumps(yaml.safe_load(open('/tmp/swagger.yaml')), indent=2))" > swagger.json
+
+ # Create .swagger-mcp config file pointing to the JSON file
+ echo "SWAGGER_FILEPATH=$(pwd)/swagger.json" > .swagger-mcp
+
+ echo "Swagger definition downloaded and converted successfully"
+ echo "Config file created at .swagger-mcp"
+
- name: Prepare project (sync, typecheck, lint)
# Using || true to allow Copilot to start even with minor typecheck/lint issues
run: |
From cab1629b47e24d8e6143e0c7c6875cfb7403d1bd Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Sun, 7 Dec 2025 15:24:17 +0000
Subject: [PATCH 6/7] Update GroupService to use /groups-management endpoint
Co-authored-by: HermanPlay <78978614+HermanPlay@users.noreply.github.com>
---
src/lib/services/GroupService.ts | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/lib/services/GroupService.ts b/src/lib/services/GroupService.ts
index a9481d2..86676b4 100644
--- a/src/lib/services/GroupService.ts
+++ b/src/lib/services/GroupService.ts
@@ -13,7 +13,7 @@ export class GroupService {
}> {
try {
const response: ApiResponse = await this.apiService.get({
- url: '/groups/'
+ url: '/groups-management/'
});
return { success: true, data: response.data, status: 200 };
} catch (error) {
@@ -36,7 +36,7 @@ export class GroupService {
}> {
try {
const response: ApiResponse = await this.apiService.get({
- url: `/groups/${groupId}`
+ url: `/groups-management/${groupId}`
});
return { success: true, data: response.data, status: 200 };
} catch (error) {
From 08d470d5c5d5d746c2c867fa9e152a6de1b55b18 Mon Sep 17 00:00:00 2001
From: HermanPlay
Date: Sun, 7 Dec 2025 16:28:42 +0100
Subject: [PATCH 7/7] fix: update endpoint path
---
src/lib/services/GroupService.ts | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/lib/services/GroupService.ts b/src/lib/services/GroupService.ts
index 86676b4..edcb8e5 100644
--- a/src/lib/services/GroupService.ts
+++ b/src/lib/services/GroupService.ts
@@ -13,7 +13,7 @@ export class GroupService {
}> {
try {
const response: ApiResponse = await this.apiService.get({
- url: '/groups-management/'
+ url: '/groups-management/groups'
});
return { success: true, data: response.data, status: 200 };
} catch (error) {
@@ -36,7 +36,7 @@ export class GroupService {
}> {
try {
const response: ApiResponse = await this.apiService.get({
- url: `/groups-management/${groupId}`
+ url: `/groups-management/groups/${groupId}`
});
return { success: true, data: response.data, status: 200 };
} catch (error) {