refactor: migrate to monorepo structure with Docker, PocketBase, and e2e tests

- Reorganize into apps/, packages/, docs/, e2e/, pocketbase/ directories
- Add Dockerfiles for web, worker, and PocketBase services
- Add docker-compose.yml for local orchestration
- Add turbo.json for monorepo task management
- Add Playwright e2e test infrastructure
- Add PocketBase backend with migrations
- Remove Vite/Next.js/ESLint/PostCSS config files
- Update package.json with workspace dependencies
- Add .env.example and .dockerignore
This commit is contained in:
2026-07-16 06:19:58 -04:00
parent ec14645a4b
commit 8f55626e03
286 changed files with 31992 additions and 9245 deletions
+21
View File
@@ -0,0 +1,21 @@
{
"name": "@project-e/shared",
"version": "0.1.0",
"private": true,
"main": "./src/index.ts",
"types": "./src/index.ts",
"exports": {
".": "./src/index.ts",
"./*": "./src/*.ts"
},
"scripts": {
"typecheck": "tsc --noEmit",
"lint": "echo 'no lint configured'"
},
"dependencies": {
"zod": "^3.25.0"
},
"devDependencies": {
"typescript": "^5.9.3"
}
}
+68
View File
@@ -0,0 +1,68 @@
// ── Task ─────────────────────────────────────────────────────────────────────
export const TASK_STATUS = ['todo', 'in_progress', 'done', 'cancelled'] as const;
export const TASK_PRIORITY = ['low', 'medium', 'high', 'urgent'] as const;
// ── Habit ────────────────────────────────────────────────────────────────────
export const HABIT_FREQUENCY = ['daily', 'weekly', 'custom'] as const;
export const HABIT_DIFFICULTY = ['easy', 'medium', 'hard'] as const;
export const HABIT_COMPLETION_MODE = ['quick', 'detailed'] as const;
// ── Project ──────────────────────────────────────────────────────────────────
export const PROJECT_STATUS = ['active', 'paused', 'archived'] as const;
// ── Milestone ────────────────────────────────────────────────────────────────
export const MILESTONE_STATUS = ['planned', 'in_progress', 'complete'] as const;
// ── Report ───────────────────────────────────────────────────────────────────
export const REPORT_TYPE = ['weekly', 'monthly', 'project', 'habit', 'custom'] as const;
// ── Canvas ───────────────────────────────────────────────────────────────────
export const CANVAS_MODE = ['freeform', 'graph'] as const;
export const CANVAS_CARD_TYPE = ['note', 'task', 'image', 'entity'] as const;
// ── Agent ────────────────────────────────────────────────────────────────────
export const AGENT_PERMISSION_TIER = [
'full_access',
'read_only',
'content_creator',
'task_manager',
'custom',
] as const;
export const AGENT_STATUS = ['active', 'disabled'] as const;
// ── System ───────────────────────────────────────────────────────────────────
export const NOTIFICATION_TYPE = ['info', 'success', 'warning', 'error'] as const;
export const QUEUE_JOB_STATUS = ['pending', 'in_progress', 'completed', 'failed'] as const;
export const TIME_ENTRY_SOURCE = ['manual', 'timer', 'pomodoro'] as const;
// ── Defaults ─────────────────────────────────────────────────────────────────
export const DEFAULTS = {
TASK_PRIORITY: 'medium',
TASK_STATUS: 'todo',
HABIT_FREQUENCY: 'daily',
HABIT_DIFFICULTY: 'medium',
HABIT_COMPLETION_MODE: 'quick',
PROJECT_STATUS: 'active',
MILESTONE_STATUS: 'planned',
POMODORO_FOCUS_MINUTES: 25,
POMODORO_BREAK_MINUTES: 5,
MAX_FILE_SIZE: 5 * 1024 * 1024, // 5MB
MAX_RETRIES: 3,
} as const;
// ── Default Domains ──────────────────────────────────────────────────────────
export const DEFAULT_DOMAINS = [
{ name: 'personal', color: '#299667', icon: '🏠', sort_order: 0 },
{ name: 'work', color: '#356bff', icon: '💼', sort_order: 1 },
{ name: 'ots', color: '#ea7658', icon: '🛒', sort_order: 2 },
] as const;
+17
View File
@@ -0,0 +1,17 @@
// Schemas
export * from './schemas/common';
export * from './schemas/task';
export * from './schemas/habit';
export * from './schemas/project';
export * from './schemas/milestone';
export * from './schemas/note';
export * from './schemas/report';
export * from './schemas/canvas';
export * from './schemas/agent';
export * from './schemas/webhook';
// Types
export * from './types';
// Constants
export * from './constants';
+96
View File
@@ -0,0 +1,96 @@
import { z } from 'zod';
// ── Enums ────────────────────────────────────────────────────────────────────
export const agentPermissionTierEnum = z.enum([
'full_access',
'read_only',
'content_creator',
'task_manager',
'custom',
]);
export const agentStatusEnum = z.enum(['active', 'disabled']);
// ── Sub-schemas ──────────────────────────────────────────────────────────────
export const agentActivitySchema = z.object({
id: z.string(),
agent_id: z.string(),
action: z.string(),
entity_type: z.string().optional(),
entity_id: z.string().optional(),
details: z.record(z.unknown()).optional(),
success: z.boolean().default(true),
error_message: z.string().optional(),
created: z.string().datetime(),
updated: z.string().datetime(),
});
export const createAgentActivitySchema = agentActivitySchema.omit({
id: true,
created: true,
updated: true,
});
export const agentTaskSchema = z.object({
id: z.string(),
agent_id: z.string(),
task_type: z.string(),
input: z.record(z.unknown()),
status: z.enum(['pending', 'running', 'completed', 'failed']).default('pending'),
output: z.record(z.unknown()).optional(),
error_message: z.string().optional(),
started_at: z.string().datetime().optional(),
completed_at: z.string().datetime().optional(),
created: z.string().datetime(),
updated: z.string().datetime(),
});
export const createAgentTaskSchema = agentTaskSchema.omit({
id: true,
status: true,
output: true,
error_message: true,
started_at: true,
completed_at: true,
created: true,
updated: true,
});
// ── Agent Schema ─────────────────────────────────────────────────────────────
export const agentSchema = z.object({
id: z.string(),
name: z.string().min(1, 'Agent name is required'),
description: z.string().optional(),
status: agentStatusEnum.default('active'),
permission_tier: agentPermissionTierEnum.default('read_only'),
custom_permissions: z.array(z.string()).optional(),
api_key: z.string().optional(),
last_active_at: z.string().datetime().optional(),
domain: z.string(),
tags: z.array(z.string()).default([]),
config: z.record(z.unknown()).optional(),
custom_fields: z.record(z.unknown()).optional(),
created: z.string().datetime(),
updated: z.string().datetime(),
});
export const createAgentSchema = agentSchema.omit({
id: true,
last_active_at: true,
created: true,
updated: true,
});
export const updateAgentSchema = createAgentSchema.partial();
// ── Types ────────────────────────────────────────────────────────────────────
export type Agent = z.infer<typeof agentSchema>;
export type CreateAgent = z.infer<typeof createAgentSchema>;
export type UpdateAgent = z.infer<typeof updateAgentSchema>;
export type AgentActivity = z.infer<typeof agentActivitySchema>;
export type CreateAgentActivity = z.infer<typeof createAgentActivitySchema>;
export type AgentTask = z.infer<typeof agentTaskSchema>;
export type CreateAgentTask = z.infer<typeof createAgentTaskSchema>;
+81
View File
@@ -0,0 +1,81 @@
import { z } from 'zod';
// ── Enums ────────────────────────────────────────────────────────────────────
export const canvasModeEnum = z.enum(['freeform', 'graph']);
export const canvasCardTypeEnum = z.enum(['note', 'task', 'image', 'entity']);
// ── Sub-schemas ──────────────────────────────────────────────────────────────
export const canvasCardSchema = z.object({
id: z.string(),
canvas_id: z.string(),
type: canvasCardTypeEnum,
entity_id: z.string().optional(),
title: z.string().optional(),
content: z.string().optional(),
x: z.number().default(0),
y: z.number().default(0),
width: z.number().positive().default(200),
height: z.number().positive().default(150),
rotation: z.number().default(0),
color: z.string().optional(),
z_index: z.number().int().default(0),
created: z.string().datetime(),
updated: z.string().datetime(),
});
export const createCanvasCardSchema = canvasCardSchema.omit({
id: true,
created: true,
updated: true,
});
export const updateCanvasCardSchema = createCanvasCardSchema.partial();
// ── Canvas Schema ────────────────────────────────────────────────────────────
export const canvasSchema = z.object({
id: z.string(),
name: z.string().min(1, 'Canvas name is required'),
description: z.string().optional(),
mode: canvasModeEnum.default('freeform'),
domain: z.string(),
tags: z.array(z.string()).default([]),
cards: z.array(canvasCardSchema).default([]),
connections: z.array(z.object({
id: z.string(),
source_card_id: z.string(),
target_card_id: z.string(),
label: z.string().optional(),
style: z.enum(['solid', 'dashed', 'dotted']).default('solid'),
})).default([]),
viewport: z.object({
x: z.number().default(0),
y: z.number().default(0),
zoom: z.number().positive().default(1),
}).optional(),
background: z.string().optional(),
custom_fields: z.record(z.unknown()).optional(),
created: z.string().datetime(),
updated: z.string().datetime(),
});
export const createCanvasSchema = canvasSchema.omit({
id: true,
cards: true,
connections: true,
created: true,
updated: true,
});
export const updateCanvasSchema = createCanvasSchema.partial();
// ── Types ────────────────────────────────────────────────────────────────────
export type Canvas = z.infer<typeof canvasSchema>;
export type CreateCanvas = z.infer<typeof createCanvasSchema>;
export type UpdateCanvas = z.infer<typeof updateCanvasSchema>;
export type CanvasCard = z.infer<typeof canvasCardSchema>;
export type CreateCanvasCard = z.infer<typeof createCanvasCardSchema>;
export type UpdateCanvasCard = z.infer<typeof updateCanvasCardSchema>;
+162
View File
@@ -0,0 +1,162 @@
import { z } from 'zod';
// ── Tag ──────────────────────────────────────────────────────────────────────
export const tagSchema = z.object({
id: z.string(),
name: z.string().min(1, 'Tag name is required'),
color: z.string().optional(),
created: z.string().datetime(),
updated: z.string().datetime(),
});
export const createTagSchema = tagSchema.omit({
id: true,
created: true,
updated: true,
});
export const updateTagSchema = createTagSchema.partial();
export type Tag = z.infer<typeof tagSchema>;
export type CreateTag = z.infer<typeof createTagSchema>;
export type UpdateTag = z.infer<typeof updateTagSchema>;
// ── Domain ───────────────────────────────────────────────────────────────────
export const domainSchema = z.object({
id: z.string(),
name: z.string().min(1, 'Domain name is required'),
color: z.string().optional(),
icon: z.string().optional(),
sort_order: z.number().int().nonnegative().default(0),
created: z.string().datetime(),
updated: z.string().datetime(),
});
export const createDomainSchema = domainSchema.omit({
id: true,
created: true,
updated: true,
});
export const updateDomainSchema = createDomainSchema.partial();
export type Domain = z.infer<typeof domainSchema>;
export type CreateDomain = z.infer<typeof createDomainSchema>;
export type UpdateDomain = z.infer<typeof updateDomainSchema>;
// ── Time Entry ───────────────────────────────────────────────────────────────
export const timeEntrySourceEnum = z.enum(['manual', 'timer', 'pomodoro']);
export const timeEntrySchema = z.object({
id: z.string(),
entity_type: z.string(),
entity_id: z.string(),
source: timeEntrySourceEnum,
duration_minutes: z.number().int().positive(),
started_at: z.string().datetime(),
ended_at: z.string().datetime().optional(),
notes: z.string().optional(),
created: z.string().datetime(),
updated: z.string().datetime(),
});
export const createTimeEntrySchema = timeEntrySchema.omit({
id: true,
created: true,
updated: true,
});
export const updateTimeEntrySchema = createTimeEntrySchema.partial();
export type TimeEntry = z.infer<typeof timeEntrySchema>;
export type CreateTimeEntry = z.infer<typeof createTimeEntrySchema>;
export type UpdateTimeEntry = z.infer<typeof updateTimeEntrySchema>;
// ── Notification ─────────────────────────────────────────────────────────────
export const notificationTypeEnum = z.enum(['info', 'success', 'warning', 'error']);
export const notificationSchema = z.object({
id: z.string(),
type: notificationTypeEnum,
title: z.string().min(1),
message: z.string(),
read: z.boolean().default(false),
entity_type: z.string().optional(),
entity_id: z.string().optional(),
action_url: z.string().url().optional(),
created: z.string().datetime(),
updated: z.string().datetime(),
});
export const createNotificationSchema = notificationSchema.omit({
id: true,
read: true,
created: true,
updated: true,
});
export type Notification = z.infer<typeof notificationSchema>;
export type CreateNotification = z.infer<typeof createNotificationSchema>;
// ── Error Log ────────────────────────────────────────────────────────────────
export const errorLogSchema = z.object({
id: z.string(),
level: z.enum(['warn', 'error', 'critical']),
source: z.string(),
message: z.string(),
stack_trace: z.string().optional(),
metadata: z.record(z.unknown()).optional(),
resolved: z.boolean().default(false),
created: z.string().datetime(),
updated: z.string().datetime(),
});
export const createErrorLogSchema = errorLogSchema.omit({
id: true,
resolved: true,
created: true,
updated: true,
});
export type ErrorLog = z.infer<typeof errorLogSchema>;
export type CreateErrorLog = z.infer<typeof createErrorLogSchema>;
// ── Queue Job ────────────────────────────────────────────────────────────────
export const queueJobStatusEnum = z.enum(['pending', 'in_progress', 'completed', 'failed']);
export const queueJobSchema = z.object({
id: z.string(),
queue: z.string(),
type: z.string(),
payload: z.record(z.unknown()),
status: queueJobStatusEnum.default('pending'),
attempts: z.number().int().nonnegative().default(0),
max_attempts: z.number().int().positive().default(3),
result: z.record(z.unknown()).optional(),
error_message: z.string().optional(),
scheduled_at: z.string().datetime().optional(),
started_at: z.string().datetime().optional(),
completed_at: z.string().datetime().optional(),
created: z.string().datetime(),
updated: z.string().datetime(),
});
export const createQueueJobSchema = queueJobSchema.omit({
id: true,
attempts: true,
result: true,
error_message: true,
started_at: true,
completed_at: true,
created: true,
updated: true,
});
export type QueueJob = z.infer<typeof queueJobSchema>;
export type CreateQueueJob = z.infer<typeof createQueueJobSchema>;
+90
View File
@@ -0,0 +1,90 @@
import { z } from 'zod';
// ── Enums ────────────────────────────────────────────────────────────────────
export const habitFrequencyEnum = z.enum(['daily', 'weekly', 'custom']);
export const habitDifficultyEnum = z.enum(['easy', 'medium', 'hard']);
export const habitCompletionModeEnum = z.enum(['quick', 'detailed']);
// ── Sub-schemas ──────────────────────────────────────────────────────────────
export const habitScoreConfigSchema = z.object({
streak_weight: z.number().min(0).max(1).default(0.5),
difficulty_weight: z.number().min(0).max(1).default(0.3),
consistency_weight: z.number().min(0).max(1).default(0.2),
});
export const habitLogSchema = z.object({
id: z.string(),
habit_id: z.string(),
completed: z.boolean(),
notes: z.string().optional(),
value: z.number().optional(),
mood: z.number().int().min(1).max(5).optional(),
skipped: z.boolean().default(false),
logged_at: z.string().datetime(),
created: z.string().datetime(),
updated: z.string().datetime(),
});
export const createHabitLogSchema = habitLogSchema.omit({
id: true,
created: true,
updated: true,
});
export const habitSkipDaySchema = z.object({
habit_id: z.string(),
date: z.string().datetime(),
reason: z.string().optional(),
});
// ── Habit Schema ─────────────────────────────────────────────────────────────
export const habitSchema = z.object({
id: z.string(),
name: z.string().min(1, 'Habit name is required'),
description: z.string().optional(),
domain: z.string(),
frequency: habitFrequencyEnum.default('daily'),
custom_days: z.array(z.number().int().min(0).max(6)).optional(),
difficulty: habitDifficultyEnum.default('medium'),
completion_mode: habitCompletionModeEnum.default('quick'),
goal_per_period: z.number().int().positive().default(1),
icon: z.string().optional(),
color: z.string().optional(),
start_date: z.string().datetime().optional(),
end_date: z.string().datetime().optional(),
current_streak: z.number().int().nonnegative().default(0),
best_streak: z.number().int().nonnegative().default(0),
total_completions: z.number().int().nonnegative().default(0),
score: z.number().default(0),
score_config: habitScoreConfigSchema.optional(),
active: z.boolean().default(true),
tags: z.array(z.string()).default([]),
custom_fields: z.record(z.unknown()).optional(),
created: z.string().datetime(),
updated: z.string().datetime(),
});
export const createHabitSchema = habitSchema.omit({
id: true,
current_streak: true,
best_streak: true,
total_completions: true,
score: true,
created: true,
updated: true,
});
export const updateHabitSchema = createHabitSchema.partial();
// ── Types ────────────────────────────────────────────────────────────────────
export type Habit = z.infer<typeof habitSchema>;
export type CreateHabit = z.infer<typeof createHabitSchema>;
export type UpdateHabit = z.infer<typeof updateHabitSchema>;
export type HabitLog = z.infer<typeof habitLogSchema>;
export type CreateHabitLog = z.infer<typeof createHabitLogSchema>;
export type HabitSkipDay = z.infer<typeof habitSkipDaySchema>;
export type HabitScoreConfig = z.infer<typeof habitScoreConfigSchema>;
+97
View File
@@ -0,0 +1,97 @@
import { z } from 'zod';
// ── Enums ────────────────────────────────────────────────────────────────────
export const milestoneStatusEnum = z.enum(['planned', 'in_progress', 'complete']);
// ── Sub-schemas ──────────────────────────────────────────────────────────────
export const milestoneDependencySchema = z.object({
id: z.string(),
milestone_id: z.string(),
depends_on_id: z.string(),
type: z.enum(['finish_to_start', 'start_to_start', 'finish_to_finish', 'start_to_finish']).default('finish_to_start'),
lag_days: z.number().int().default(0),
created: z.string().datetime(),
updated: z.string().datetime(),
});
export const createMilestoneDependencySchema = milestoneDependencySchema.omit({
id: true,
created: true,
updated: true,
});
export const milestoneTemplateSchema = z.object({
id: z.string(),
name: z.string().min(1, 'Template name is required'),
description: z.string().optional(),
domain: z.string(),
default_duration_days: z.number().int().positive().default(14),
tasks: z.array(z.object({
title: z.string(),
description: z.string().optional(),
estimate: z.number().int().positive().optional(),
sort_order: z.number().int().nonnegative().default(0),
})).default([]),
created: z.string().datetime(),
updated: z.string().datetime(),
});
export const createMilestoneTemplateSchema = milestoneTemplateSchema.omit({
id: true,
created: true,
updated: true,
});
export const milestoneHistorySchema = z.object({
id: z.string(),
milestone_id: z.string(),
field: z.string(),
old_value: z.string().optional(),
new_value: z.string().optional(),
changed_by: z.string().optional(),
created: z.string().datetime(),
updated: z.string().datetime(),
});
// ── Milestone Schema ─────────────────────────────────────────────────────────
export const milestoneSchema = z.object({
id: z.string(),
name: z.string().min(1, 'Milestone name is required'),
description: z.string().optional(),
status: milestoneStatusEnum.default('planned'),
project_id: z.string(),
domain: z.string(),
tags: z.array(z.string()).default([]),
sort_order: z.number().int().nonnegative().default(0),
target_date: z.string().datetime().optional(),
completed_at: z.string().datetime().optional(),
tasks: z.array(z.string()).default([]),
dependencies: z.array(milestoneDependencySchema).default([]),
custom_fields: z.record(z.unknown()).optional(),
created: z.string().datetime(),
updated: z.string().datetime(),
});
export const createMilestoneSchema = milestoneSchema.omit({
id: true,
completed_at: true,
dependencies: true,
created: true,
updated: true,
});
export const updateMilestoneSchema = createMilestoneSchema.partial();
// ── Types ────────────────────────────────────────────────────────────────────
export type Milestone = z.infer<typeof milestoneSchema>;
export type CreateMilestone = z.infer<typeof createMilestoneSchema>;
export type UpdateMilestone = z.infer<typeof updateMilestoneSchema>;
export type MilestoneDependency = z.infer<typeof milestoneDependencySchema>;
export type CreateMilestoneDependency = z.infer<typeof createMilestoneDependencySchema>;
export type MilestoneTemplate = z.infer<typeof milestoneTemplateSchema>;
export type CreateMilestoneTemplate = z.infer<typeof createMilestoneTemplateSchema>;
export type MilestoneHistory = z.infer<typeof milestoneHistorySchema>;
+80
View File
@@ -0,0 +1,80 @@
import { z } from 'zod';
// ── Sub-schemas ──────────────────────────────────────────────────────────────
export const noteLinkSchema = z.object({
id: z.string(),
source_note_id: z.string(),
target_note_id: z.string(),
label: z.string().optional(),
created: z.string().datetime(),
updated: z.string().datetime(),
});
export const createNoteLinkSchema = noteLinkSchema.omit({
id: true,
created: true,
updated: true,
});
export const noteTaskLinkSchema = z.object({
id: z.string(),
note_id: z.string(),
task_id: z.string(),
label: z.string().optional(),
created: z.string().datetime(),
updated: z.string().datetime(),
});
export const createNoteTaskLinkSchema = noteTaskLinkSchema.omit({
id: true,
created: true,
updated: true,
});
// ── Note Schema ──────────────────────────────────────────────────────────────
export const noteSchema = z.object({
id: z.string(),
title: z.string().min(1, 'Note title is required'),
content: z.string().optional(),
domain: z.string(),
tags: z.array(z.string()).default([]),
project_id: z.string().optional(),
is_pinned: z.boolean().default(false),
is_archived: z.boolean().default(false),
word_count: z.number().int().nonnegative().default(0),
links: z.array(noteLinkSchema).default([]),
task_links: z.array(noteTaskLinkSchema).default([]),
attachments: z.array(z.object({
id: z.string(),
filename: z.string(),
mime_type: z.string(),
size: z.number(),
url: z.string(),
})).default([]),
custom_fields: z.record(z.unknown()).optional(),
created: z.string().datetime(),
updated: z.string().datetime(),
});
export const createNoteSchema = noteSchema.omit({
id: true,
word_count: true,
links: true,
task_links: true,
created: true,
updated: true,
});
export const updateNoteSchema = createNoteSchema.partial();
// ── Types ────────────────────────────────────────────────────────────────────
export type Note = z.infer<typeof noteSchema>;
export type CreateNote = z.infer<typeof createNoteSchema>;
export type UpdateNote = z.infer<typeof updateNoteSchema>;
export type NoteLink = z.infer<typeof noteLinkSchema>;
export type CreateNoteLink = z.infer<typeof createNoteLinkSchema>;
export type NoteTaskLink = z.infer<typeof noteTaskLinkSchema>;
export type CreateNoteTaskLink = z.infer<typeof createNoteTaskLinkSchema>;
+55
View File
@@ -0,0 +1,55 @@
import { z } from 'zod';
// ── Enums ────────────────────────────────────────────────────────────────────
export const projectStatusEnum = z.enum(['active', 'paused', 'archived']);
// ── Sub-schemas ──────────────────────────────────────────────────────────────
export const projectSettingsSchema = z.object({
default_domain: z.string().optional(),
default_priority: z.enum(['low', 'medium', 'high', 'urgent']).optional(),
auto_archive_days: z.number().int().nonnegative().optional(),
pomodoro_enabled: z.boolean().default(false),
pomodoro_focus_minutes: z.number().int().positive().default(25),
pomodoro_break_minutes: z.number().int().positive().default(5),
notifications_enabled: z.boolean().default(true),
custom_fields: z.record(z.unknown()).optional(),
});
// ── Project Schema ───────────────────────────────────────────────────────────
export const projectSchema = z.object({
id: z.string(),
name: z.string().min(1, 'Project name is required'),
description: z.string().optional(),
status: projectStatusEnum.default('active'),
domain: z.string(),
color: z.string().optional(),
icon: z.string().optional(),
tags: z.array(z.string()).default([]),
owner: z.string().optional(),
start_date: z.string().datetime().optional(),
target_date: z.string().datetime().optional(),
completed_at: z.string().datetime().optional(),
settings: projectSettingsSchema.optional(),
custom_fields: z.record(z.unknown()).optional(),
created: z.string().datetime(),
updated: z.string().datetime(),
});
export const createProjectSchema = projectSchema.omit({
id: true,
completed_at: true,
created: true,
updated: true,
});
export const updateProjectSchema = createProjectSchema.partial();
// ── Types ────────────────────────────────────────────────────────────────────
export type Project = z.infer<typeof projectSchema>;
export type CreateProject = z.infer<typeof createProjectSchema>;
export type UpdateProject = z.infer<typeof updateProjectSchema>;
export type ProjectSettings = z.infer<typeof projectSettingsSchema>;
+72
View File
@@ -0,0 +1,72 @@
import { z } from 'zod';
// ── Enums ────────────────────────────────────────────────────────────────────
export const reportTypeEnum = z.enum(['weekly', 'monthly', 'project', 'habit', 'custom']);
// ── Sub-schemas ──────────────────────────────────────────────────────────────
export const reportTemplateSchema = z.object({
id: z.string(),
name: z.string().min(1, 'Template name is required'),
description: z.string().optional(),
type: reportTypeEnum,
sections: z.array(z.object({
title: z.string(),
type: z.enum(['summary', 'chart', 'table', 'list', 'text']).default('text'),
config: z.record(z.unknown()).optional(),
sort_order: z.number().int().nonnegative().default(0),
})).default([]),
created: z.string().datetime(),
updated: z.string().datetime(),
});
export const createReportTemplateSchema = reportTemplateSchema.omit({
id: true,
created: true,
updated: true,
});
// ── Report Schema ────────────────────────────────────────────────────────────
export const reportSchema = z.object({
id: z.string(),
title: z.string().min(1, 'Report title is required'),
type: reportTypeEnum,
template_id: z.string().optional(),
domain: z.string(),
date_range: z.object({
start: z.string().datetime(),
end: z.string().datetime(),
}),
sections: z.array(z.object({
title: z.string(),
content: z.string().optional(),
data: z.record(z.unknown()).optional(),
sort_order: z.number().int().nonnegative().default(0),
})).default([]),
summary: z.string().optional(),
is_draft: z.boolean().default(true),
generated_at: z.string().datetime().optional(),
tags: z.array(z.string()).default([]),
custom_fields: z.record(z.unknown()).optional(),
created: z.string().datetime(),
updated: z.string().datetime(),
});
export const createReportSchema = reportSchema.omit({
id: true,
generated_at: true,
created: true,
updated: true,
});
export const updateReportSchema = createReportSchema.partial();
// ── Types ────────────────────────────────────────────────────────────────────
export type Report = z.infer<typeof reportSchema>;
export type CreateReport = z.infer<typeof createReportSchema>;
export type UpdateReport = z.infer<typeof updateReportSchema>;
export type ReportTemplate = z.infer<typeof reportTemplateSchema>;
export type CreateReportTemplate = z.infer<typeof createReportTemplateSchema>;
+71
View File
@@ -0,0 +1,71 @@
import { z } from 'zod';
// ── Enums ────────────────────────────────────────────────────────────────────
export const taskStatusEnum = z.enum(['todo', 'in_progress', 'done', 'cancelled']);
export const taskPriorityEnum = z.enum(['low', 'medium', 'high', 'urgent']);
// ── Sub-schemas ──────────────────────────────────────────────────────────────
export const recurringConfigSchema = z.object({
rule: z.string().min(1, 'Recurrence rule is required'),
next_due: z.string().datetime().optional(),
});
export const attachmentSchema = z.object({
id: z.string(),
filename: z.string(),
mime_type: z.string(),
size: z.number().int().nonnegative(),
url: z.string(),
});
export const subtaskSchema = z.object({
id: z.string(),
title: z.string().min(1, 'Subtask title is required'),
done: z.boolean().default(false),
sort_order: z.number().int().nonnegative().default(0),
});
// ── Task Schema ──────────────────────────────────────────────────────────────
export const taskSchema = z.object({
id: z.string(),
title: z.string().min(1, 'Title is required'),
description: z.string().optional(),
status: taskStatusEnum.default('todo'),
priority: taskPriorityEnum.default('medium'),
due_date: z.string().datetime().optional(),
project_id: z.string().optional(),
milestone_id: z.string().optional(),
tags: z.array(z.string()).default([]),
domain: z.string(),
assignee: z.string().optional(),
estimate: z.number().int().positive().optional(),
time_spent: z.number().int().nonnegative().default(0),
recurring_config: recurringConfigSchema.optional(),
attachments: z.array(attachmentSchema).default([]),
dependencies: z.array(z.string()).default([]),
subtasks: z.array(subtaskSchema).default([]),
custom_fields: z.record(z.unknown()).optional(),
completed_at: z.string().datetime().optional(),
created: z.string().datetime(),
updated: z.string().datetime(),
});
export const createTaskSchema = taskSchema.omit({
id: true,
created: true,
updated: true,
});
export const updateTaskSchema = createTaskSchema.partial();
// ── Types ────────────────────────────────────────────────────────────────────
export type Task = z.infer<typeof taskSchema>;
export type CreateTask = z.infer<typeof createTaskSchema>;
export type UpdateTask = z.infer<typeof updateTaskSchema>;
export type RecurringConfig = z.infer<typeof recurringConfigSchema>;
export type Attachment = z.infer<typeof attachmentSchema>;
export type Subtask = z.infer<typeof subtaskSchema>;
+52
View File
@@ -0,0 +1,52 @@
import { z } from 'zod';
// ── Sub-schemas ──────────────────────────────────────────────────────────────
export const webhookDeliverySchema = z.object({
id: z.string(),
webhook_id: z.string(),
event: z.string(),
payload: z.record(z.unknown()),
status: z.enum(['success', 'failed', 'pending']).default('pending'),
status_code: z.number().int().optional(),
response_body: z.string().optional(),
error_message: z.string().optional(),
attempts: z.number().int().nonnegative().default(0),
delivered_at: z.string().datetime().optional(),
created: z.string().datetime(),
updated: z.string().datetime(),
});
// ── Webhook Schema ───────────────────────────────────────────────────────────
export const webhookSchema = z.object({
id: z.string(),
name: z.string().min(1, 'Webhook name is required'),
url: z.string().url('Invalid webhook URL'),
events: z.array(z.string()).min(1, 'At least one event is required'),
secret: z.string().optional(),
active: z.boolean().default(true),
domain: z.string(),
headers: z.record(z.string()).optional(),
retry_count: z.number().int().nonnegative().default(3),
last_triggered_at: z.string().datetime().optional(),
custom_fields: z.record(z.unknown()).optional(),
created: z.string().datetime(),
updated: z.string().datetime(),
});
export const createWebhookSchema = webhookSchema.omit({
id: true,
last_triggered_at: true,
created: true,
updated: true,
});
export const updateWebhookSchema = createWebhookSchema.partial();
// ── Types ────────────────────────────────────────────────────────────────────
export type Webhook = z.infer<typeof webhookSchema>;
export type CreateWebhook = z.infer<typeof createWebhookSchema>;
export type UpdateWebhook = z.infer<typeof updateWebhookSchema>;
export type WebhookDelivery = z.infer<typeof webhookDeliverySchema>;
View File
+67
View File
@@ -0,0 +1,67 @@
// ── Common ───────────────────────────────────────────────────────────────────
export type { Tag, CreateTag, UpdateTag } from '../schemas/common';
export type { Domain, CreateDomain, UpdateDomain } from '../schemas/common';
export type { TimeEntry, CreateTimeEntry, UpdateTimeEntry } from '../schemas/common';
export type { Notification, CreateNotification } from '../schemas/common';
export type { ErrorLog, CreateErrorLog } from '../schemas/common';
export type { QueueJob, CreateQueueJob } from '../schemas/common';
// ── Task ─────────────────────────────────────────────────────────────────────
export type { Task, CreateTask, UpdateTask } from '../schemas/task';
export type { RecurringConfig, Attachment, Subtask } from '../schemas/task';
// ── Habit ────────────────────────────────────────────────────────────────────
export type { Habit, CreateHabit, UpdateHabit } from '../schemas/habit';
export type { HabitLog, CreateHabitLog, HabitSkipDay, HabitScoreConfig } from '../schemas/habit';
// ── Project ──────────────────────────────────────────────────────────────────
export type { Project, CreateProject, UpdateProject, ProjectSettings } from '../schemas/project';
// ── Milestone ────────────────────────────────────────────────────────────────
export type { Milestone, CreateMilestone, UpdateMilestone } from '../schemas/milestone';
export type {
MilestoneDependency,
CreateMilestoneDependency,
MilestoneTemplate,
CreateMilestoneTemplate,
MilestoneHistory,
} from '../schemas/milestone';
// ── Note ─────────────────────────────────────────────────────────────────────
export type { Note, CreateNote, UpdateNote } from '../schemas/note';
export type {
NoteLink,
CreateNoteLink,
NoteTaskLink,
CreateNoteTaskLink,
} from '../schemas/note';
// ── Report ───────────────────────────────────────────────────────────────────
export type { Report, CreateReport, UpdateReport } from '../schemas/report';
export type { ReportTemplate, CreateReportTemplate } from '../schemas/report';
// ── Canvas ───────────────────────────────────────────────────────────────────
export type { Canvas, CreateCanvas, UpdateCanvas } from '../schemas/canvas';
export type { CanvasCard, CreateCanvasCard, UpdateCanvasCard } from '../schemas/canvas';
// ── Agent ────────────────────────────────────────────────────────────────────
export type { Agent, CreateAgent, UpdateAgent } from '../schemas/agent';
export type {
AgentActivity,
CreateAgentActivity,
AgentTask,
CreateAgentTask,
} from '../schemas/agent';
// ── Webhook ──────────────────────────────────────────────────────────────────
export type { Webhook, CreateWebhook, UpdateWebhook, WebhookDelivery } from '../schemas/webhook';
+8
View File
@@ -0,0 +1,8 @@
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"outDir": "./dist"
},
"include": ["src/**/*.ts"],
"exclude": ["node_modules", "dist"]
}