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:
2026-03-12 18:25:32 +00:00
parent d380df4074
commit fd43a6f429
105 changed files with 3899 additions and 1558 deletions

View File

@@ -0,0 +1,91 @@
<script setup lang="ts">
import { Head, Link, useForm } from '@inertiajs/vue3';
import DeclarationForm from '@/components/DeclarationForm.vue';
import type { DeclarationFormData } from '@/components/DeclarationForm.vue';
import Heading from '@/components/Heading.vue';
import AppLayout from '@/layouts/AppLayout.vue';
type Client = {
id: number;
company_name: string;
};
type WorkspaceUser = {
id: number;
name: string;
email: string;
};
type Props = {
indexUrl: string;
storeUrl: string;
initialClientId?: number | null;
declarationTypeLabels: Record<string, string>;
declarationStatusLabels: Record<string, string>;
declarationPriorityLabels: Record<string, string>;
clients: Client[];
workspaceUsers: WorkspaceUser[];
};
const props = defineProps<Props>();
const currentYear = new Date().getFullYear();
const form = useForm<DeclarationFormData>({
client_id: props.initialClientId ? String(props.initialClientId) : '',
title: '',
type: 'vat_monthly',
period_year: currentYear,
period_month: '',
period_quarter: '',
due_date: '',
status: 'draft',
priority: 'medium',
assigned_to: '',
notes_internal: '',
notes_client: '',
});
function submit() {
form.post(props.storeUrl);
}
</script>
<template>
<AppLayout
:breadcrumbs="[
{ title: 'Déclarations', href: props.indexUrl },
{ title: 'Nouvelle déclaration' },
]"
>
<Head title="Nouvelle déclaration" />
<div class="flex flex-col space-y-6 p-4">
<Heading
title="Nouvelle déclaration"
description="Créer une nouvelle déclaration fiscale"
/>
<div
v-if="!props.clients.length"
class="rounded-lg border border-amber-200 bg-amber-50 px-4 py-3 text-sm text-amber-800 dark:border-amber-800 dark:bg-amber-950/30 dark:text-amber-200"
>
Aucun client dans ce workspace. Créez d'abord un
<Link href="/clients" class="font-medium underline">
client
</Link>
pour pouvoir créer une déclaration.
</div>
<DeclarationForm
v-else
:form="form"
:declaration-type-labels="props.declarationTypeLabels"
:declaration-status-labels="props.declarationStatusLabels"
:declaration-priority-labels="props.declarationPriorityLabels"
:clients="props.clients"
:workspace-users="props.workspaceUsers"
submit-label="Créer la déclaration"
@submit="submit"
/>
</div>
</AppLayout>
</template>