import { supabase } from '../db/client.js';
import type {
Project,
CreateProjectRequest,
UpdateProjectRequest
} from '../types.js';
/**
* Create a new project
*/
export async function createProject(projectData: CreateProjectRequest): Promise<Project> {
try {
if (!projectData.name || !projectData.business_type) {
throw new Error('Project name and business type are required');
}
const client = supabase.getAnonClient();
// Validate style_id if provided
if (projectData.style_id) {
const { data: styleExists, error: styleError } = await client
.from('design_styles')
.select('id')
.eq('id', projectData.style_id)
.single();
if (styleError || !styleExists) {
throw new Error(`Style with ID '${projectData.style_id}' not found`);
}
}
// Validate palette_id if provided
if (projectData.palette_id) {
const { data: paletteExists, error: paletteError } = await client
.from('design_palettes')
.select('id')
.eq('id', projectData.palette_id)
.single();
if (paletteError || !paletteExists) {
throw new Error(`Palette with ID '${projectData.palette_id}' not found`);
}
}
const newProject = {
name: projectData.name,
business_type: projectData.business_type,
description: projectData.description || null,
style_id: projectData.style_id || null,
palette_id: projectData.palette_id || null,
domain: projectData.domain || null,
status: 'draft' as const,
// user_id will be set by RLS if authentication is properly configured
};
const { data, error } = await client
.from('projects')
.insert(newProject)
.select()
.single();
if (error) {
supabase.log(`Error creating project: ${error.message}`, 'error');
throw new Error(`Failed to create project: ${error.message}`);
}
if (!data) {
throw new Error('Failed to create project: No data returned');
}
supabase.log(`Created project: ${data.name} (${data.id})`);
return data as Project;
} catch (error) {
supabase.log(`Error in createProject: ${error}`, 'error');
throw error;
}
}
/**
* List projects with optional filtering
*/
export async function listProjects(params: {
status?: 'draft' | 'published' | 'archived';
business_type?: string;
limit?: number;
offset?: number;
} = {}): Promise<{ projects: Project[]; total: number }> {
try {
const client = supabase.getAnonClient();
const { status, business_type, limit = 50, offset = 0 } = params;
let query = client
.from('projects')
.select('*', { count: 'exact' });
// Apply filters
if (status) {
query = query.eq('status', status);
}
if (business_type) {
query = query.eq('business_type', business_type);
}
const { data, error, count } = await query
.order('updated_at', { ascending: false })
.range(offset, offset + limit - 1);
if (error) {
supabase.log(`Error listing projects: ${error.message}`, 'error');
throw new Error(`Failed to list projects: ${error.message}`);
}
const projects = (data || []) as Project[];
supabase.log(`Retrieved ${projects.length} projects`);
return {
projects,
total: count || projects.length
};
} catch (error) {
supabase.log(`Error in listProjects: ${error}`, 'error');
throw error;
}
}
/**
* Get a specific project by ID
*/
export async function getProject(projectId: string): Promise<Project> {
try {
if (!projectId) {
throw new Error('Project ID is required');
}
const client = supabase.getAnonClient();
const { data, error } = await client
.from('projects')
.select('*')
.eq('id', projectId)
.single();
if (error) {
if (error.code === 'PGRST116') {
throw new Error(`Project with ID '${projectId}' not found`);
}
supabase.log(`Error fetching project: ${error.message}`, 'error');
throw new Error(`Failed to fetch project: ${error.message}`);
}
if (!data) {
throw new Error(`Project with ID '${projectId}' not found`);
}
supabase.log(`Retrieved project: ${data.name} (${data.id})`);
return data as Project;
} catch (error) {
supabase.log(`Error in getProject: ${error}`, 'error');
throw error;
}
}
/**
* Update an existing project
*/
export async function updateProject(
projectId: string,
updates: UpdateProjectRequest
): Promise<Project> {
try {
if (!projectId) {
throw new Error('Project ID is required');
}
if (Object.keys(updates).length === 0) {
throw new Error('At least one field must be provided for update');
}
const client = supabase.getAnonClient();
// Validate style_id if being updated
if (updates.style_id) {
const { data: styleExists, error: styleError } = await client
.from('design_styles')
.select('id')
.eq('id', updates.style_id)
.single();
if (styleError || !styleExists) {
throw new Error(`Style with ID '${updates.style_id}' not found`);
}
}
// Validate palette_id if being updated
if (updates.palette_id) {
const { data: paletteExists, error: paletteError } = await client
.from('design_palettes')
.select('id')
.eq('id', updates.palette_id)
.single();
if (paletteError || !paletteExists) {
throw new Error(`Palette with ID '${updates.palette_id}' not found`);
}
}
const { data, error } = await client
.from('projects')
.update(updates)
.eq('id', projectId)
.select()
.single();
if (error) {
if (error.code === 'PGRST116') {
throw new Error(`Project with ID '${projectId}' not found`);
}
supabase.log(`Error updating project: ${error.message}`, 'error');
throw new Error(`Failed to update project: ${error.message}`);
}
if (!data) {
throw new Error(`Project with ID '${projectId}' not found`);
}
supabase.log(`Updated project: ${data.name} (${data.id})`);
return data as Project;
} catch (error) {
supabase.log(`Error in updateProject: ${error}`, 'error');
throw error;
}
}
/**
* Delete a project
*/
export async function deleteProject(projectId: string): Promise<void> {
try {
if (!projectId) {
throw new Error('Project ID is required');
}
const client = supabase.getAnonClient();
// First check if project exists
const { data: existingProject, error: fetchError } = await client
.from('projects')
.select('name')
.eq('id', projectId)
.single();
if (fetchError) {
if (fetchError.code === 'PGRST116') {
throw new Error(`Project with ID '${projectId}' not found`);
}
throw new Error(`Error checking project: ${fetchError.message}`);
}
// Delete the project
const { error } = await client
.from('projects')
.delete()
.eq('id', projectId);
if (error) {
supabase.log(`Error deleting project: ${error.message}`, 'error');
throw new Error(`Failed to delete project: ${error.message}`);
}
supabase.log(`Deleted project: ${existingProject.name} (${projectId})`);
} catch (error) {
supabase.log(`Error in deleteProject: ${error}`, 'error');
throw error;
}
}