refactor: split monolith into 3 microservices (frontend, backend, discord-gateway)

- Extract services into services/{frontend,backend,discord-gateway}
- Create packages/shared/ for shared logger, errors, utils, types
- Setup Modular MVC pattern in backend (controller→service→repository)
- Setup event-driven architecture in discord-gateway with Redis pub/sub
- Move Docker files to infra/docker/ with per-service Dockerfiles
- Update docker-compose.yml to use Traefik-only routing (no port exposes)
- Update GitHub Actions deploy workflow for multi-service matrix build
- Fix all import paths and resolve type errors across all services
- All 3 services pass tsc --noEmit clean

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
MythEclipse
2026-06-01 21:44:29 +07:00
co-authored by Claude Opus 4.8
parent bda8304bb9
commit c48a0c5e3b
193 changed files with 16879 additions and 1158 deletions
@@ -0,0 +1,60 @@
import type { ActiveSpeaker } from "../../../shared/api/client";
import { Skeleton } from "../../../shared/ui";
interface ActiveSpeakersProps {
speakers: ActiveSpeaker[];
}
export function ActiveSpeakers({ speakers }: ActiveSpeakersProps) {
if (speakers.length === 0) {
return (
<div className="rounded-xl border border-dashed border-border p-6 text-center text-sm text-muted-foreground">
No active speakers.
</div>
);
}
return (
<div className="space-y-2">
{speakers.map((s) => {
// BUG 4 FIX: stable key — no index fallback
const key = s.userId ?? s.id ?? `speaker-${s.username}`;
return (
<div
key={key}
className="flex items-center gap-3 rounded-xl border border-border bg-background/60 p-3"
>
<img
src={s.avatar}
alt=""
className="h-8 w-8 rounded-full object-cover"
/>
<div className="min-w-0">
<div className="truncate text-sm font-medium">{s.username}</div>
<div className="text-xs text-emerald-300">Speaking</div>
</div>
</div>
);
})}
</div>
);
}
export function ActiveSpeakersSkeleton() {
return (
<div className="space-y-2">
{[1, 2, 3].map((i) => (
<div
key={i}
className="flex items-center gap-3 rounded-xl border border-border bg-background/60 p-3"
>
<Skeleton className="h-8 w-8 rounded-full" />
<div className="flex-1 space-y-1">
<Skeleton className="h-4 w-24" />
<Skeleton className="h-3 w-16" />
</div>
</div>
))}
</div>
);
}