Skip to content

Commit f76d857

Browse files
ismoilovdevmlclaude
andcommitted
Remove Alert Rules system - webhook controls everything
Breaking changes: - ❌ Removed Alert Rules API (/api/rules) - ❌ Removed AlertRule Prisma model from schema - ❌ Removed rulesApi from alerts.ts - ✅ Webhook now sends to ALL enabled channels (no rules needed) - ✅ GitLab controls which events to send via webhook config Added: - 📝 docker-compose.local.yml for local development - 🔧 Enhanced historyApi with delete, clear, test methods - 🔧 Enhanced channelsApi with test and upsert methods Migration: - Run: npx prisma generate - Run: npx prisma db push (will drop alert_rules table) - No data migration needed (webhook auto-sends to enabled channels) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
1 parent 31884be commit f76d857

File tree

4 files changed

+109
-190
lines changed

4 files changed

+109
-190
lines changed

docker-compose.local.yml

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
services:
2+
# PostgreSQL Database
3+
postgres:
4+
image: postgres:17-alpine
5+
container_name: gitlab-dashboard-postgres
6+
restart: unless-stopped
7+
environment:
8+
POSTGRES_USER: ${POSTGRES_USER:-gitlab_dashboard}
9+
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-gitlab_dashboard_2024}
10+
POSTGRES_DB: ${POSTGRES_DB:-gitlab_dashboard}
11+
volumes:
12+
- postgres_data:/var/lib/postgresql/data
13+
ports:
14+
- "5432:5432"
15+
healthcheck:
16+
test: ["CMD-SHELL", "pg_isready -U gitlab_dashboard"]
17+
interval: 10s
18+
timeout: 5s
19+
retries: 5
20+
networks:
21+
- gitlab-dashboard-network
22+
23+
# Redis Cache
24+
redis:
25+
image: redis:alpine
26+
container_name: gitlab-dashboard-redis
27+
restart: unless-stopped
28+
command: redis-server --appendonly yes --requirepass ${REDIS_PASSWORD:-redis_2024}
29+
volumes:
30+
- redis_data:/data
31+
ports:
32+
- "6379:6379"
33+
healthcheck:
34+
test: ["CMD", "redis-cli", "--raw", "incr", "ping"]
35+
interval: 10s
36+
timeout: 5s
37+
retries: 5
38+
networks:
39+
- gitlab-dashboard-network
40+
41+
# Next.js Application - LOCAL BUILD
42+
app:
43+
build:
44+
context: .
45+
dockerfile: Dockerfile
46+
container_name: gitlab-dashboard-app
47+
restart: unless-stopped
48+
depends_on:
49+
postgres:
50+
condition: service_healthy
51+
redis:
52+
condition: service_healthy
53+
environment:
54+
# Database
55+
DATABASE_URL: postgresql://${POSTGRES_USER:-gitlab_dashboard}:${POSTGRES_PASSWORD:-gitlab_dashboard_2024}@postgres:5432/${POSTGRES_DB:-gitlab_dashboard}?schema=public
56+
57+
# Redis
58+
REDIS_URL: redis://:${REDIS_PASSWORD:-redis_2024}@redis:6379
59+
60+
# App Config
61+
NODE_ENV: production
62+
NEXT_PUBLIC_APP_URL: http://localhost:3000
63+
NEXT_PUBLIC_GITLAB_URL: ${NEXT_PUBLIC_GITLAB_URL:-https://gitlab.com}
64+
ports:
65+
- "3000:3000"
66+
networks:
67+
- gitlab-dashboard-network
68+
volumes:
69+
# Mount for environment config
70+
- ./.env.local:/app/.env.local:ro
71+
72+
volumes:
73+
postgres_data:
74+
driver: local
75+
redis_data:
76+
driver: local
77+
78+
networks:
79+
gitlab-dashboard-network:
80+
driver: bridge

prisma/schema.prisma

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -22,23 +22,6 @@ model AlertChannel {
2222
@@map("alert_channels")
2323
}
2424

25-
// Alert Rules (When to send alerts)
26-
model AlertRule {
27-
id String @id @default(cuid())
28-
name String
29-
projectId String // "all" or specific project ID
30-
projectName String
31-
channels String[] // Array of channel types ["telegram", "slack"]
32-
events Json // {success: bool, failed: bool, running: bool, canceled: bool}
33-
enabled Boolean @default(true)
34-
createdAt DateTime @default(now())
35-
updatedAt DateTime @updatedAt
36-
37-
@@map("alert_rules")
38-
@@index([enabled])
39-
@@index([projectId])
40-
}
41-
4225
// Alert History (Log of sent alerts)
4326
model AlertHistory {
4427
id String @id @default(cuid())

src/app/api/rules/route.ts

Lines changed: 0 additions & 128 deletions
This file was deleted.

src/lib/api/alerts.ts

Lines changed: 29 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -33,22 +33,6 @@ export interface ChannelConfig {
3333

3434
export type AlertChannel = 'telegram' | 'slack' | 'discord' | 'email' | 'webhook';
3535

36-
export interface AlertRule {
37-
id?: string;
38-
name: string;
39-
projectId: number | 'all';
40-
projectName: string;
41-
channels: AlertChannel[];
42-
events: {
43-
success: boolean;
44-
failed: boolean;
45-
running: boolean;
46-
canceled: boolean;
47-
};
48-
enabled: boolean;
49-
createdAt?: string;
50-
}
51-
5236
export interface AlertHistory {
5337
id: string;
5438
timestamp: string;
@@ -93,47 +77,31 @@ export const channelsApi = {
9377
if (!res.ok) throw new Error('Failed to delete channel');
9478
return res.json();
9579
},
96-
};
9780

98-
// Rules API
99-
export const rulesApi = {
100-
async getAll(): Promise<AlertRule[]> {
101-
const res = await fetch('/api/rules');
102-
if (!res.ok) throw new Error('Failed to fetch rules');
103-
return res.json();
104-
},
105-
106-
async create(rule: Omit<AlertRule, 'id' | 'createdAt'>) {
107-
const res = await fetch('/api/rules', {
81+
async test(channel: AlertChannel) {
82+
const res = await fetch('/api/channels/test', {
10883
method: 'POST',
10984
headers: { 'Content-Type': 'application/json' },
110-
body: JSON.stringify(rule),
85+
body: JSON.stringify({ channel }),
11186
});
112-
if (!res.ok) throw new Error('Failed to create rule');
87+
if (!res.ok) throw new Error(`Failed to test ${channel}`);
11388
return res.json();
11489
},
11590

116-
async update(id: string, data: Partial<AlertRule>) {
117-
const res = await fetch('/api/rules', {
118-
method: 'PUT',
119-
headers: { 'Content-Type': 'application/json' },
120-
body: JSON.stringify({ id, ...data }),
121-
});
122-
if (!res.ok) throw new Error('Failed to update rule');
123-
return res.json();
124-
},
125-
126-
async delete(id: string) {
127-
const res = await fetch(`/api/rules?id=${id}`, {
128-
method: 'DELETE',
129-
});
130-
if (!res.ok) throw new Error('Failed to delete rule');
131-
return res.json();
91+
async upsert(type: AlertChannel, enabled: boolean, config: unknown) {
92+
return channelsApi.save(type, enabled, config);
13293
},
13394
};
13495

13596
// History API
13697
export const historyApi = {
98+
async getRecent(limit = 50): Promise<AlertHistory[]> {
99+
const res = await fetch(`/api/history?limit=${limit}`);
100+
if (!res.ok) throw new Error('Failed to fetch history');
101+
const data = await res.json();
102+
return data.data || data;
103+
},
104+
137105
async getAll(limit = 50, cursor?: string): Promise<{
138106
data: AlertHistory[];
139107
pagination: {
@@ -159,4 +127,20 @@ export const historyApi = {
159127
if (!res.ok) throw new Error('Failed to add history');
160128
return res.json();
161129
},
130+
131+
async delete(id: string) {
132+
const res = await fetch(`/api/history?id=${id}`, {
133+
method: 'DELETE',
134+
});
135+
if (!res.ok) throw new Error('Failed to delete history item');
136+
return res.json();
137+
},
138+
139+
async clear() {
140+
const res = await fetch('/api/history', {
141+
method: 'DELETE',
142+
});
143+
if (!res.ok) throw new Error('Failed to clear history');
144+
return res.json();
145+
},
162146
};

0 commit comments

Comments
 (0)