feat: enhance audit logging, add MCP settings, and production docker setup
continuous-integration/drone/push Build is passing

- Implemented comprehensive audit logging for Tasks, Users, Settings, Goals, Labels, AI Chat, and Rewards.
- Added Admin UI for MCP Server settings and Audit Logs.
- Created docker-compose-production.yml with Traefik configuration.
- Fixed backend bugs (missing storage methods, route closure).
- Added Audit Logging Guidelines.
This commit is contained in:
2025-12-15 15:53:31 +01:00
parent fdf321cde9
commit d1736c5991
35 changed files with 5165 additions and 499 deletions
@@ -0,0 +1,94 @@
import { useQuery } from "@tanstack/react-query";
import { format } from "date-fns";
import {
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow,
} from "@/components/ui/table";
import { Card, CardContent, CardHeader, CardTitle, CardDescription } from "@/components/ui/card";
import { Badge } from "@/components/ui/badge";
import { useTranslation } from "react-i18next";
import { Loader2 } from "lucide-react";
interface AuditLog {
id: string;
userId: string | null;
action: string;
entityType: string;
entityId: string | null;
source: string;
details: any;
createdAt: string;
}
export function AuditLogsTable() {
const { t } = useTranslation();
const { data: logs, isLoading, error } = useQuery<AuditLog[]>({
queryKey: ['/api/admin/audit-logs'],
});
if (isLoading) {
return <div className="flex justify-center p-8"><Loader2 className="h-8 w-8 animate-spin" /></div>;
}
if (error) {
return <div className="p-8 text-center text-red-500">Failed to load audit logs. Please check server logs.</div>;
}
return (
<Card>
<CardHeader>
<CardTitle>Audit Logs</CardTitle>
<CardDescription>Track all system changes and AI actions.</CardDescription>
</CardHeader>
<CardContent>
<Table>
<TableHeader>
<TableRow>
<TableHead>Time</TableHead>
<TableHead>Source</TableHead>
<TableHead>Action</TableHead>
<TableHead>Entity</TableHead>
<TableHead>Details</TableHead>
</TableRow>
</TableHeader>
<TableBody>
{logs?.map((log) => (
<TableRow key={log.id}>
<TableCell className="whitespace-nowrap">
{format(new Date(log.createdAt), "MMM d, HH:mm:ss")}
</TableCell>
<TableCell>
<Badge variant={log.source === 'AI' ? 'secondary' : 'outline'}>
{log.source}
</Badge>
</TableCell>
<TableCell className="font-medium">{log.action}</TableCell>
<TableCell>
{log.entityType}
{log.entityId && <span className="text-xs text-muted-foreground block truncate max-w-[100px]">{log.entityId}</span>}
</TableCell>
<TableCell className="text-sm text-muted-foreground w-1/3">
<pre className="whitespace-pre-wrap font-mono text-xs">
{JSON.stringify(log.details, null, 2)}
</pre>
</TableCell>
</TableRow>
))}
{(!logs || logs.length === 0) && (
<TableRow>
<TableCell colSpan={5} className="text-center py-8 text-muted-foreground">
No logs found.
</TableCell>
</TableRow>
)}
</TableBody>
</Table>
</CardContent>
</Card>
);
}