feat: complete Epic 0 — foundation migration & infrastructure setup
Stories 0.2-0.5: rename folders→declarations (backend+frontend), configure Redis for cache/queue/sessions, add foundation database migrations (permissions, archived_at), replace DeclarationStatus enum with architecture lifecycle values, create DeclarationObserver for status transition validation and auto-archive, fix controller status transitions to respect observer rules. 93 tests pass (240 assertions). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,12 +1,18 @@
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue';
|
||||
import { Head, Link } from '@inertiajs/vue3';
|
||||
import { User, FolderOpen, Building2, Calendar, AlertCircle } from 'lucide-vue-next';
|
||||
import {
|
||||
User,
|
||||
FolderOpen,
|
||||
Building2,
|
||||
Calendar,
|
||||
AlertCircle,
|
||||
} from 'lucide-vue-next';
|
||||
import { computed } from 'vue';
|
||||
import Heading from '@/components/Heading.vue';
|
||||
import AppLayout from '@/layouts/AppLayout.vue';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Badge } from '@/components/ui/badge';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
|
||||
import AppLayout from '@/layouts/AppLayout.vue';
|
||||
|
||||
type WorkspaceUser = {
|
||||
id: number;
|
||||
@@ -24,10 +30,10 @@ type Workspace = {
|
||||
|
||||
type Stats = {
|
||||
clients: number;
|
||||
folders: number;
|
||||
folders_by_status: Record<string, number>;
|
||||
folders_this_month: number;
|
||||
folders_needing_attention: number;
|
||||
declarations: number;
|
||||
declarations_by_status: Record<string, number>;
|
||||
declarations_this_month: number;
|
||||
declarations_needing_attention: number;
|
||||
};
|
||||
|
||||
type Props = {
|
||||
@@ -45,13 +51,14 @@ function roleLabel(role: string): string {
|
||||
|
||||
const inProgressCount = computed(
|
||||
() =>
|
||||
(props.stats.folders_by_status?.processing ?? 0) +
|
||||
(props.stats.folders_by_status?.additional_documents_requested ?? 0) +
|
||||
(props.stats.folders_by_status?.documents_received ?? 0),
|
||||
(props.stats.declarations_by_status?.processing ?? 0) +
|
||||
(props.stats.declarations_by_status?.additional_documents_requested ??
|
||||
0) +
|
||||
(props.stats.declarations_by_status?.documents_received ?? 0),
|
||||
);
|
||||
|
||||
const validatedCount = computed(
|
||||
() => props.stats.folders_by_status?.validated ?? 0,
|
||||
() => props.stats.declarations_by_status?.validated ?? 0,
|
||||
);
|
||||
</script>
|
||||
|
||||
@@ -77,85 +84,111 @@ const validatedCount = computed(
|
||||
|
||||
<div class="grid gap-4 md:grid-cols-2 lg:grid-cols-6">
|
||||
<Card>
|
||||
<CardHeader class="flex flex-row items-center justify-between space-y-0 pb-2">
|
||||
<CardHeader
|
||||
class="flex flex-row items-center justify-between space-y-0 pb-2"
|
||||
>
|
||||
<CardTitle class="text-sm font-medium">
|
||||
Clients
|
||||
</CardTitle>
|
||||
<Building2 class="h-4 w-4 text-muted-foreground" />
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div class="text-2xl font-bold">{{ props.stats.clients }}</div>
|
||||
<div class="text-2xl font-bold">
|
||||
{{ props.stats.clients }}
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
<Card>
|
||||
<CardHeader class="flex flex-row items-center justify-between space-y-0 pb-2">
|
||||
<CardHeader
|
||||
class="flex flex-row items-center justify-between space-y-0 pb-2"
|
||||
>
|
||||
<CardTitle class="text-sm font-medium">
|
||||
Dossiers
|
||||
Déclarations
|
||||
</CardTitle>
|
||||
<FolderOpen class="h-4 w-4 text-muted-foreground" />
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div class="text-2xl font-bold">{{ props.stats.folders }}</div>
|
||||
<div class="text-2xl font-bold">
|
||||
{{ props.stats.declarations }}
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
<Card>
|
||||
<CardHeader class="flex flex-row items-center justify-between space-y-0 pb-2">
|
||||
<CardHeader
|
||||
class="flex flex-row items-center justify-between space-y-0 pb-2"
|
||||
>
|
||||
<CardTitle class="text-sm font-medium">
|
||||
En cours
|
||||
</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div class="text-2xl font-bold">{{ inProgressCount }}</div>
|
||||
<div class="text-2xl font-bold">
|
||||
{{ inProgressCount }}
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
<Card>
|
||||
<CardHeader class="flex flex-row items-center justify-between space-y-0 pb-2">
|
||||
<CardHeader
|
||||
class="flex flex-row items-center justify-between space-y-0 pb-2"
|
||||
>
|
||||
<CardTitle class="text-sm font-medium">
|
||||
Validés
|
||||
</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div class="text-2xl font-bold">{{ validatedCount }}</div>
|
||||
<div class="text-2xl font-bold">
|
||||
{{ validatedCount }}
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
<Card>
|
||||
<CardHeader class="flex flex-row items-center justify-between space-y-0 pb-2">
|
||||
<CardHeader
|
||||
class="flex flex-row items-center justify-between space-y-0 pb-2"
|
||||
>
|
||||
<CardTitle class="text-sm font-medium">
|
||||
Ce mois
|
||||
</CardTitle>
|
||||
<Calendar class="h-4 w-4 text-muted-foreground" />
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div class="text-2xl font-bold">{{ props.stats.folders_this_month }}</div>
|
||||
<div class="text-2xl font-bold">
|
||||
{{ props.stats.declarations_this_month }}
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
<Card>
|
||||
<CardHeader class="flex flex-row items-center justify-between space-y-0 pb-2">
|
||||
<CardHeader
|
||||
class="flex flex-row items-center justify-between space-y-0 pb-2"
|
||||
>
|
||||
<CardTitle class="text-sm font-medium">
|
||||
À traiter
|
||||
</CardTitle>
|
||||
<AlertCircle class="h-4 w-4 text-muted-foreground" />
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div class="text-2xl font-bold">{{ props.stats.folders_needing_attention }}</div>
|
||||
<div class="text-2xl font-bold">
|
||||
{{ props.stats.declarations_needing_attention }}
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="rounded-xl border border-sidebar-border/70 dark:border-sidebar-border overflow-hidden"
|
||||
class="overflow-hidden rounded-xl border border-sidebar-border/70 dark:border-sidebar-border"
|
||||
>
|
||||
<div class="overflow-x-auto">
|
||||
<table class="w-full text-sm">
|
||||
<thead class="border-b border-sidebar-border/70 bg-muted/50">
|
||||
<thead
|
||||
class="border-b border-sidebar-border/70 bg-muted/50"
|
||||
>
|
||||
<tr>
|
||||
<th
|
||||
class="h-10 px-4 text-left font-medium align-middle"
|
||||
class="h-10 px-4 text-left align-middle font-medium"
|
||||
>
|
||||
User
|
||||
</th>
|
||||
<th
|
||||
class="h-10 px-4 text-left font-medium align-middle"
|
||||
class="h-10 px-4 text-left align-middle font-medium"
|
||||
>
|
||||
Role
|
||||
</th>
|
||||
@@ -189,7 +222,9 @@ const validatedCount = computed(
|
||||
colspan="2"
|
||||
class="px-4 py-8 text-center text-muted-foreground"
|
||||
>
|
||||
<div class="flex flex-col items-center gap-2">
|
||||
<div
|
||||
class="flex flex-col items-center gap-2"
|
||||
>
|
||||
<User class="h-10 w-10" />
|
||||
<p>No users in this workspace.</p>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user