export type WorkType = "support" | "consulting"; export type BillingStatus = "billable" | "billed" | "non_billable" | null; export type PeriodType = "month" | "day"; export type TicketDetailPeriodType = PeriodType | "all"; export type UserRole = "admin" | "user"; export type AuthUser = { id: string; username: string; display_name: string; role: UserRole; active: boolean; zammad_user_id: string | null; has_zammad_api_token: boolean; teamspace_user_id: string | null; has_teamspace_credentials: boolean; zammad_email_session_webhook_enabled: boolean; session_billing_prompt_enabled: boolean; teamspace_time_tracking_enabled: boolean; zammad_session_note_default_enabled: boolean; zammad_time_unit_rounding_enabled: boolean; zammad_time_unit_rounding_minutes: number; zammad_atoss_email_sync_enabled: boolean; zammad_article_type_id: number; project_followup_enabled: boolean; project_followup_weeks: number; project_followup_second_enabled: boolean; project_followup_second_weeks: number; project_followup_complete_on_session: boolean; }; export type DashboardWidgetType = "dayControl" | "today" | "month" | "openRatings" | "projectBudgets" | "todos" | "teamspace" | "favorites" | "divider" | "statistic" | "notes"; export type DashboardSortDirection = "asc" | "desc"; export type DashboardFavorite = { ticketNumber: string; addedAt: string; sortOrder: number; }; export type DashboardWidget = { id: string; type: DashboardWidgetType; title?: string; x: number; y: number; w: number; h: number; config?: Record; }; export type DashboardPreference = { version: number; widgets: DashboardWidget[]; favorites: DashboardFavorite[]; }; export type DashboardDayTicket = { ticket_id: string; ticket_number: string; title: string | null; organization_name: string | null; work_type: WorkType | null; zammad_priority_id: string | null; zammad_state_id: string | null; zammad_pending_time: string | null; latest_started_at: string | null; has_project: boolean; own_session_count: number; open_session_count: number; open_todo_count: number; due_todo_count: number; }; export type AdminUser = AuthUser & { created_at: string; updated_at: string; }; export type ZammadSessionArticleQueueItem = { id: string; session_id: string; ticket_id: string; ticket_number: string; zammad_ticket_id: string | null; activity: string; time_unit: number; zammad_article_type_id: number; attempt_count: number; last_error: string | null; last_attempt_at: string | null; created_at: string; started_at: string; rounded_minutes: number; }; export type Organization = { id: string; zammad_id: string; name: string; synced_at: string; }; export type RecurringBillingSlot = { id?: string; weekday: number | null; start_time: string | null; duration_minutes: number; }; export type RecurringBilling = { id: string; user_id: string; owner_username: string; owner_display_name: string; ticket_number: string; configured_ticket_number: string | null; organization_id: string; organization_name: string; activity: string; work_type: WorkType; recurrence_type: "weekly" | "every_n_weeks"; interval_value: number; valid_from: string; valid_until: string | null; start_time: string; active: boolean; created_at: string; updated_at: string; slots: RecurringBillingSlot[]; }; export type TicketMeta = { id: string; ticket_number: string; title: string | null; organization_id: string | null; organization_name: string | null; customer_name: string | null; work_type: WorkType | null; zammad_ticket_id?: string | null; zammad_group_id?: string | null; zammad_priority_id?: string | null; zammad_state_id?: string | null; zammad_owner_id?: string | null; zammad_owner_user_id?: string | null; zammad_owner_display_name?: string | null; zammad_owner_username?: string | null; is_foreign_zammad_owner?: boolean; can_edit_ticket_data?: boolean; project_id?: string | null; is_project?: boolean; project_name?: string | null; project_hour_budget_minutes?: number | null; project_teamspace_entry_count?: number; project_teamspace_entries?: ProjectTeamspaceEntry[]; project_owner_user_id?: string | null; project_owner_display_name?: string | null; can_edit_project?: boolean; has_recurring_billing?: boolean; }; export type TicketSearchResult = { ticket_id: string; ticket_number: string; title: string | null; organization_id: string | null; organization_name: string | null; customer_name: string | null; work_type: WorkType | null; project_id: string | null; is_project: boolean; project_name: string | null; latest_started_at: string | null; latest_period: string; session_count: number; total_minutes: number; }; export type ProjectSummary = { id: string; user_id?: string; owner_username?: string | null; owner_display_name?: string | null; can_edit?: boolean; ticket_id: string; ticket_number: string; title: string | null; organization_id: string | null; organization_name: string | null; customer_name: string | null; work_type: WorkType | null; zammad_priority_id?: string | null; zammad_state_id?: string | null; zammad_ticket_id?: string | null; zammad_owner_id?: string | null; ticket_zammad_owner_id?: string | null; zammad_pending_time?: string | null; zammad_merged_from_ticket_id?: string | null; zammad_merged_from_ticket_number?: string | null; teamspace_project: string | null; description: string; goals: string; starts_on: string | null; ends_on: string | null; hour_budget_minutes: number | null; manual_consumption_minutes: number; teamspace_consumption_minutes?: number; consumption_minutes?: number; closed_at: string | null; created_at: string; updated_at: string; session_count?: number; recurring_session_count?: number; manual_session_count?: number; has_recurring_billing?: boolean; billed_minutes?: number; open_todos?: number; overdue_todos?: number; done_todos?: number; teamspace_entry_count?: number; teamspace_entries?: ProjectTeamspaceEntry[]; unassigned_teamspace_session_count?: number; unassigned_teamspace_subentry_count?: number; close_review_required?: boolean; hidden_for_user?: boolean; }; export type ProjectTeamspaceEntry = { id: string; project_id?: string; teamspace_project: string | null; teamspace_api_project_id?: string | null; teamspace_api_project_url?: string | null; teamspace_description?: string | null; subentries?: ProjectTeamspaceSubentry[]; is_default: boolean; hour_budget_minutes: number | null; budget_sync_disabled?: boolean; manual_consumption_minutes: number; teamspace_consumption_minutes?: number; consumption_minutes?: number; display_order?: number; }; export type ProjectTeamspaceSubentry = { id: string; project_teamspace_entry_id?: string; teamspace_api_project_id: string; teamspace_api_project_url: string | null; teamspace_project_id: string | null; billing_type: string | null; name: string | null; alias: string; description: string; progress: number | null; planned_minutes: number | null; sum_minutes: number | null; planned_minutes_billable: number | null; sum_minutes_billable: number | null; planned_income: number | string | null; sum_income: number | string | null; consumption_minutes?: number; display_order: number; }; export type TodoPriority = "low" | "medium" | "high" | "urgent"; export type TodoStatus = "open" | "done"; export type TicketTodo = { id: string; ticket_id: string; ticket_number?: string; organization_name?: string | null; project_id?: string | null; teamspace_project?: string | null; title: string; description: string; priority: TodoPriority; status: TodoStatus; sort_order: number; starts_on: string | null; ends_on: string | null; completed_at: string | null; created_at: string; updated_at: string; }; export type TicketSummary = { id: string; ticket_number: string; title: string | null; organization_id: string | null; organization_name: string | null; customer_name: string | null; work_type: WorkType | null; project_id: string | null; session_count: number; total_minutes: number; crm_billed_minutes: number; billable_minutes: number; non_billable_minutes: number; open_minutes: number; open_count: number; ticket_open_count: number; billable_count: number; billed_count: number; non_billable_count: number; recurring_session_count: number; manual_session_count: number; requires_closure: boolean; closed: boolean; closed_at: string | null; }; export type OpenSession = { id: string; ticket_id: string; ticket_number: string; organization_id: string | null; organization_name: string | null; customer_name: string; activity: string; work_type: WorkType; project_teamspace_entry_id?: string | null; project_teamspace_project?: string | null; started_at: string; rounded_minutes: number; recurring_billing_id?: string | null; }; export type ActivityBucket = { bucket_key: string; session_count: number; total_minutes: number; }; export type PeriodOverview = { periodType: PeriodType; period: string; closed: boolean; closedAt: string | null; canClose: boolean; totals: { tickets: number; sessions: number; minutes: number; crmBilledMinutes: number; billableMinutes: number; nonBillableMinutes: number; openMinutes: number; openSessions: number; }; tickets: TicketSummary[]; openSessions: OpenSession[]; activitySeries: ActivityBucket[]; }; export type TicketDayBilling = { day: string; project_teamspace_entry_id?: string | null; billed_minutes: number; }; export type TicketAvailableMonth = { month: string; session_count: number; }; export type SessionEntry = { id: string; organization_id: string | null; organization_name: string | null; customer_name: string; activity: string; zammad_article_body?: string | null; work_type: WorkType; project_teamspace_entry_id?: string | null; project_teamspace_project?: string | null; started_at: string; ended_at: string; duration_seconds: number; rounded_minutes: number; billing_status: BillingStatus; billing_updated_at: string | null; created_at: string; recurring_billing_id: string | null; recurring_billing_slot_id: string | null; recurring_occurrence_date: string | null; zammad_source_article_id?: string | null; zammad_article_status?: "pending" | "sent" | null; zammad_article_id?: string | null; zammad_article_type_id?: number; }; export type TicketPeriod = { periodType: TicketDetailPeriodType; period: string; closed: boolean; closedAt: string | null; filters?: { month: string; status: "all" | "open" | "billable" | "billed" | "non_billable"; source: "all" | "manual" | "recurring"; }; availableMonths?: TicketAvailableMonth[]; ticket: { id: string; ticket_number: string; title: string | null; organization_id: string | null; organization_name: string | null; customer_name: string | null; work_type: WorkType | null; zammad_ticket_id?: string | null; zammad_group_id?: string | null; zammad_priority_id?: string | null; zammad_state_id?: string | null; zammad_owner_id?: string | null; zammad_owner_user_id?: string | null; zammad_owner_display_name?: string | null; zammad_owner_username?: string | null; is_foreign_zammad_owner?: boolean; can_edit_ticket_data?: boolean; closed_at: string | null; requires_closure: boolean; recurring_session_count: number; manual_session_count: number; has_recurring_billing?: boolean; }; sessions: SessionEntry[]; dayBillings: TicketDayBilling[]; project?: ProjectSummary | null; todos?: TicketTodo[]; canClose: boolean; openCount: number; ticketOpenCount: number; }; export type MonthOverview = PeriodOverview; export type TicketMonth = TicketPeriod; export type StatisticsDailyBucket = { day: string; sessions: number; total_minutes: number; billed_minutes: number; billable_minutes: number; non_billable_minutes: number; open_minutes: number; billed_sessions: number; billable_sessions: number; non_billable_sessions: number; open_sessions: number; crm_billed_minutes: number; }; export type StatisticsGroup = { organization_id?: string | null; organization_name?: string; work_type?: WorkType; tickets: number; sessions: number; total_minutes: number; billed_minutes: number; billable_minutes: number; non_billable_minutes: number; open_minutes: number; billed_sessions: number; billable_sessions: number; non_billable_sessions: number; open_sessions: number; crm_billed_minutes: number; crm_delta_minutes: number; }; export type StatisticsTicket = { ticket_id: string; ticket_number: string; organization_id: string | null; organization_name: string; active_days: number; sessions: number; total_minutes: number; billed_minutes: number; billable_minutes: number; non_billable_minutes: number; open_minutes: number; billed_sessions: number; billable_sessions: number; non_billable_sessions: number; open_sessions: number; crm_billed_minutes: number; crm_delta_minutes: number; }; export type StatisticsOpenSession = { id: string; ticket_id: string; ticket_number: string; organization_name: string; activity: string; started_at: string; rounded_minutes: number; }; export type StatisticsCrmDay = { ticket_id: string; ticket_number: string; organization_name: string; day: string; tracked_minutes: number; crm_billed_minutes: number; delta_minutes?: number; acknowledged?: boolean; acknowledged_at?: string | null; }; export type StatisticsTeamspaceDay = { ticket_id: string; ticket_number: string; organization_name: string; day: string; tracked_minutes: number; crm_billed_minutes: number; delta_minutes: number; session_count: number; project_teamspace_project: string | null; }; export type StatisticsProjectFollowup = { project_id: string; ticket_id: string; ticket_number: string; title: string | null; organization_name: string | null; teamspace_project: string | null; hour_budget_minutes: number | null; consumption_minutes: number; remaining_minutes: number | null; latest_tt_update: string; last_session_at: string | null; project_updated_at: string; open_followup_todo_id: string | null; followup_state: "open" | "done" | "dismissed" | null; open_todos: number; overdue_todos: number; }; export type StatisticsProjectFollowupOverview = { enabled: boolean; weeks: number; secondEnabled: boolean; secondWeeks: number; createdTodos: number; updatedTodos: number; projects: StatisticsProjectFollowup[]; }; export type StatisticsOverview = { periodType: "month" | "week"; period: string; closed: boolean; closedAt: string | null; totals: { tickets: number; sessions: number; minutes: number; billedMinutes: number; billableMinutes: number; nonBillableMinutes: number; openMinutes: number; billedSessions: number; billableSessions: number; nonBillableSessions: number; openSessions: number; recurringMinutes: number; manualMinutes: number; recurringSessions: number; manualSessions: number; averageSessionMinutes: number; activeDays: number; crmBilledMinutes: number; crmDeltaMinutes: number; }; dailySeries: StatisticsDailyBucket[]; organizations: StatisticsGroup[]; workTypes: StatisticsGroup[]; tickets: StatisticsTicket[]; attention: { openSessions: StatisticsOpenSession[]; missingCrmDays: StatisticsCrmDay[]; acknowledgedMissingCrmDays: StatisticsCrmDay[]; crmMismatches: StatisticsCrmDay[]; }; teamspaceDays: StatisticsTeamspaceDay[]; };