Initial commit
Some checks failed
CI/CD Pipeline / Code Quality & Linting (push) Has been cancelled
CI/CD Pipeline / Policy Validation (push) Has been cancelled
CI/CD Pipeline / Test Suite (push) Has been cancelled
CI/CD Pipeline / Build Docker Images (svc-coverage) (push) Has been cancelled
CI/CD Pipeline / Build Docker Images (svc-extract) (push) Has been cancelled
CI/CD Pipeline / Build Docker Images (svc-firm-connectors) (push) Has been cancelled
CI/CD Pipeline / Build Docker Images (svc-forms) (push) Has been cancelled
CI/CD Pipeline / Build Docker Images (svc-hmrc) (push) Has been cancelled
CI/CD Pipeline / Build Docker Images (svc-ingestion) (push) Has been cancelled
CI/CD Pipeline / Build Docker Images (svc-kg) (push) Has been cancelled
CI/CD Pipeline / Build Docker Images (svc-normalize-map) (push) Has been cancelled
CI/CD Pipeline / Build Docker Images (svc-ocr) (push) Has been cancelled
CI/CD Pipeline / Build Docker Images (svc-rag-indexer) (push) Has been cancelled
CI/CD Pipeline / Build Docker Images (svc-rag-retriever) (push) Has been cancelled
CI/CD Pipeline / Build Docker Images (svc-reason) (push) Has been cancelled
CI/CD Pipeline / Build Docker Images (svc-rpa) (push) Has been cancelled
CI/CD Pipeline / Build Docker Images (ui-review) (push) Has been cancelled
CI/CD Pipeline / Security Scanning (svc-coverage) (push) Has been cancelled
CI/CD Pipeline / Security Scanning (svc-extract) (push) Has been cancelled
CI/CD Pipeline / Security Scanning (svc-kg) (push) Has been cancelled
CI/CD Pipeline / Security Scanning (svc-rag-retriever) (push) Has been cancelled
CI/CD Pipeline / Security Scanning (ui-review) (push) Has been cancelled
CI/CD Pipeline / Generate SBOM (push) Has been cancelled
CI/CD Pipeline / Deploy to Staging (push) Has been cancelled
CI/CD Pipeline / Deploy to Production (push) Has been cancelled
CI/CD Pipeline / Notifications (push) Has been cancelled

This commit is contained in:
harkon
2025-10-11 08:41:36 +01:00
commit b324ff09ef
276 changed files with 55220 additions and 0 deletions

200
mocks/actvity.ts Normal file
View File

