v1.6.5: fix attendance unique constraint, schema sync, seed script

- Change attendance idx_attendance_user_date from unique to index (allow multiple shifts per day)
- Reset migrations to single baseline init migration
- Add seed script with admin user (admin/admin)
- Update CLAUDE.md with migration workflow documentation
- Various frontend fixes (queries, pages, hooks)

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
BOHA
2026-05-17 16:21:34 +02:00
parent 1db5060c42
commit cd6d3daf43
75 changed files with 1748 additions and 1169 deletions

View File

@@ -11,6 +11,13 @@ import {
attendanceBalancesOptions,
attendanceWorkFundOptions,
attendanceProjectReportOptions,
type BalanceEntry,
type BalancesData,
type FundData,
type FundUserData,
type MonthFundData,
type ProjectData,
type UserShort,
} from "../lib/queries/attendance";
import apiFetch from "../utils/api";
@@ -18,70 +25,6 @@ import { Skeleton } from "boneyard-js/react";
import AttendanceBalancesFixture from "../fixtures/AttendanceBalancesFixture";
const API_BASE = "/api/admin";
interface BalanceEntry {
name: string;
vacation_total: number;
vacation_used: number;
vacation_remaining: number;
sick_used: number;
}
interface UserShort {
id: number | string;
name: string;
}
interface FundUserData {
name: string;
worked: number;
covered: number;
overtime: number;
missing: number;
}
interface MonthFundData {
month_name: string;
fund: number;
fund_to_date: number;
business_days: number;
users?: Record<string, FundUserData>;
}
interface ProjectUser {
user_id: number;
user_name: string;
hours: number;
}
interface ProjectEntry {
project_id: number | null;
project_number?: string;
project_name?: string;
hours: number;
users: ProjectUser[];
}
interface MonthProjectData {
month_name: string;
projects: ProjectEntry[];
}
interface BalancesData {
users: UserShort[];
balances: Record<string, BalanceEntry>;
}
interface FundData {
months: Record<string, MonthFundData>;
holidays: unknown[];
users: UserShort[];
balances: Record<string, unknown>;
}
interface ProjectData {
months: Record<string, MonthProjectData>;
}
const getVacationClass = (remaining: number): string => {
if (remaining <= 0) return "text-danger";
if (remaining < 20) return "text-warning";
@@ -144,18 +87,15 @@ export default function AttendanceBalances() {
const { hasPermission } = useAuth();
const queryClient = useQueryClient();
const [year, setYear] = useState(new Date().getFullYear());
const { data: balancesRaw, isPending: balancesPending } = useQuery(
const { data: balancesData, isPending: balancesPending } = useQuery(
attendanceBalancesOptions(year),
);
const { data: fundRaw, isPending: fundPending } = useQuery(
const { data: fundData, isPending: fundPending } = useQuery(
attendanceWorkFundOptions(year),
);
const { data: projectRaw, isPending: projectPending } = useQuery(
const { data: projectData, isPending: projectPending } = useQuery(
attendanceProjectReportOptions(year),
);
const balancesData = balancesRaw as BalancesData | undefined;
const fundData = fundRaw as FundData | undefined;
const projectData = projectRaw as ProjectData | undefined;
const [showEditModal, setShowEditModal] = useState(false);
const [editingUser, setEditingUser] = useState<{