diff --git a/.env.example b/.env.example index a0dc663..9d128a5 100644 --- a/.env.example +++ b/.env.example @@ -22,3 +22,12 @@ NODE_ENV=development LOG_LEVEL=info PORT=3000 PUBLIC_BASE_URL=http://localhost:5173 + +# --- Kimai-Sync (optional, ENTWICKLUN-9) --- +# Nur wenn ALLE vier gesetzt sind, synct ebw beim Check-In/Out nach Kimai +# (sonst No-Op). API-Token in Kimai unter Benutzerprofil → API-Zugriff. +# PROJECT/ACTIVITY = numerische IDs des Default-Projekts/-Tätigkeit in Kimai. +# KIMAI_BASE_URL=https://kimai.tool-ctrl.de +# KIMAI_API_TOKEN= +# KIMAI_PROJECT_ID= +# KIMAI_ACTIVITY_ID= diff --git a/apps/api/src/env.ts b/apps/api/src/env.ts index 8d4435b..c938c70 100644 --- a/apps/api/src/env.ts +++ b/apps/api/src/env.ts @@ -19,6 +19,13 @@ const envSchema = z.object({ CRON_BEARER_TOKEN: z.string().min(8), PUBLIC_BASE_URL: z.string().url().default('http://localhost:5173'), + + // Kimai-Anbindung (optional). Erst wenn alle gesetzt sind, wird beim + // Check-In/Out wirklich nach Kimai synchronisiert; sonst No-Op. + KIMAI_BASE_URL: z.string().url().optional(), + KIMAI_API_TOKEN: z.string().min(1).optional(), + KIMAI_PROJECT_ID: z.coerce.number().int().optional(), + KIMAI_ACTIVITY_ID: z.coerce.number().int().optional(), }); export type Env = z.infer; diff --git a/apps/api/src/lib/kimai.ts b/apps/api/src/lib/kimai.ts new file mode 100644 index 0000000..134e918 --- /dev/null +++ b/apps/api/src/lib/kimai.ts @@ -0,0 +1,102 @@ +// Kimai-Anbindung (optional). Nur wenn KIMAI_BASE_URL + KIMAI_API_TOKEN + +// KIMAI_PROJECT_ID + KIMAI_ACTIVITY_ID gesetzt sind, wird wirklich synchronisiert; +// sonst No-Op. Alle Calls sind best-effort — ein Kimai-Ausfall darf den +// ebw-Check-In/Out NIE blockieren. + +import { loadEnv } from '../env.js'; +import { logger } from './logger.js'; + +type KimaiConfig = { + baseUrl: string; + token: string; + projectId: number; + activityId: number; +}; + +function kimaiConfig(): KimaiConfig | null { + const env = loadEnv(); + if ( + env.KIMAI_BASE_URL && + env.KIMAI_API_TOKEN && + env.KIMAI_PROJECT_ID !== undefined && + env.KIMAI_ACTIVITY_ID !== undefined + ) { + return { + baseUrl: env.KIMAI_BASE_URL.replace(/\/$/, ''), + token: env.KIMAI_API_TOKEN, + projectId: env.KIMAI_PROJECT_ID, + activityId: env.KIMAI_ACTIVITY_ID, + }; + } + return null; +} + +export function kimaiEnabled(): boolean { + return kimaiConfig() !== null; +} + +async function safeText(res: Response): Promise { + try { + return (await res.text()).slice(0, 300); + } catch { + return ''; + } +} + +/** + * Startet ein laufendes Timesheet in Kimai (Clock-In). Liefert die Kimai- + * Timesheet-ID zurück oder null (nicht konfiguriert / Fehler). + */ +export async function kimaiClockIn(opts: { begin: Date; description?: string }): Promise { + const cfg = kimaiConfig(); + if (!cfg) { + logger.debug('kimai not configured — clock-in skipped'); + return null; + } + try { + const res = await fetch(`${cfg.baseUrl}/api/timesheets`, { + method: 'POST', + headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${cfg.token}` }, + body: JSON.stringify({ + begin: opts.begin.toISOString(), + project: cfg.projectId, + activity: cfg.activityId, + description: opts.description ?? 'ebw Check-In', + }), + }); + if (!res.ok) { + logger.warn({ status: res.status, body: await safeText(res) }, 'kimai clock-in failed'); + return null; + } + const data = (await res.json()) as { id?: number }; + return typeof data.id === 'number' ? data.id : null; + } catch (err) { + logger.warn({ err }, 'kimai clock-in error'); + return null; + } +} + +/** + * Stoppt das laufende Timesheet in Kimai (Clock-Out). Best-effort. + */ +export async function kimaiClockOut(opts: { timesheetId: number }): Promise { + const cfg = kimaiConfig(); + if (!cfg) { + logger.debug('kimai not configured — clock-out skipped'); + return false; + } + try { + const res = await fetch(`${cfg.baseUrl}/api/timesheets/${opts.timesheetId}/stop`, { + method: 'PATCH', + headers: { Authorization: `Bearer ${cfg.token}` }, + }); + if (!res.ok) { + logger.warn({ status: res.status, body: await safeText(res) }, 'kimai clock-out failed'); + return false; + } + return true; + } catch (err) { + logger.warn({ err }, 'kimai clock-out error'); + return false; + } +} diff --git a/apps/api/src/routers/day-entry.ts b/apps/api/src/routers/day-entry.ts index 5253716..c786538 100644 --- a/apps/api/src/routers/day-entry.ts +++ b/apps/api/src/routers/day-entry.ts @@ -4,6 +4,7 @@ import { dayEntry, todo, blocker, user, type Todo } from '@cockpit/db'; import { DayEntrySchemas } from '@cockpit/shared'; import { router, protectedProcedure } from '../trpc.js'; import { todayIso, previousWerktag, nextWerktag } from '../lib/werktag.js'; +import { kimaiClockIn, kimaiClockOut, kimaiEnabled } from '../lib/kimai.js'; export const dayEntryRouter = router({ /** @@ -162,9 +163,54 @@ export const dayEntryRouter = router({ return { entry: created, todos: todoRows, carriedOver: stale.length }; }); + // Kimai-Sync (best-effort, nicht blockierend): Check-In = Clock-In. + if (kimaiEnabled()) { + const tsId = await kimaiClockIn({ + begin: result.entry.checkedInAt ?? new Date(), + description: `ebw — ${ctx.user.name}`, + }); + if (tsId !== null) { + await ctx.db + .update(dayEntry) + .set({ kimaiTimesheetId: tsId, kimaiSynced: true }) + .where(eq(dayEntry.id, result.entry.id)); + } + } + return result; }), + /** + * Check-Out / Arbeitsende: markiert das Ende der Arbeits-Session. Best-effort + * Kimai-Clock-Out, falls beim Check-In ein Timesheet gestartet wurde. + */ + checkOut: protectedProcedure.mutation(async ({ ctx }) => { + const date = todayIso(); + const entry = ( + await ctx.db + .select() + .from(dayEntry) + .where(and(eq(dayEntry.userId, ctx.user.id), eq(dayEntry.date, date))) + .limit(1) + )[0]; + if (!entry) { + throw new TRPCError({ code: 'BAD_REQUEST', message: 'Du bist heute noch nicht locked in.' }); + } + if (entry.checkedOutAt) return entry; + + const now = new Date(); + const [updated] = await ctx.db + .update(dayEntry) + .set({ checkedOutAt: now, updatedAt: now }) + .where(eq(dayEntry.id, entry.id)) + .returning(); + + if (entry.kimaiTimesheetId !== null && kimaiEnabled()) { + await kimaiClockOut({ timesheetId: entry.kimaiTimesheetId }); + } + return updated; + }), + /** * ToDos im Verlauf des Tages ändern (vor Reflexion). */ diff --git a/apps/web/src/routes/heute.tsx b/apps/web/src/routes/heute.tsx index 92bb873..4e709ef 100644 --- a/apps/web/src/routes/heute.tsx +++ b/apps/web/src/routes/heute.tsx @@ -6,8 +6,9 @@ import { Card } from '../components/ui/Card'; import { Button } from '../components/ui/Button'; import { SkeletonCard } from '../components/ui/SkeletonCard'; import { toast } from 'sonner'; -import { X, Plus, RotateCw, BellRing, Play, Clock, Check } from 'lucide-react'; +import { X, Plus, RotateCw, BellRing, Play, Clock, Check, LogOut } from 'lucide-react'; import { TimelineSection, ManualDialog } from '../components/time/TimelineSection'; +import { formatDurationCompact } from '../lib/format-duration'; /** Aktuelle Stunde in Europe/Berlin (0–23). */ function berlinHourNow(): number { @@ -315,6 +316,61 @@ function AddTodoInline() { ); } +function CheckInOutBar({ + checkedInAt, + checkedOutAt, +}: { + checkedInAt: string | Date | null; + checkedOutAt: string | Date | null; +}) { + const utils = trpc.useUtils(); + const checkOut = trpc.dayEntry.checkOut.useMutation({ + onSuccess: async () => { + toast('Feierabend — Check-Out gespeichert.'); + await utils.dayEntry.today.invalidate(); + await utils.dashboard.overview.invalidate(); + }, + }); + const hhmm = (d: string | Date | null) => + d + ? new Intl.DateTimeFormat('de-DE', { + timeZone: 'Europe/Berlin', + hour: '2-digit', + minute: '2-digit', + }).format(new Date(d)) + : '—'; + const duration = + checkedInAt && checkedOutAt + ? formatDurationCompact( + Math.max(0, Math.round((new Date(checkedOutAt).getTime() - new Date(checkedInAt).getTime()) / 1000)), + ) + : null; + + return ( +
+ + Arbeitsantritt {hhmm(checkedInAt)} + + {checkedOutAt ? ( + + · Feierabend {hhmm(checkedOutAt)} + {duration && ` · ${duration}`} + + ) : ( + + )} +
+ ); +} + function AddUnplannedInline() { const utils = trpc.useUtils(); const [title, setTitle] = useState(''); @@ -357,7 +413,11 @@ function EinstempeltView({ entry, }: { todos: Array<{ id: string; title: string; status: 'open' | 'done' | 'dropped'; unplanned?: boolean }>; - entry: { status: 'begun' | 'full' | 'absent' }; + entry: { + status: 'begun' | 'full' | 'absent'; + checkedInAt: string | Date | null; + checkedOutAt: string | Date | null; + }; }) { // Reflexion ist „fällig", wenn nach 18:00 Berlin und noch nicht abgeschlossen. const reflectionDue = entry.status !== 'full' && berlinHourNow() >= 18; @@ -375,6 +435,8 @@ function EinstempeltView({

{subtitle}

+ + {reflectionDue && (
statement-breakpoint +ALTER TABLE "day_entry" ADD COLUMN "kimai_timesheet_id" integer;--> statement-breakpoint +ALTER TABLE "day_entry" ADD COLUMN "kimai_synced" boolean DEFAULT false NOT NULL; \ No newline at end of file diff --git a/packages/db/migrations/meta/0014_snapshot.json b/packages/db/migrations/meta/0014_snapshot.json new file mode 100644 index 0000000..16b0f38 --- /dev/null +++ b/packages/db/migrations/meta/0014_snapshot.json @@ -0,0 +1,3299 @@ +{ + "id": "a42c494f-e272-4a11-9b39-d02225004768", + "prevId": "9e7dd400-642e-4475-9361-2f9e3e24adf6", + "version": "7", + "dialect": "postgresql", + "tables": { + "public.absence_day": { + "name": "absence_day", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "date": { + "name": "date", + "type": "date", + "primaryKey": false, + "notNull": true + }, + "reason": { + "name": "reason", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "uniq_absence_user_date": { + "name": "uniq_absence_user_date", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "date", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "absence_day_user_id_user_id_fk": { + "name": "absence_day_user_id_user_id_fk", + "tableFrom": "absence_day", + "tableTo": "user", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.area": { + "name": "area", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "slug": { + "name": "slug", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "kind": { + "name": "kind", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "order": { + "name": "order", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "uniq_area_slug": { + "name": "uniq_area_slug", + "columns": [ + { + "expression": "slug", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.audit_event": { + "name": "audit_event", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "actor_user_id": { + "name": "actor_user_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "action": { + "name": "action", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "entity_kind": { + "name": "entity_kind", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "entity_id": { + "name": "entity_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "payload": { + "name": "payload", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'::jsonb" + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "idx_audit_event_actor": { + "name": "idx_audit_event_actor", + "columns": [ + { + "expression": "actor_user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_audit_event_action": { + "name": "idx_audit_event_action", + "columns": [ + { + "expression": "action", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_audit_event_entity": { + "name": "idx_audit_event_entity", + "columns": [ + { + "expression": "entity_kind", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "entity_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "audit_event_actor_user_id_user_id_fk": { + "name": "audit_event_actor_user_id_user_id_fk", + "tableFrom": "audit_event", + "tableTo": "user", + "columnsFrom": [ + "actor_user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.blocker": { + "name": "blocker", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "area_id": { + "name": "area_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "project_id": { + "name": "project_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "owner_user_id": { + "name": "owner_user_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "opened_by": { + "name": "opened_by", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "opened_at": { + "name": "opened_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "resolved_by": { + "name": "resolved_by", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "resolved_at": { + "name": "resolved_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + }, + "resolution_text": { + "name": "resolution_text", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "idx_blocker_area": { + "name": "idx_blocker_area", + "columns": [ + { + "expression": "area_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_blocker_project": { + "name": "idx_blocker_project", + "columns": [ + { + "expression": "project_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_blocker_opened_at": { + "name": "idx_blocker_opened_at", + "columns": [ + { + "expression": "opened_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "blocker_owner_user_id_user_id_fk": { + "name": "blocker_owner_user_id_user_id_fk", + "tableFrom": "blocker", + "tableTo": "user", + "columnsFrom": [ + "owner_user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "blocker_opened_by_user_id_fk": { + "name": "blocker_opened_by_user_id_fk", + "tableFrom": "blocker", + "tableTo": "user", + "columnsFrom": [ + "opened_by" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "blocker_resolved_by_user_id_fk": { + "name": "blocker_resolved_by_user_id_fk", + "tableFrom": "blocker", + "tableTo": "user", + "columnsFrom": [ + "resolved_by" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.campaign": { + "name": "campaign", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "area_id": { + "name": "area_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'active'" + }, + "reach": { + "name": "reach", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "owner_user_id": { + "name": "owner_user_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "idx_campaign_status": { + "name": "idx_campaign_status", + "columns": [ + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "campaign_area_id_area_id_fk": { + "name": "campaign_area_id_area_id_fk", + "tableFrom": "campaign", + "tableTo": "area", + "columnsFrom": [ + "area_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "restrict", + "onUpdate": "no action" + }, + "campaign_owner_user_id_user_id_fk": { + "name": "campaign_owner_user_id_user_id_fk", + "tableFrom": "campaign", + "tableTo": "user", + "columnsFrom": [ + "owner_user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.change_entry": { + "name": "change_entry", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "project_id": { + "name": "project_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "titel": { + "name": "titel", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "auswirkung": { + "name": "auswirkung", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "entscheidung": { + "name": "entscheidung", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'offen'" + }, + "created_by": { + "name": "created_by", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "idx_change_entry_project": { + "name": "idx_change_entry_project", + "columns": [ + { + "expression": "project_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "change_entry_project_id_project_id_fk": { + "name": "change_entry_project_id_project_id_fk", + "tableFrom": "change_entry", + "tableTo": "project", + "columnsFrom": [ + "project_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "change_entry_created_by_user_id_fk": { + "name": "change_entry_created_by_user_id_fk", + "tableFrom": "change_entry", + "tableTo": "user", + "columnsFrom": [ + "created_by" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.day_entry": { + "name": "day_entry", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "date": { + "name": "date", + "type": "date", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "checked_in_at": { + "name": "checked_in_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + }, + "checked_out_at": { + "name": "checked_out_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + }, + "kimai_timesheet_id": { + "name": "kimai_timesheet_id", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "kimai_synced": { + "name": "kimai_synced", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "reflected_at": { + "name": "reflected_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + }, + "reflection_text": { + "name": "reflection_text", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "ampel": { + "name": "ampel", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "trend": { + "name": "trend", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "url": { + "name": "url", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "blocker_id": { + "name": "blocker_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "edit_locked_at": { + "name": "edit_locked_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + }, + "published_at": { + "name": "published_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "uniq_day_entry_user_date": { + "name": "uniq_day_entry_user_date", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "date", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_day_entry_date": { + "name": "idx_day_entry_date", + "columns": [ + { + "expression": "date", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_day_entry_published_at": { + "name": "idx_day_entry_published_at", + "columns": [ + { + "expression": "published_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "day_entry_user_id_user_id_fk": { + "name": "day_entry_user_id_user_id_fk", + "tableFrom": "day_entry", + "tableTo": "user", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.deal": { + "name": "deal", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "area_id": { + "name": "area_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "owner_user_id": { + "name": "owner_user_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "value_eur": { + "name": "value_eur", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "probability": { + "name": "probability", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 50 + }, + "stage": { + "name": "stage", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "entered_stage_at": { + "name": "entered_stage_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "won_at": { + "name": "won_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + }, + "won_value_eur": { + "name": "won_value_eur", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "idx_deal_stage": { + "name": "idx_deal_stage", + "columns": [ + { + "expression": "stage", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_deal_owner": { + "name": "idx_deal_owner", + "columns": [ + { + "expression": "owner_user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "deal_area_id_area_id_fk": { + "name": "deal_area_id_area_id_fk", + "tableFrom": "deal", + "tableTo": "area", + "columnsFrom": [ + "area_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "restrict", + "onUpdate": "no action" + }, + "deal_owner_user_id_user_id_fk": { + "name": "deal_owner_user_id_user_id_fk", + "tableFrom": "deal", + "tableTo": "user", + "columnsFrom": [ + "owner_user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.gtm_step": { + "name": "gtm_step", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "product": { + "name": "product", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "owner_user_id": { + "name": "owner_user_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'open'" + }, + "order": { + "name": "order", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "idx_gtm_product": { + "name": "idx_gtm_product", + "columns": [ + { + "expression": "product", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "gtm_step_owner_user_id_user_id_fk": { + "name": "gtm_step_owner_user_id_user_id_fk", + "tableFrom": "gtm_step", + "tableTo": "user", + "columnsFrom": [ + "owner_user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.lead": { + "name": "lead", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "area_id": { + "name": "area_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "project_id": { + "name": "project_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "firma": { + "name": "firma", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'cold'" + }, + "score": { + "name": "score", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "owner_user_id": { + "name": "owner_user_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "branche": { + "name": "branche", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "sub_segment": { + "name": "sub_segment", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "standorte": { + "name": "standorte", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "mitarbeiterzahl": { + "name": "mitarbeiterzahl", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "umsatz": { + "name": "umsatz", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "website": { + "name": "website", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "quelle": { + "name": "quelle", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "pain_point": { + "name": "pain_point", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "status_quo_kosten": { + "name": "status_quo_kosten", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "bestehende_loesung": { + "name": "bestehende_loesung", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "wechselgrund": { + "name": "wechselgrund", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "persoenlicher_erfolg": { + "name": "persoenlicher_erfolg", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "budget_indikation": { + "name": "budget_indikation", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "entscheidungshorizont": { + "name": "entscheidungshorizont", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "compelling_event": { + "name": "compelling_event", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "mitbewerber": { + "name": "mitbewerber", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "buying_center": { + "name": "buying_center", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "beschaffungsweg": { + "name": "beschaffungsweg", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "kommunikationsstil": { + "name": "kommunikationsstil", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "vorlieben": { + "name": "vorlieben", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "hot_buttons": { + "name": "hot_buttons", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "no_gos": { + "name": "no_gos", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "druckpunkte": { + "name": "druckpunkte", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "anker": { + "name": "anker", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "vertrauenslevel": { + "name": "vertrauenslevel", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "nutzen_hypothese": { + "name": "nutzen_hypothese", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "differenzierer": { + "name": "differenzierer", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "naechster_schritt": { + "name": "naechster_schritt", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "naechster_schritt_datum": { + "name": "naechster_schritt_datum", + "type": "date", + "primaryKey": false, + "notNull": false + }, + "risiken": { + "name": "risiken", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "plan_b": { + "name": "plan_b", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "offene_fragen": { + "name": "offene_fragen", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'[]'::jsonb" + }, + "anhaenge": { + "name": "anhaenge", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'[]'::jsonb" + }, + "promoted_deal_id": { + "name": "promoted_deal_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "created_by": { + "name": "created_by", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "idx_lead_status": { + "name": "idx_lead_status", + "columns": [ + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_lead_owner": { + "name": "idx_lead_owner", + "columns": [ + { + "expression": "owner_user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_lead_project": { + "name": "idx_lead_project", + "columns": [ + { + "expression": "project_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "lead_area_id_area_id_fk": { + "name": "lead_area_id_area_id_fk", + "tableFrom": "lead", + "tableTo": "area", + "columnsFrom": [ + "area_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "restrict", + "onUpdate": "no action" + }, + "lead_project_id_project_id_fk": { + "name": "lead_project_id_project_id_fk", + "tableFrom": "lead", + "tableTo": "project", + "columnsFrom": [ + "project_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "lead_owner_user_id_user_id_fk": { + "name": "lead_owner_user_id_user_id_fk", + "tableFrom": "lead", + "tableTo": "user", + "columnsFrom": [ + "owner_user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "lead_promoted_deal_id_deal_id_fk": { + "name": "lead_promoted_deal_id_deal_id_fk", + "tableFrom": "lead", + "tableTo": "deal", + "columnsFrom": [ + "promoted_deal_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "lead_created_by_user_id_fk": { + "name": "lead_created_by_user_id_fk", + "tableFrom": "lead", + "tableTo": "user", + "columnsFrom": [ + "created_by" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.lead_contact": { + "name": "lead_contact", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "lead_id": { + "name": "lead_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "rolle": { + "name": "rolle", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "funktion": { + "name": "funktion", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "telefon": { + "name": "telefon", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "linkedin": { + "name": "linkedin", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "im_buying_center_seit": { + "name": "im_buying_center_seit", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "sprache": { + "name": "sprache", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "is_primary": { + "name": "is_primary", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "order": { + "name": "order", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "idx_lead_contact_lead": { + "name": "idx_lead_contact_lead", + "columns": [ + { + "expression": "lead_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "lead_contact_lead_id_lead_id_fk": { + "name": "lead_contact_lead_id_lead_id_fk", + "tableFrom": "lead_contact", + "tableTo": "lead", + "columnsFrom": [ + "lead_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.lead_handover": { + "name": "lead_handover", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "campaign_id": { + "name": "campaign_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "deal_id": { + "name": "deal_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "uebergeben_am": { + "name": "uebergeben_am", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "uebergeben_von": { + "name": "uebergeben_von", + "type": "uuid", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "lead_handover_campaign_id_campaign_id_fk": { + "name": "lead_handover_campaign_id_campaign_id_fk", + "tableFrom": "lead_handover", + "tableTo": "campaign", + "columnsFrom": [ + "campaign_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "lead_handover_deal_id_deal_id_fk": { + "name": "lead_handover_deal_id_deal_id_fk", + "tableFrom": "lead_handover", + "tableTo": "deal", + "columnsFrom": [ + "deal_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "lead_handover_uebergeben_von_user_id_fk": { + "name": "lead_handover_uebergeben_von_user_id_fk", + "tableFrom": "lead_handover", + "tableTo": "user", + "columnsFrom": [ + "uebergeben_von" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.lead_touchpoint": { + "name": "lead_touchpoint", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "lead_id": { + "name": "lead_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "datum": { + "name": "datum", + "type": "date", + "primaryKey": false, + "notNull": true + }, + "kanal": { + "name": "kanal", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "bearbeiter_user_id": { + "name": "bearbeiter_user_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "inhalt": { + "name": "inhalt", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "outcome": { + "name": "outcome", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "follow_up_bis": { + "name": "follow_up_bis", + "type": "date", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "idx_lead_touchpoint_lead": { + "name": "idx_lead_touchpoint_lead", + "columns": [ + { + "expression": "lead_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_lead_touchpoint_followup": { + "name": "idx_lead_touchpoint_followup", + "columns": [ + { + "expression": "follow_up_bis", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "lead_touchpoint_lead_id_lead_id_fk": { + "name": "lead_touchpoint_lead_id_lead_id_fk", + "tableFrom": "lead_touchpoint", + "tableTo": "lead", + "columnsFrom": [ + "lead_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "lead_touchpoint_bearbeiter_user_id_user_id_fk": { + "name": "lead_touchpoint_bearbeiter_user_id_user_id_fk", + "tableFrom": "lead_touchpoint", + "tableTo": "user", + "columnsFrom": [ + "bearbeiter_user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.milestone": { + "name": "milestone", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "project_id": { + "name": "project_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "due": { + "name": "due", + "type": "date", + "primaryKey": false, + "notNull": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'open'" + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "ergebnis": { + "name": "ergebnis", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "kundennutzen": { + "name": "kundennutzen", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "order": { + "name": "order", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "idx_milestone_project": { + "name": "idx_milestone_project", + "columns": [ + { + "expression": "project_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "milestone_project_id_project_id_fk": { + "name": "milestone_project_id_project_id_fk", + "tableFrom": "milestone", + "tableTo": "project", + "columnsFrom": [ + "project_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.phase_gate": { + "name": "phase_gate", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "project_id": { + "name": "project_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "phase": { + "name": "phase", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "ergebnis_erreicht": { + "name": "ergebnis_erreicht", + "type": "boolean", + "primaryKey": false, + "notNull": true + }, + "notiz": { + "name": "notiz", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "reviewed_by": { + "name": "reviewed_by", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "reviewed_at": { + "name": "reviewed_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "idx_phase_gate_project": { + "name": "idx_phase_gate_project", + "columns": [ + { + "expression": "project_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "phase_gate_project_id_project_id_fk": { + "name": "phase_gate_project_id_project_id_fk", + "tableFrom": "phase_gate", + "tableTo": "project", + "columnsFrom": [ + "project_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "phase_gate_reviewed_by_user_id_fk": { + "name": "phase_gate_reviewed_by_user_id_fk", + "tableFrom": "phase_gate", + "tableTo": "user", + "columnsFrom": [ + "reviewed_by" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.project": { + "name": "project", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "area_id": { + "name": "area_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "maxime": { + "name": "maxime", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "ziel": { + "name": "ziel", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "nicht_ziele": { + "name": "nicht_ziele", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "liefergegenstaende": { + "name": "liefergegenstaende", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "zieldreieck_flex": { + "name": "zieldreieck_flex", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "kind": { + "name": "kind", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "verantwortliche_user_id": { + "name": "verantwortliche_user_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "arbeitsmodus": { + "name": "arbeitsmodus", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "modus": { + "name": "modus", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'standard'" + }, + "phase": { + "name": "phase", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'definition'" + }, + "outline_steckbrief_url": { + "name": "outline_steckbrief_url", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "steckbrief_freigegeben": { + "name": "steckbrief_freigegeben", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "plane_project_url": { + "name": "plane_project_url", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "risikoliste_url": { + "name": "risikoliste_url", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "dod_text": { + "name": "dod_text", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "start": { + "name": "start", + "type": "date", + "primaryKey": false, + "notNull": false + }, + "deadline": { + "name": "deadline", + "type": "date", + "primaryKey": false, + "notNull": false + }, + "status_cache": { + "name": "status_cache", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "trend_cache": { + "name": "trend_cache", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "pflicht_minimum_state": { + "name": "pflicht_minimum_state", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'::jsonb" + }, + "archiviert": { + "name": "archiviert", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "archiviert_am": { + "name": "archiviert_am", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + }, + "lessons_learned_url": { + "name": "lessons_learned_url", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "abschlussvermerk": { + "name": "abschlussvermerk", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_by": { + "name": "created_by", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "idx_project_area": { + "name": "idx_project_area", + "columns": [ + { + "expression": "area_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_project_archived": { + "name": "idx_project_archived", + "columns": [ + { + "expression": "archiviert", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "project_area_id_area_id_fk": { + "name": "project_area_id_area_id_fk", + "tableFrom": "project", + "tableTo": "area", + "columnsFrom": [ + "area_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "restrict", + "onUpdate": "no action" + }, + "project_verantwortliche_user_id_user_id_fk": { + "name": "project_verantwortliche_user_id_user_id_fk", + "tableFrom": "project", + "tableTo": "user", + "columnsFrom": [ + "verantwortliche_user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "project_created_by_user_id_fk": { + "name": "project_created_by_user_id_fk", + "tableFrom": "project", + "tableTo": "user", + "columnsFrom": [ + "created_by" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.project_status": { + "name": "project_status", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "project_id": { + "name": "project_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "ampel": { + "name": "ampel", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "trend": { + "name": "trend", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "text": { + "name": "text", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "extern_sichtbar": { + "name": "extern_sichtbar", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "created_by": { + "name": "created_by", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "idx_project_status_project": { + "name": "idx_project_status_project", + "columns": [ + { + "expression": "project_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "project_status_project_id_project_id_fk": { + "name": "project_status_project_id_project_id_fk", + "tableFrom": "project_status", + "tableTo": "project", + "columnsFrom": [ + "project_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "project_status_created_by_user_id_fk": { + "name": "project_status_created_by_user_id_fk", + "tableFrom": "project_status", + "tableTo": "user", + "columnsFrom": [ + "created_by" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.risk": { + "name": "risk", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "project_id": { + "name": "project_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "kind": { + "name": "kind", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'risiko'" + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "wahrscheinlichkeit": { + "name": "wahrscheinlichkeit", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'mittel'" + }, + "auswirkung": { + "name": "auswirkung", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'mittel'" + }, + "herkunft": { + "name": "herkunft", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "showstopper": { + "name": "showstopper", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "massnahme": { + "name": "massnahme", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "strategie": { + "name": "strategie", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "owner_user_id": { + "name": "owner_user_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'offen'" + }, + "created_by": { + "name": "created_by", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "idx_risk_project": { + "name": "idx_risk_project", + "columns": [ + { + "expression": "project_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_risk_showstopper": { + "name": "idx_risk_showstopper", + "columns": [ + { + "expression": "showstopper", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "risk_project_id_project_id_fk": { + "name": "risk_project_id_project_id_fk", + "tableFrom": "risk", + "tableTo": "project", + "columnsFrom": [ + "project_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "risk_owner_user_id_user_id_fk": { + "name": "risk_owner_user_id_user_id_fk", + "tableFrom": "risk", + "tableTo": "user", + "columnsFrom": [ + "owner_user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "risk_created_by_user_id_fk": { + "name": "risk_created_by_user_id_fk", + "tableFrom": "risk", + "tableTo": "user", + "columnsFrom": [ + "created_by" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.session": { + "name": "session", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "ip_address": { + "name": "ip_address", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "user_agent": { + "name": "user_agent", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "idx_session_user_id": { + "name": "idx_session_user_id", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_session_expires_at": { + "name": "idx_session_expires_at", + "columns": [ + { + "expression": "expires_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "session_user_id_user_id_fk": { + "name": "session_user_id_user_id_fk", + "tableFrom": "session", + "tableTo": "user", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.stakeholder": { + "name": "stakeholder", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "project_id": { + "name": "project_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "rolle": { + "name": "rolle", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "interesse": { + "name": "interesse", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'mittel'" + }, + "einfluss": { + "name": "einfluss", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'mittel'" + }, + "haltung": { + "name": "haltung", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'neutral'" + }, + "beduerfnis": { + "name": "beduerfnis", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "notiz": { + "name": "notiz", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "order": { + "name": "order", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "idx_stakeholder_project": { + "name": "idx_stakeholder_project", + "columns": [ + { + "expression": "project_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "stakeholder_project_id_project_id_fk": { + "name": "stakeholder_project_id_project_id_fk", + "tableFrom": "stakeholder", + "tableTo": "project", + "columnsFrom": [ + "project_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.time_entry": { + "name": "time_entry", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "day_entry_id": { + "name": "day_entry_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "todo_id": { + "name": "todo_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "bezug_kind": { + "name": "bezug_kind", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "bezug_id": { + "name": "bezug_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "category": { + "name": "category", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'focus'" + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "started_at": { + "name": "started_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true + }, + "ended_at": { + "name": "ended_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + }, + "duration_seconds": { + "name": "duration_seconds", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "idx_time_entry_user_start": { + "name": "idx_time_entry_user_start", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "started_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_time_entry_user_active": { + "name": "idx_time_entry_user_active", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"time_entry\".\"ended_at\" IS NULL", + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_time_entry_todo": { + "name": "idx_time_entry_todo", + "columns": [ + { + "expression": "todo_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "time_entry_user_id_user_id_fk": { + "name": "time_entry_user_id_user_id_fk", + "tableFrom": "time_entry", + "tableTo": "user", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "time_entry_day_entry_id_day_entry_id_fk": { + "name": "time_entry_day_entry_id_day_entry_id_fk", + "tableFrom": "time_entry", + "tableTo": "day_entry", + "columnsFrom": [ + "day_entry_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + }, + "time_entry_todo_id_todo_id_fk": { + "name": "time_entry_todo_id_todo_id_fk", + "tableFrom": "time_entry", + "tableTo": "todo", + "columnsFrom": [ + "todo_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.todo": { + "name": "todo", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "day_entry_id": { + "name": "day_entry_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "date": { + "name": "date", + "type": "date", + "primaryKey": false, + "notNull": true + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "order": { + "name": "order", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "bezug_kind": { + "name": "bezug_kind", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "bezug_id": { + "name": "bezug_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'open'" + }, + "drop_reason": { + "name": "drop_reason", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "unplanned": { + "name": "unplanned", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "carried_over": { + "name": "carried_over", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "completed_at": { + "name": "completed_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + }, + "dropped_at": { + "name": "dropped_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "idx_todo_day_entry_id": { + "name": "idx_todo_day_entry_id", + "columns": [ + { + "expression": "day_entry_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_todo_user_date": { + "name": "idx_todo_user_date", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "date", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_todo_user_status_carry": { + "name": "idx_todo_user_status_carry", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "carried_over", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "todo_day_entry_id_day_entry_id_fk": { + "name": "todo_day_entry_id_day_entry_id_fk", + "tableFrom": "todo", + "tableTo": "day_entry", + "columnsFrom": [ + "day_entry_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "todo_user_id_user_id_fk": { + "name": "todo_user_id_user_id_fk", + "tableFrom": "todo", + "tableTo": "user", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.user": { + "name": "user", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "authentik_sub": { + "name": "authentik_sub", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "default_area_id": { + "name": "default_area_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "is_admin": { + "name": "is_admin", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "active": { + "name": "active", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "abwesend_bis": { + "name": "abwesend_bis", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "uniq_user_authentik_sub": { + "name": "uniq_user_authentik_sub", + "columns": [ + { + "expression": "authentik_sub", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "uniq_user_email": { + "name": "uniq_user_email", + "columns": [ + { + "expression": "email", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + } + }, + "enums": {}, + "schemas": {}, + "sequences": {}, + "roles": {}, + "policies": {}, + "views": {}, + "_meta": { + "columns": {}, + "schemas": {}, + "tables": {} + } +} \ No newline at end of file diff --git a/packages/db/migrations/meta/_journal.json b/packages/db/migrations/meta/_journal.json index c3faa53..5d0c8c2 100644 --- a/packages/db/migrations/meta/_journal.json +++ b/packages/db/migrations/meta/_journal.json @@ -99,6 +99,13 @@ "when": 1780763141548, "tag": "0013_parallel_timers", "breakpoints": true + }, + { + "idx": 14, + "version": "7", + "when": 1780764129593, + "tag": "0014_checkout_kimai", + "breakpoints": true } ] } \ No newline at end of file diff --git a/packages/db/src/schema.ts b/packages/db/src/schema.ts index 3519640..94fa506 100644 --- a/packages/db/src/schema.ts +++ b/packages/db/src/schema.ts @@ -219,6 +219,11 @@ export const dayEntry = pgTable( date: date('date').notNull(), // YYYY-MM-DD im Europe/Berlin status: text('status', { enum: ['begun', 'full', 'absent'] }).notNull(), checkedInAt: timestamp('checked_in_at', { withTimezone: true }), + // Arbeitsende (Check-Out) — markiert das Ende der Arbeits-Session des Tages. + checkedOutAt: timestamp('checked_out_at', { withTimezone: true }), + // Kimai-Sync: ID des bei Check-In gestarteten Timesheets + Sync-Status. + kimaiTimesheetId: integer('kimai_timesheet_id'), + kimaiSynced: boolean('kimai_synced').notNull().default(false), reflectedAt: timestamp('reflected_at', { withTimezone: true }), reflectionText: text('reflection_text'), ampel: text('ampel', { enum: ['green', 'amber', 'red'] }),