@@ -0,0 +1,200 @@
"use client";
import Link from "next/link";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import { Badge } from "@/components/ui/badge";
import { Avatar, AvatarFallback } from "@/components/ui/avatar";
import {
FileText,
Upload,
Calculator,
CheckCircle,
Send,
Clock,
} from "lucide-react";
import { formatDate } from "@/lib/formatting";
// Mock data - in real app this would come from API
const mockActivity = [
{
id: "1",
type: "document_uploaded",
title: "P60 uploaded for John Smith",
description: "Employment certificate for 2023-24",
clientId: "client-1",
clientName: "John Smith",
userId: "user-1",
userName: "Sarah Wilson",
timestamp: "2024-01-10T14:30:00Z",
status: "completed",
},
{
id: "2",
type: "schedule_computed",
title: "SA103 calculated for Sarah Johnson",
description: "Self-employment schedule completed",
clientId: "client-2",
clientName: "Sarah Johnson",
userId: "user-2",
userName: "Mike Davis",
timestamp: "2024-01-10T13:15:00Z",
status: "completed",
},
{
id: "3",
type: "coverage_checked",
title: "Coverage check completed",
description: "2 missing items identified for Michael Brown",
clientId: "client-3",
clientName: "Michael Brown",
userId: "user-1",
userName: "Sarah Wilson",
timestamp: "2024-01-10T11:45:00Z",
status: "attention_required",
},
{
id: "4",
type: "form_generated",
title: "SA100 form generated",
description: "Main return PDF created for Emma Davis",
clientId: "client-4",
clientName: "Emma Davis",
userId: "user-3",
userName: "Alex Thompson",
timestamp: "2024-01-10T10:20:00Z",
status: "completed",
},
{
id: "5",
type: "submission_prepared",
title: "HMRC submission ready",
description: "Return prepared for David Wilson",
clientId: "client-5",
clientName: "David Wilson",
userId: "user-2",
userName: "Mike Davis",
timestamp: "2024-01-10T09:30:00Z",
status: "pending_review",
},
];
const activityIcons = {
document_uploaded: Upload,
schedule_computed: Calculator,
coverage_checked: CheckCircle,
form_generated: FileText,
submission_prepared: Send,
default: Clock,
};
const statusColors = {
completed: "bg-green-100 text-green-800",
attention_required: "bg-yellow-100 text-yellow-800",
pending_review: "bg-blue-100 text-blue-800",
failed: "bg-red-100 text-red-800",
};
export function RecentActivity(): JSX.Element {
return (
<Card>
<CardHeader className="flex flex-row items-center justify-between">
<CardTitle>Recent Activity</CardTitle>
<Badge variant="outline">Last 24 hours</Badge>
</CardHeader>
<CardContent>
<div className="space-y-4">
{mockActivity.map((activity) => {
const Icon =
activityIcons[activity.type as keyof typeof activityIcons] ||
activityIcons.default;
return (
<div
key={activity.id}
className="flex items-start space-x-4 p-3 border rounded-lg hover:bg-muted/50 transition-colors"
>
<div className="flex-shrink-0">
<div className="h-8 w-8 rounded-full bg-primary/10 flex items-center justify-center">
<Icon className="h-4 w-4 text-primary" />
</div>
</div>
<div className="flex-1 min-w-0">
<div className="flex items-center justify-between mb-1">
<h4 className="text-sm font-medium truncate">
{activity.title}
</h4>
<Badge
variant="outline"
className={
statusColors[
activity.status as keyof typeof statusColors
]
}
>
{activity.status.replace("_", " ")}
</Badge>
</div>
<p className="text-sm text-muted-foreground mb-2">
{activity.description}
</p>
<div className="flex items-center justify-between">
<div className="flex items-center space-x-2">
<Avatar className="h-5 w-5">
<AvatarFallback className="text-xs">
{activity.userName
.split(" ")
.map((n) => n[0])
.join("")}
</AvatarFallback>
</Avatar>
<span className="text-xs text-muted-foreground">
{activity.userName}
</span>
</div>
<span className="text-xs text-muted-foreground">
{formatDate(activity.timestamp, { relative: true })}
</span>
</div>
</div>
<div className="flex-shrink-0">
<Link
href={`/clients/${activity.clientId}`}
className="text-xs text-primary hover:underline"
>
View Client
</Link>
</div>
</div>
);
})}
{mockActivity.length === 0 && (
<div className="text-center py-8 text-muted-foreground">
<Clock className="h-8 w-8 mx-auto mb-2 opacity-50" />
<p>No recent activity</p>
<p className="text-sm">
Activity will appear here as work is completed
</p>
</div>
)}
</div>
{mockActivity.length > 0 && (
<div className="mt-4 pt-4 border-t">
<Link
href="/audit"
className="text-sm text-primary hover:underline"
>
View full audit trail
</Link>
</div>
)}
</CardContent>
</Card>
);
}

324
mocks/audit.ts Normal file
View File

