Initial commit: everythingbutwork MVP
ci / quality (push) Has been cancelled
ci / build (push) Has been cancelled

Internes Project-Management-Tool für ToolCTRL — ergänzend zu Plane (Tickets)
und Outline (Doku). Umfasst Puls-Übersicht, Tagesrhythmus (Lock-in + Reflexion),
Bereichs-Detail-Views (Entwicklung/Vertrieb/Marketing), Pflicht-Minimum-Check
und Blocker-Lifecycle gemäß Projektmanagement-Leitfaden v3.0.

Stack: pnpm-Monorepo · Vite + React 18 + Tailwind · Fastify + tRPC v11 +
Drizzle ORM · Postgres 16 · Authentik OIDC (Phase 2, Dev-Auto-Login aktiv).

Planungs-Artefakte unter _bmad-output/planning-artifacts/.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
dejanandClaude Opus 4.7 committed 2026-05-25 22:47:26 +02:00
commit 4f33509a0f
131 files changed
+34339

No files matched your search

+24
View File
@@ -0,0 +1,24 @@
{
"name": "@cockpit/shared",
"private": true,
"version": "0.0.0",
"type": "module",
"main": "./src/index.ts",
"types": "./src/index.ts",
"exports": {
".": "./src/index.ts",
"./schemas/*": "./src/schemas/*.ts"
},
"scripts": {
"typecheck": "tsc --noEmit",
"build": "tsc",
"test": "vitest run --passWithNoTests"
},
"dependencies": {
"zod": "^3.24.1"
},
"devDependencies": {
"typescript": "^5.7.2",
"vitest": "^2.1.8"
}
}
+8
View File
@@ -0,0 +1,8 @@
// Konstanten, die zwischen Frontend und Backend identisch genutzt werden.
export const MAX_TODO_TEXT_LENGTH = 200;
export const MAX_REFLECTION_TEXT_LENGTH = 1000;
export const WERKTAGE = ['MO', 'DI', 'MI', 'DO', 'FR'] as const;
export const JOURFIXE_DAY = 'DI' as const; // Di 11:00 als Default
export const JOURFIXE_HOUR = 11;
export const REFLEXION_REMINDER_HOUR = 17;
+7
View File
@@ -0,0 +1,7 @@
export * from './constants.js';
export * as DayEntrySchemas from './schemas/day-entry.js';
export * as ProjectSchemas from './schemas/project.js';
export * as DealSchemas from './schemas/deal.js';
export * as CampaignSchemas from './schemas/campaign.js';
export const SHARED_VERSION = '0.0.2';
+9
View File
@@ -0,0 +1,9 @@
import { z } from 'zod';
export const createCampaignInput = z.object({
name: z.string().min(1).max(200),
status: z.enum(['active', 'paused', 'done']).default('active'),
reach: z.number().int().min(0).default(0),
ownerUserId: z.string().uuid().optional(),
});
export type CreateCampaignInput = z.infer<typeof createCampaignInput>;
+59
View File
@@ -0,0 +1,59 @@
import { z } from 'zod';
export const ampelSchema = z.enum(['green', 'amber', 'red']);
export const trendSchema = z.enum(['besser', 'gleich', 'schlechter']);
export const bezugKindSchema = z.enum(['project', 'deal', 'campaign', 'allgemein']);
export const todoStatusSchema = z.enum(['open', 'done', 'dropped']);
export const todoInputSchema = z.object({
title: z.string().min(1).max(200),
bezugKind: bezugKindSchema.optional(),
bezugId: z.string().uuid().optional(),
});
export type TodoInput = z.infer<typeof todoInputSchema>;
export const checkInInput = z.object({
todos: z.array(todoInputSchema).min(1),
date: z
.string()
.regex(/^\d{4}-\d{2}-\d{2}$/)
.optional(), // Default: heute
});
export type CheckInInput = z.infer<typeof checkInInput>;
export const submitReflectionInput = z.object({
dayEntryId: z.string().uuid(),
todos: z
.array(
z.object({
id: z.string().uuid(),
status: todoStatusSchema,
dropReason: z.string().max(200).optional(),
}),
)
.default([]),
reflectionText: z.string().max(1000).default(''),
ampel: ampelSchema,
trend: trendSchema.nullable().optional(),
blocker: z
.object({
title: z.string().min(1).max(200),
description: z.string().max(1000).optional(),
})
.optional(),
url: z.string().url().optional(),
});
export type SubmitReflectionInput = z.infer<typeof submitReflectionInput>;
export const todoMutationInput = z.object({
dayEntryId: z.string().uuid(),
todos: z.array(todoInputSchema).min(0),
});
export type TodoMutationInput = z.infer<typeof todoMutationInput>;
export const markAbsentInput = z.object({
from: z.string().regex(/^\d{4}-\d{2}-\d{2}$/),
to: z.string().regex(/^\d{4}-\d{2}-\d{2}$/),
reason: z.enum(['urlaub', 'krank', 'sonstiges']),
});
export type MarkAbsentInput = z.infer<typeof markAbsentInput>;
+19
View File
@@ -0,0 +1,19 @@
import { z } from 'zod';
export const dealStageSchema = z.enum(['lead', 'erstgespraech', 'demo', 'angebot', 'abschluss']);
export const DEAL_STAGES = dealStageSchema.options;
export const createDealInput = z.object({
name: z.string().min(1).max(200),
ownerUserId: z.string().uuid().optional(),
valueEur: z.number().int().min(0),
probability: z.number().int().min(0).max(100).default(50),
stage: dealStageSchema.default('lead'),
});
export type CreateDealInput = z.infer<typeof createDealInput>;
export const updateDealStageInput = z.object({
dealId: z.string().uuid(),
stage: dealStageSchema,
});
export type UpdateDealStageInput = z.infer<typeof updateDealStageInput>;
+45
View File
@@ -0,0 +1,45 @@
import { z } from 'zod';
export const createProjectInput = z.object({
areaId: z.string().uuid(),
name: z.string().min(1).max(200),
kind: z.enum(['kundenprojekt', 'internes_projekt']),
verantwortlicheUserId: z.string().uuid().optional(),
arbeitsmodus: z.enum(['cycle', 'kanban']).optional(),
outlineSteckbriefUrl: z.string().url(),
planeProjectUrl: z.string().url(),
risikolisteUrl: z.string().url().optional(),
dodText: z.string().max(2000).optional(),
start: z
.string()
.regex(/^\d{4}-\d{2}-\d{2}$/)
.optional(),
deadline: z
.string()
.regex(/^\d{4}-\d{2}-\d{2}$/)
.optional(),
milestones: z
.array(
z.object({
title: z.string().min(1).max(200),
due: z
.string()
.regex(/^\d{4}-\d{2}-\d{2}$/)
.optional(),
}),
)
.default([]),
});
export type CreateProjectInput = z.infer<typeof createProjectInput>;
export const archiveProjectInput = z.object({
projectId: z.string().uuid(),
lessonsLearnedUrl: z.string().url(),
});
export type ArchiveProjectInput = z.infer<typeof archiveProjectInput>;
export const setMilestoneStatusInput = z.object({
milestoneId: z.string().uuid(),
status: z.enum(['open', 'done', 'overdue']),
});
export type SetMilestoneStatusInput = z.infer<typeof setMilestoneStatusInput>;
+10
View File
@@ -0,0 +1,10 @@
{
"extends": "../../tsconfig.base.json",
"compilerOptions": {
"outDir": "./dist",
"rootDir": "./src",
"declaration": true,
"noEmit": true
},
"include": ["src"]
}