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:
@@ -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;
|
||||
@@ -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';
|
||||
@@ -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>;
|
||||
@@ -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>;
|
||||
@@ -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>;
|
||||
@@ -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>;
|
||||
@@ -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>;
|
||||
@@ -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>;
|
||||
@@ -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>;
|
||||
@@ -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>;
|
||||
@@ -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>;
|
||||
@@ -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>;
|
||||
@@ -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';
|
||||
Reference in New Issue
Block a user