feat(registratura): atomic numbering, reserved slots, audit trail, API endpoints + theme toggle animation

Registratura module:
- Atomic sequence numbering (BTG-2026-IN-00125 format) via PostgreSQL upsert
- Reserved monthly slots (2/company/month) for late registrations
- Append-only audit trail with diff tracking
- REST API: /api/registratura (CRUD), /api/registratura/reserved, /api/registratura/audit
- Auth: NextAuth session + Bearer API key support
- New "intern" direction type with UI support (form, filters, table, detail panel)
- Prisma models: RegistrySequence, RegistryAudit

Theme toggle:
- SVG mask-based sun/moon morph with 360° spin animation
- Inverted logic (sun in dark mode, moon in light mode)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
AI Assistant
2026-03-10 07:54:32 +02:00
parent f94529c380
commit a0dd35a066
15 changed files with 1354 additions and 124 deletions
@@ -82,7 +82,7 @@ const COLUMNS: ColumnDef[] = [
id: "direction",
label: "Dir.",
tooltip:
"Direcție: Intrat = primit de la terți, Ieșit = trimis către terți",
"Direcție: Intrat = primit, Ieșit = trimis, Intern = intern",
defaultVisible: true,
},
{
@@ -141,6 +141,7 @@ const STORAGE_KEY = "registratura:visible-columns";
const DIRECTION_LABELS: Record<string, string> = {
intrat: "Intrat",
iesit: "Ieșit",
intern: "Intern",
};
function getDocTypeLabel(type: string): string {
@@ -152,6 +153,7 @@ function getDocTypeLabel(type: string): string {
const STATUS_LABELS: Record<string, string> = {
deschis: "Deschis",
inchis: "Închis",
reserved: "Rezervat",
};
function loadVisibleColumns(): Set<ColumnId> {
@@ -327,7 +329,11 @@ export function RegistryTable({
<td className="px-3 py-2">
<Badge
variant={
entry.direction === "intrat" ? "default" : "secondary"
entry.direction === "intrat"
? "default"
: entry.direction === "intern"
? "outline"
: "secondary"
}
className="text-xs"
>
@@ -424,9 +430,16 @@ export function RegistryTable({
<td className="px-3 py-2">
<Badge
variant={
entry.status === "deschis" ? "default" : "outline"
entry.status === "deschis"
? "default"
: entry.status === "reserved"
? "secondary"
: "outline"
}
className="text-xs"
className={cn(
"text-xs",
entry.status === "reserved" && "border-dashed",
)}
>
{STATUS_LABELS[entry.status]}
</Badge>