Skip to content

Commit 8746a09

Browse files
committed
feat: add event management backend and frontend integration
1 parent 6990789 commit 8746a09

16 files changed

Lines changed: 1799 additions & 44 deletions

File tree

bootstrap/http_handler.go

Lines changed: 38 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,47 +1,50 @@
11
package bootstrap
22

33
import (
4-
"context"
5-
"fmt"
6-
"net/http"
4+
"context"
5+
"fmt"
6+
"net/http"
77

8-
"eventra/internal/config"
9-
"eventra/internal/delivery/httpserver"
10-
"eventra/internal/repository/postgres"
11-
"eventra/internal/usecase/auth"
12-
"eventra/pkg/database"
13-
"eventra/pkg/security"
8+
"eventra/internal/config"
9+
"eventra/internal/delivery/httpserver"
10+
"eventra/internal/repository/postgres"
11+
"eventra/internal/usecase/auth"
12+
usecaseevent "eventra/internal/usecase/event"
13+
"eventra/pkg/database"
14+
"eventra/pkg/security"
1415
)
1516

1617
func NewHTTPHandler(ctx context.Context) (http.Handler, error) {
17-
cfg, err := config.Load()
18-
if err != nil {
19-
return nil, fmt.Errorf("load config: %w", err)
20-
}
18+
cfg, err := config.Load()
19+
if err != nil {
20+
return nil, fmt.Errorf("load config: %w", err)
21+
}
2122

22-
dbPool, err := database.NewPostgresPool(ctx, cfg.DBURL)
23-
if err != nil {
24-
return nil, fmt.Errorf("connect database: %w", err)
25-
}
23+
dbPool, err := database.NewPostgresPool(ctx, cfg.DBURL)
24+
if err != nil {
25+
return nil, fmt.Errorf("connect database: %w", err)
26+
}
2627

27-
jwtManager := security.NewJWTManager(cfg.JWTSecret, cfg.JWTExpiration)
28-
userRepo := postgres.NewUserRepository(dbPool)
29-
refreshRepo := postgres.NewRefreshTokenRepository(dbPool)
30-
securityRepo := postgres.NewLoginSecurityRepository(dbPool)
31-
auditRepo := postgres.NewSecurityAuditRepository(dbPool, cfg.SecurityAlertWebhookURL, cfg.SecurityAlertWebhookFormat)
32-
tokenBlacklistRepo := postgres.NewTokenBlacklistRepository(dbPool)
28+
jwtManager := security.NewJWTManager(cfg.JWTSecret, cfg.JWTExpiration)
29+
userRepo := postgres.NewUserRepository(dbPool)
30+
refreshRepo := postgres.NewRefreshTokenRepository(dbPool)
31+
securityRepo := postgres.NewLoginSecurityRepository(dbPool)
32+
auditRepo := postgres.NewSecurityAuditRepository(dbPool, cfg.SecurityAlertWebhookURL, cfg.SecurityAlertWebhookFormat)
33+
tokenBlacklistRepo := postgres.NewTokenBlacklistRepository(dbPool)
3334

34-
authService := auth.NewService(
35-
userRepo,
36-
refreshRepo,
37-
jwtManager,
38-
cfg.RefreshTokenExpiration,
39-
auth.WithLoginSecurityRepository(securityRepo),
40-
auth.WithAuditLogger(auditRepo),
41-
auth.WithTokenBlacklist(tokenBlacklistRepo),
42-
)
35+
authService := auth.NewService(
36+
userRepo,
37+
refreshRepo,
38+
jwtManager,
39+
cfg.RefreshTokenExpiration,
40+
auth.WithLoginSecurityRepository(securityRepo),
41+
auth.WithAuditLogger(auditRepo),
42+
auth.WithTokenBlacklist(tokenBlacklistRepo),
43+
)
44+
eventService := usecaseevent.NewService(postgres.NewEventRepository(dbPool))
4345

44-
authHandler := httpserver.NewAuthHandler(authService)
45-
router := httpserver.NewRouter(authHandler, jwtManager, tokenBlacklistRepo, cfg.CORSAllowedOrigins)
46-
return router, nil
46+
authHandler := httpserver.NewAuthHandler(authService)
47+
eventHandler := httpserver.NewEventHandler(eventService)
48+
router := httpserver.NewRouter(authHandler, eventHandler, jwtManager, tokenBlacklistRepo, cfg.CORSAllowedOrigins)
49+
return router, nil
4750
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
DROP TABLE IF EXISTS events;
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
CREATE EXTENSION IF NOT EXISTS pg_trgm;
2+
3+
CREATE TABLE IF NOT EXISTS events (
4+
id UUID PRIMARY KEY,
5+
organizer_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
6+
title TEXT NOT NULL,
7+
description TEXT NOT NULL DEFAULT '',
8+
event_date TIMESTAMPTZ NOT NULL,
9+
location TEXT NOT NULL,
10+
visibility TEXT NOT NULL DEFAULT 'public' CHECK (visibility IN ('public', 'private')),
11+
participant_limit INT,
12+
category TEXT,
13+
tags TEXT[] NOT NULL DEFAULT '{}',
14+
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
15+
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
16+
CONSTRAINT participant_limit_non_negative CHECK (participant_limit IS NULL OR participant_limit >= 0)
17+
);
18+
19+
CREATE INDEX IF NOT EXISTS idx_events_event_date ON events(event_date);
20+
CREATE INDEX IF NOT EXISTS idx_events_visibility_event_date ON events(visibility, event_date DESC);
21+
CREATE INDEX IF NOT EXISTS idx_events_organizer_id ON events(organizer_id);
22+
CREATE INDEX IF NOT EXISTS idx_events_category ON events(category);
23+
CREATE INDEX IF NOT EXISTS idx_events_location ON events(location);
24+
CREATE INDEX IF NOT EXISTS idx_events_tags_gin ON events USING GIN (tags);
25+
CREATE INDEX IF NOT EXISTS idx_events_title_trgm ON events USING GIN (title gin_trgm_ops);
26+
CREATE INDEX IF NOT EXISTS idx_events_description_trgm ON events USING GIN (description gin_trgm_ops);
Lines changed: 178 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,178 @@
1+
---
2+
goal: Eventra platformunu auth ürününden full event SaaS platformuna dönüştürmek
3+
version: 1.0
4+
date_created: 2026-03-22
5+
last_updated: 2026-03-22
6+
owner: Eventra Core Team
7+
status: Planned
8+
tags: [feature, architecture, auth, events, ticketing, realtime, security, monetization]
9+
---
10+
11+
# Introduction
12+
13+
![Status: Planned](https://img.shields.io/badge/status-Planned-blue)
14+
15+
Bu plan, mevcut Eventra auth altyapısını koruyarak event management, ticketing, real-time etkileşim, geliştirici API'leri, observability ve monetization katmanlarıyla production-grade bir SaaS platformuna dönüştürür.
16+
17+
## 1. Requirements & Constraints
18+
19+
- REQ-001: OAuth (Google, GitHub) ile sosyal giriş.
20+
- REQ-002: Session/device yönetimi (aktif oturum listeleme, cihazdan çıkış).
21+
- REQ-003: Email verification ve password reset akışları.
22+
- REQ-004: Event CRUD, public/private, kapasite, tag/kategori, search/filter.
23+
- REQ-005: Ticketing (free/paid), QR ticket, check-in, capacity tracking.
24+
- REQ-006: Real-time attendee/check-in/chat/notification.
25+
- REQ-007: Public API + API key + webhook + analytics API.
26+
- REQ-008: Payment (Stripe veya iyzico), komisyon modeli.
27+
- REQ-009: Organization/role/multi-tenant.
28+
- REQ-010: UI dashboard, discover, responsive, dark mode.
29+
- SEC-001: Login brute-force koruması sistem genelinde korunmalı ve genişletilmeli.
30+
- SEC-002: CSRF, XSS, audit log, IP tracking zorunlu.
31+
- SEC-003: Tenant isolation kritik (org_id bazlı erişim kontrolü).
32+
- CON-001: Mevcut Go net/http + PostgreSQL mimarisi korunacak.
33+
- CON-002: Migration-first gelişim; tüm şema değişiklikleri SQL migration ile yapılacak.
34+
- CON-003: İlk versiyonda monolith-modular kalınacak, event-driven bileşenler incrementally eklenecek.
35+
- GUD-001: Özellikler feature flag ile yayınlanmalı.
36+
- GUD-002: Tüm yeni endpointler için integration test zorunlu.
37+
38+
## 2. Implementation Steps
39+
40+
### Implementation Phase 1 - Foundation and Domain Expansion (2-3 hafta)
41+
42+
- GOAL-001: Auth dışına taşan core domain'i kurmak ve event/ticket altyapısını hazırlamak.
43+
44+
| Task | Description | Completed | Date |
45+
|------|-------------|-----------|------|
46+
| TASK-001 | Eventra domain boundaries tanımla: `internal/domain/event`, `internal/domain/ticket`, `internal/domain/organization`, `internal/domain/notification` klasörlerini oluştur | | |
47+
| TASK-002 | Event ve ticket için migration setlerini ekle (`configs/migrations/000004+`) | | |
48+
| TASK-003 | Event repository/usecase/http handler iskeletlerini ekle (`internal/repository/postgres`, `internal/usecase/event`, `internal/delivery/httpserver`) | | |
49+
| TASK-004 | API versioning stratejisi belirle (`/api/v1` korunur, yeni kaynak endpointleri eklenir) | | |
50+
| TASK-005 | Search için PostgreSQL GIN/BTREE indexleri ekle (title/date/location/tags) | | |
51+
52+
### Implementation Phase 2 - Auth System Upgrade (2 hafta)
53+
54+
- GOAL-002: Ürün düzeyi kimlik doğrulama ve hesap güvenliği özelliklerini tamamlamak.
55+
56+
| Task | Description | Completed | Date |
57+
|------|-------------|-----------|------|
58+
| TASK-006 | OAuth provider entegrasyonu (Google, GitHub) + account linking | | |
59+
| TASK-007 | Session/device modeli ekle: `user_sessions` tablosu, cihaz adı/IP/last_seen | | |
60+
| TASK-008 | Email verification token akışı ve endpointleri (`/auth/verify-email`) | | |
61+
| TASK-009 | Password reset request/confirm akışı ve token invalidation | | |
62+
| TASK-010 | Rate limiter'ı IP+email+device fingerprint kombinasyonuna yükselt | | |
63+
64+
### Implementation Phase 3 - Event Management + Ticketing MVP (3-4 hafta)
65+
66+
- GOAL-003: Ürünün ana kullanım değerini veren event ve ticket akışını canlıya almak.
67+
68+
| Task | Description | Completed | Date |
69+
|------|-------------|-----------|------|
70+
| TASK-011 | Event create/update/delete/list/get endpointleri | | |
71+
| TASK-012 | Public/private visibility ve organizer ownership kontrolü | | |
72+
| TASK-013 | Participant limit + waitlist mantığı | | |
73+
| TASK-014 | Tag/category sistemi ve faceted search/filter endpointleri | | |
74+
| TASK-015 | Ticket types (free/paid), order creation, capacity decrement transaction | | |
75+
| TASK-016 | QR ticket üretimi + check-in endpointi + duplicate check-in koruması | | |
76+
77+
### Implementation Phase 4 - Real-time, Notifications, Developer APIs (3 hafta)
78+
79+
- GOAL-004: Modern SaaS deneyimi ve geliştirici ekosistemini açmak.
80+
81+
| Task | Description | Completed | Date |
82+
|------|-------------|-----------|------|
83+
| TASK-017 | WebSocket gateway: live attendee count, live check-in updates, event chat channels | | |
84+
| TASK-018 | Notification orchestration: in-app + email reminder + push (web push) | | |
85+
| TASK-019 | Public API key sistemi (`api_keys` tablosu, hashed key, scope, rotation) | | |
86+
| TASK-020 | Webhook delivery altyapısı (`webhook_endpoints`, `webhook_deliveries`, retry/backoff, signature) | | |
87+
| TASK-021 | Analytics API (event_views, conversion_rate, attendance_rate) | | |
88+
89+
### Implementation Phase 5 - Advanced Backend and Security Hardening (2-3 hafta)
90+
91+
- GOAL-005: Ölçeklenebilirlik, gözlemlenebilirlik ve enterprise güvenlik standardına çıkmak.
92+
93+
| Task | Description | Completed | Date |
94+
|------|-------------|-----------|------|
95+
| TASK-022 | Event-driven omurga: başlangıçta Redis stream/NATS, sonrasında Kafka opsiyonel | | |
96+
| TASK-023 | Async worker katmanı (email, webhook retry, reminder jobs, fraud checks) | | |
97+
| TASK-024 | Structured logging + request correlation id + security audit enrichment | | |
98+
| TASK-025 | Prometheus metrics + OpenTelemetry traces + baseline alerting | | |
99+
| TASK-026 | CSRF/XSS sertleştirme, IP reputation, admin audit log ekranı | | |
100+
101+
### Implementation Phase 6 - Monetization + Multi-tenant + UI Excellence (4 hafta)
102+
103+
- GOAL-006: Ticari ürün kabiliyeti ve farklılaştıran kullanıcı deneyimi.
104+
105+
| Task | Description | Completed | Date |
106+
|------|-------------|-----------|------|
107+
| TASK-027 | Payment integration (Stripe öncelikli, iyzico adaptörü opsiyonel) | | |
108+
| TASK-028 | Commission ve payout hesaplama modeli | | |
109+
| TASK-029 | Organization/team/roles (admin-organizer-member) + tenant enforcement middleware | | |
110+
| TASK-030 | Dashboard (analytics/revenue/user growth) + discover page + önerilen eventler | | |
111+
| TASK-031 | Dark mode, responsive polishing, motion transitions | | |
112+
| TASK-032 | PWA hazırlığı + push permission UX | | |
113+
114+
## 3. Alternatives
115+
116+
- ALT-001: Tüm modülleri tek sprintte geliştirmek. Reddedildi: test ve release riski çok yüksek.
117+
- ALT-002: Tam microservice dönüşümüyle başlamak. Reddedildi: erken karmaşıklık ve operasyon maliyeti.
118+
- ALT-003: Elasticsearch ile erken arama altyapısı kurmak. Reddedildi: önce PostgreSQL full-text + index ile doğrulama daha hızlı.
119+
120+
## 4. Dependencies
121+
122+
- DEP-001: PostgreSQL 14+ (JSONB, indexes, transactional consistency).
123+
- DEP-002: Redis (queue/cache/rate limiting backend).
124+
- DEP-003: OAuth credentials (Google/GitHub).
125+
- DEP-004: SMTP/Email provider (Resend, SES, SendGrid vb.).
126+
- DEP-005: Payment provider hesabı (Stripe veya iyzico).
127+
- DEP-006: Metrics/Tracing stack (Prometheus + Grafana + OTEL collector).
128+
129+
## 5. Files
130+
131+
- FILE-001: `configs/migrations/*.sql` (yeni domain tabloları).
132+
- FILE-002: `internal/domain/**` (event, ticket, organization, notification varlıkları).
133+
- FILE-003: `internal/repository/postgres/**` (event/ticket/session/webhook repository).
134+
- FILE-004: `internal/usecase/**` (event, ticket, payment, notification, analytics usecase).
135+
- FILE-005: `internal/delivery/httpserver/**` (router, handler, middleware, ws handler).
136+
- FILE-006: `internal/config/config.go` (yeni environment değişkenleri).
137+
- FILE-007: `pkg/security/**` (api key hash/signature utilities).
138+
- FILE-008: `frontend/src/**` (dashboard, discover, organizer panel, notification panel).
139+
140+
## 6. Testing
141+
142+
- TEST-001: Auth regression suite (register/login/refresh/logout + oauth + session revocation).
143+
- TEST-002: Event lifecycle integration testleri (create, publish, search, filter).
144+
- TEST-003: Ticketing transaction testleri (capacity race, duplicate check-in, payment states).
145+
- TEST-004: Webhook retry/signature validation testleri.
146+
- TEST-005: API key scope ve rate limit testleri.
147+
- TEST-006: Frontend e2e testleri (critical flows: event create, buy ticket, check-in, dashboard).
148+
149+
## 7. Risks & Assumptions
150+
151+
- RISK-001: Ticket capacity yarış durumları oversell yaratabilir. Mitigasyon: DB transaction + row level lock.
152+
- RISK-002: Real-time chat kötüye kullanım/spam riski taşır. Mitigasyon: moderation + throttling.
153+
- RISK-003: Çok erken çoklu provider (Stripe + iyzico) scope riskini artırır. Mitigasyon: önce tek provider.
154+
- RISK-004: Multi-tenant izolasyon hatası veri sızıntısı riski doğurur. Mitigasyon: zorunlu org_id policy + integration tests.
155+
- ASSUMPTION-001: İlk hedef pazar web; native mobile daha sonra.
156+
- ASSUMPTION-002: İlk sürümde tek bölge deployment kabul edilebilir.
157+
158+
## 8. Related Specifications / Further Reading
159+
160+
- `README.md`
161+
- `api/auth.md`
162+
- `configs/migrations/000003_security_hardening.up.sql`
163+
164+
## 9. Suggested Release Train
165+
166+
- Release A (4-5 hafta): Phase 1 + Phase 2
167+
- Release B (4 hafta): Phase 3
168+
- Release C (3 hafta): Phase 4
169+
- Release D (4-5 hafta): Phase 5 + Phase 6
170+
171+
## 10. First Build Slice (Recommended Immediate Start)
172+
173+
1. Event domain + migrations + CRUD + search/filter (public/private + tags).
174+
2. Ticket free flow + QR + check-in + live attendee count.
175+
3. OAuth + email verification + session management.
176+
4. Dashboard basic analytics (event views + attendance).
177+
178+
Bu dört adım tamamlandığında proje, auth demo seviyesinden gerçek ürün seviyesine geçer.

frontend/src/App.css

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,3 +182,79 @@
182182
border-right-color: var(--border);
183183
}
184184
}
185+
186+
.event-form-grid {
187+
display: grid;
188+
grid-template-columns: repeat(2, minmax(0, 1fr));
189+
gap: 14px;
190+
}
191+
192+
.event-form-grid .wide {
193+
grid-column: 1 / -1;
194+
}
195+
196+
.event-form select,
197+
.event-form textarea {
198+
width: 100%;
199+
border-radius: 12px;
200+
border: 1px solid var(--border);
201+
background: var(--surface-soft);
202+
color: var(--text);
203+
padding: 0.72rem 0.9rem;
204+
font: inherit;
205+
}
206+
207+
.events-list {
208+
margin-top: 1rem;
209+
display: grid;
210+
gap: 12px;
211+
}
212+
213+
.event-item {
214+
border: 1px solid var(--border);
215+
border-radius: 16px;
216+
padding: 14px;
217+
display: flex;
218+
justify-content: space-between;
219+
gap: 16px;
220+
background: var(--surface-soft);
221+
}
222+
223+
.event-item h3 {
224+
margin: 0 0 6px;
225+
}
226+
227+
.event-item p {
228+
margin: 0;
229+
color: var(--text-soft);
230+
}
231+
232+
.event-meta {
233+
margin-top: 6px !important;
234+
font-size: 0.92rem;
235+
}
236+
237+
.event-actions {
238+
display: flex;
239+
gap: 10px;
240+
align-items: center;
241+
}
242+
243+
.empty-state {
244+
color: var(--text-soft);
245+
margin: 0.4rem 0;
246+
}
247+
248+
@media (max-width: 900px) {
249+
.event-form-grid {
250+
grid-template-columns: 1fr;
251+
}
252+
253+
.event-item {
254+
flex-direction: column;
255+
}
256+
257+
.event-actions {
258+
justify-content: flex-start;
259+
}
260+
}

0 commit comments

Comments
 (0)