@@ -0,0 +1,324 @@
"use client";
import Link from "next/link";
import { Card, CardContent } from "@/components/ui/card";
import { Badge } from "@/components/ui/badge";
import { Avatar, AvatarFallback } from "@/components/ui/avatar";
import {
FileText,
Upload,
Calculator,
CheckCircle,
Send,
Clock,
User,
AlertTriangle,
Settings,
Shield,
} from "lucide-react";
import { formatDate } from "@/lib/formatting";
// Mock audit data - in real app this would come from API
const mockAuditEvents = [
{
id: "audit-1",
type: "document_uploaded",
title: "Document uploaded",
description: "P60 Employment Certificate uploaded for John Smith",
clientId: "client-1",
clientName: "John Smith",
userId: "user-1",
userName: "Sarah Wilson",
userRole: "preparer",
timestamp: "2024-01-10T14:30:00Z",
metadata: {
fileName: "P60_2023-24.pdf",
fileSize: "245KB",
documentType: "P60",
},
severity: "info",
},
{
id: "audit-2",
type: "schedule_computed",
title: "Schedule computed",
description: "SA103 Self Employment schedule calculated for Sarah Johnson",
clientId: "client-2",
clientName: "Sarah Johnson",
userId: "user-2",
userName: "Mike Davis",
userRole: "reviewer",
timestamp: "2024-01-10T13:15:00Z",
metadata: {
scheduleType: "SA103",
profit: "£45,000",
taxLiability: "£8,500",
},
severity: "info",
},
{
id: "audit-3",
type: "coverage_check_failed",
title: "Coverage check failed",
description:
"Missing evidence identified for Michael Brown - 2 critical items required",
clientId: "client-3",
clientName: "Michael Brown",
userId: "system",
userName: "System",
userRole: "system",
timestamp: "2024-01-10T11:45:00Z",
metadata: {
missingItems: ["Bank statements", "Property rental agreement"],
coverageScore: "65%",
},
severity: "warning",
},
{
id: "audit-4",
type: "form_generated",
title: "Form generated",
description: "SA100 Main Return PDF created for Emma Davis",
clientId: "client-4",
clientName: "Emma Davis",
userId: "user-3",
userName: "Alex Thompson",
userRole: "preparer",
timestamp: "2024-01-10T10:20:00Z",
metadata: {
formType: "SA100",
pages: 8,
taxLiability: "£12,450",
},
severity: "info",
},
{
id: "audit-5",
type: "hmrc_submission",
title: "HMRC submission prepared",
description: "Tax return submitted to HMRC for David Wilson",
clientId: "client-5",
clientName: "David Wilson",
userId: "user-2",
userName: "Mike Davis",
userRole: "reviewer",
timestamp: "2024-01-10T09:30:00Z",
metadata: {
submissionId: "HMRC-2024-001234",
taxYear: "2023-24",
status: "submitted",
},
severity: "success",
},
{
id: "audit-6",
type: "user_login",
title: "User login",
description: "Sarah Wilson logged into the platform",
clientId: null,
clientName: null,
userId: "user-1",
userName: "Sarah Wilson",
userRole: "preparer",
timestamp: "2024-01-10T08:00:00Z",
metadata: {
ipAddress: "192.168.1.100",
userAgent: "Chrome 120.0.0.0",
location: "London, UK",
},
severity: "info",
},
{
id: "audit-7",
type: "policy_updated",
title: "Coverage policy updated",
description:
"Self employment evidence requirements updated by administrator",
clientId: null,
clientName: null,
userId: "admin-1",
userName: "Admin User",
userRole: "admin",
timestamp: "2024-01-09T16:45:00Z",
metadata: {
policyType: "self_employment",
changes: ["Added requirement for business bank statements"],
},
severity: "warning",
},
];
const eventIcons = {
document_uploaded: Upload,
schedule_computed: Calculator,
coverage_check_failed: AlertTriangle,
form_generated: FileText,
hmrc_submission: Send,
user_login: User,
policy_updated: Settings,
system_error: AlertTriangle,
default: Clock,
};
const severityColors = {
info: "bg-blue-100 text-blue-800 border-blue-200",
success: "bg-green-100 text-green-800 border-green-200",
warning: "bg-yellow-100 text-yellow-800 border-yellow-200",
error: "bg-red-100 text-red-800 border-red-200",
};
const roleColors = {
admin: "bg-red-100 text-red-800",
reviewer: "bg-blue-100 text-blue-800",
preparer: "bg-green-100 text-green-800",
system: "bg-gray-100 text-gray-800",
};
export function AuditTimeline(): JSX.Element {
return (
<div className="space-y-4">
{mockAuditEvents.map((event, index) => {
const Icon =
eventIcons[event.type as keyof typeof eventIcons] ||
eventIcons.default;
const isLast = index === mockAuditEvents.length - 1;
return (
<div key={event.id} className="relative">
{/* Timeline line */}
{!isLast && (
<div className="absolute left-6 top-12 w-0.5 h-full bg-border" />
)}
<Card className="ml-0">
<CardContent className="p-6">
<div className="flex items-start space-x-4">
{/* Icon */}
<div className="flex-shrink-0">
<div className="h-12 w-12 rounded-full bg-background border-2 border-border flex items-center justify-center">
<Icon className="h-5 w-5 text-muted-foreground" />
</div>
</div>
{/* Content */}
<div className="flex-1 min-w-0">
<div className="flex items-start justify-between mb-2">
<div className="space-y-1">
<h3 className="text-lg font-semibold">{event.title}</h3>
<p className="text-muted-foreground">
{event.description}
</p>
</div>
<div className="flex items-center space-x-2">
<Badge
variant="outline"
className={
severityColors[
event.severity as keyof typeof severityColors
]
}
>
{event.severity}
</Badge>
<span className="text-sm text-muted-foreground">
{formatDate(event.timestamp, { relative: true })}
</span>
</div>
</div>
{/* User and client info */}
<div className="flex items-center space-x-4 mb-3">
<div className="flex items-center space-x-2">
<Avatar className="h-6 w-6">
<AvatarFallback className="text-xs">
{event.userName === "System" ? (
<Shield className="h-3 w-3" />
) : (
event.userName
.split(" ")
.map((n) => n[0])
.join("")
)}
</AvatarFallback>
</Avatar>
<span className="text-sm font-medium">
{event.userName}
</span>
<Badge
variant="outline"
className={`text-xs ${
roleColors[
event.userRole as keyof typeof roleColors
]
}`}
>
{event.userRole}
</Badge>
</div>
{event.clientName && (
<>
<span className="text-muted-foreground"></span>
<Link
href={`/clients/${event.clientId}`}
className="text-sm text-primary hover:underline"
>
{event.clientName}
</Link>
</>
)}
</div>
{/* Metadata */}
{event.metadata &&
Object.keys(event.metadata).length > 0 && (
<div className="bg-muted/50 rounded-lg p-3">
<h4 className="text-sm font-medium mb-2">Details</h4>
<div className="grid grid-cols-1 md:grid-cols-2 gap-2 text-sm">
{Object.entries(event.metadata).map(
([key, value]) => (
<div key={key} className="flex justify-between">
<span className="text-muted-foreground capitalize">
{key
.replace(/([A-Z])/g, " $1")
.toLowerCase()}
:
</span>
<span className="font-medium">
{Array.isArray(value)
? value.join(", ")
: String(value)}
</span>
</div>
)
)}
</div>
</div>
)}
</div>
</div>
</CardContent>
</Card>
</div>
);
})}
{mockAuditEvents.length === 0 && (
<Card>
<CardContent className="p-12 text-center">
<Clock className="h-12 w-12 mx-auto mb-4 text-muted-foreground opacity-50" />
<div className="text-muted-foreground">
<div className="text-lg font-medium mb-2">
No audit events found
</div>
<p className="text-sm">
Activity will appear here as work is completed
</p>
</div>
</CardContent>
</Card>
)}
</div>
);
}

136
mocks/tasks.ts Normal file
View File

@@ -0,0 +1,136 @@
"use client";
import Link from "next/link";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import { AlertCircle, Clock, FileText, MessageSquare } from "lucide-react";
import { formatDate } from "@/lib/formatting";
// Mock data - in real app this would come from API
const mockTasks = [
{
id: "1",
type: "clarification" as const,
title: "Missing P60 for John Smith",
description: "Employment income evidence required for SA102",
clientId: "client-1",
clientName: "John Smith",
taxYear: "2023-24",
priority: "high" as const,
dueDate: "2024-01-15",
},
{
id: "2",
type: "review_request" as const,
title: "Review SA103 calculations",
description: "Self-employment profit calculation needs approval",
clientId: "client-2",
clientName: "Sarah Johnson",
taxYear: "2023-24",
priority: "medium" as const,
dueDate: "2024-01-20",
},
{
id: "3",
type: "missing_evidence" as const,
title: "Bank statements required",
description: "Property income verification needed",
clientId: "client-3",
clientName: "Michael Brown",
taxYear: "2023-24",
priority: "urgent" as const,
dueDate: "2024-01-12",
},
];
const taskIcons = {
clarification: MessageSquare,
missing_evidence: FileText,
review_request: Clock,
calculation_error: AlertCircle,
};
const priorityColors = {
low: "bg-gray-100 text-gray-800",
medium: "bg-blue-100 text-blue-800",
high: "bg-orange-100 text-orange-800",
urgent: "bg-red-100 text-red-800",
};
export function TasksList(): JSX.Element {
return (
<Card>
<CardHeader className="flex flex-row items-center justify-between">
<CardTitle>Pending Tasks</CardTitle>
<Badge variant="secondary">{mockTasks.length}</Badge>
</CardHeader>
<CardContent>
<div className="space-y-4">
{mockTasks.map((task) => {
const Icon = taskIcons[task.type];
return (
<div
key={task.id}
className="flex items-start space-x-4 p-4 border rounded-lg hover:bg-muted/50 transition-colors"
>
<div className="flex-shrink-0">
<Icon className="h-5 w-5 text-muted-foreground mt-0.5" />
</div>
<div className="flex-1 min-w-0">
<div className="flex items-center justify-between mb-1">
<h4 className="text-sm font-medium truncate">
{task.title}
</h4>
<Badge
variant="outline"
className={priorityColors[task.priority]}
>
{task.priority}
</Badge>
</div>
<p className="text-sm text-muted-foreground mb-2">
{task.description}
</p>
<div className="flex items-center justify-between text-xs text-muted-foreground">
<span>
{task.clientName} {task.taxYear}
</span>
<span>
Due {formatDate(task.dueDate, { format: "short" })}
</span>
</div>
</div>
<div className="flex-shrink-0">
<Button variant="ghost" size="sm" asChild>
<Link href={`/clients/${task.clientId}`}>View</Link>
</Button>
</div>
</div>
);
})}
{mockTasks.length === 0 && (
<div className="text-center py-8 text-muted-foreground">
<Clock className="h-8 w-8 mx-auto mb-2 opacity-50" />
<p>No pending tasks</p>
<p className="text-sm">All caught up!</p>
</div>
)}
</div>
{mockTasks.length > 0 && (
<div className="mt-4 pt-4 border-t">
<Button variant="outline" className="w-full" asChild>
<Link href="/tasks">View All Tasks</Link>
</Button>
</div>
)}
</CardContent>
</Card>
);
}