Skip to main content

Overview

Project server actions handle CRUD operations for VizBoard projects, including creation with database connections, updates, deletion, and schema management.

createProjectWithConnections

Creates a new project with optional database connections. Supports both full project creation and draft mode.
export async function createProjectWithConnections(
  input: (ProjectCreateData | ProjectCreateDraftData) & { userId: string }
): Promise<CreateProjectResponse>

Parameters

input
object
required
input.title
string
required
Project title (1-100 characters, alphanumeric with spaces, dots, underscores, hyphens)
input.description
string
Project description (max 500 characters)
input.isPublic
boolean
default:false
Whether the project is publicly accessible
input.userId
string
required
ID of the user creating the project
input.connections
DatabaseConnection[]
Array of database connections. At least one required for non-draft projects.
connections[].title
string
required
Connection name (1-50 characters)
connections[].host
string
required
Database host (IP, localhost, or hostname)
connections[].port
number
required
Database port (1-65535)
connections[].database
string
required
Database name (1-60 characters, alphanumeric with hyphens/underscores)
connections[].user
string
required
Database username (1-50 characters)
connections[].password
string
required
Database password (min 1 character)

Response

success
boolean
required
Indicates if the project was created successfully
projectId
string
ID of the created project (only when success is true)
validationResult
ValidationResult | null
Connection validation results after creation
validationResult.success
boolean
Whether validation succeeded
validationResult.connectionStatuses
ConnectionStatus[]
Status of each connection
error
string
Error message (only when success is false)

Behavior

  • Auto-validation: Connections are automatically validated after creation
  • Auto-introspection: Valid connections are automatically introspected to extract schema
  • Draft mode: Projects can be created without connections (draft mode)
  • Encryption: Connection credentials are encrypted before storage
  • Revalidation: Automatically revalidates the /projects path

Example

import { createProjectWithConnections } from '@/app/actions/project/crud'

const result = await createProjectWithConnections({
  title: 'Analytics Dashboard',
  description: 'Customer analytics and reporting',
  isPublic: false,
  userId: 'clx1234567',
  connections: [
    {
      title: 'Production DB',
      host: 'db.example.com',
      port: 5432,
      database: 'analytics',
      user: 'readonly_user',
      password: 'secure_password'
    }
  ]
})

if (result.success) {
  console.log('Project created:', result.projectId)
  console.log('Valid connections:', result.validationResult?.connectionStatuses)
}

updateProject

Updates an existing project and its connections.
export async function updateProject(data: UpdateProjectData): Promise<UpdateProjectResponse>

Parameters

data
UpdateProjectData
required
data.id
string
required
Project ID to update
data.title
string
New project title
data.description
string
New project description
data.isPublic
boolean
New public visibility setting
data.connections
ConnectionUpdateData[]
Updated connections array
connections[].id
string
Connection ID (for existing connections)
connections[].title
string
required
Connection name
connections[].host
string
required
Database host
connections[].port
number
required
Database port
connections[].database
string
required
Database name
connections[].user
string
required
Database username
connections[].password
string
required
Database password or "KEEP_CURRENT_PASSWORD" to preserve existing password
connections[].isExisting
boolean
Whether this is an existing connection (internal use)

Response

success
boolean
required
Indicates if the update was successful
validationResult
ValidationResult | null
Connection validation results after update
error
string
Error message (only when success is false)

Behavior

  • Ownership verification: Only the project owner can update
  • Connection management: Connections not in the update array are deleted
  • Password handling: Use "KEEP_CURRENT_PASSWORD" to preserve existing passwords
  • Auto-validation: Connections are validated after update
  • Auto-introspection: Valid connections are re-introspected
  • Public constraint: Projects without valid connections are automatically set to private
  • Revalidation: Revalidates /projects and /projects/:id paths

Example

import { updateProject } from '@/app/actions/project/crud'

const result = await updateProject({
  id: 'clx7890abc',
  title: 'Updated Analytics Dashboard',
  description: 'New description',
  connections: [
    {
      id: 'conn_123', // Existing connection
      title: 'Production DB',
      host: 'db.example.com',
      port: 5432,
      database: 'analytics',
      user: 'readonly_user',
      password: 'KEEP_CURRENT_PASSWORD' // Keep existing password
    },
    {
      // New connection (no id)
      title: 'Staging DB',
      host: 'staging.example.com',
      port: 5432,
      database: 'analytics_staging',
      user: 'staging_user',
      password: 'new_password'
    }
  ]
})
Use "KEEP_CURRENT_PASSWORD" to avoid requiring users to re-enter passwords when editing connections.

deleteProject

Permanently deletes a project and all associated connections and widgets.
export async function deleteProject(
  projectId: string,
  userId: string
): Promise<DeleteProjectResponse>

Parameters

projectId
string
required
ID of the project to delete
userId
string
required
ID of the user requesting deletion (must be owner)

Response

success
boolean
required
Indicates if deletion was successful
message
string
Success message with project title
error
string
Error message (only when success is false)Possible errors:
  • "Invalid project ID"
  • "Project not found"
  • "Unauthorized: You can only delete your own projects"

Behavior

  • Cascade deletion: Deletes all widgets, connections, and the project
  • Ownership verification: Only the project owner can delete
  • Transaction: All deletions occur in a database transaction
  • Revalidation: Revalidates the /projects path

Example

import { deleteProject } from '@/app/actions/project/crud'

const result = await deleteProject('clx7890abc', 'clx1234567')

if (result.success) {
  console.log(result.message) // "Project 'Analytics Dashboard' deleted successfully"
} else {
  console.error(result.error)
}
This action is irreversible and will delete all associated data including widgets and database connections.

getProjectWithConnections

Retrieves a project with decrypted connection details.
export async function getProjectWithConnections(
  projectId: string,
  userId: string
): Promise<GetProjectResponse>

Parameters

projectId
string
required
ID of the project to retrieve
userId
string
required
ID of the user requesting the project (must be owner)

Response

success
boolean
required
Indicates if retrieval was successful
data
ProjectWithConnections
Project data with decrypted connections
data.id
string
Project ID
data.title
string
Project title
data.description
string
Project description
data.isPublic
boolean
Public visibility status
data.idPublic
string | null
Public ID for sharing
data.orderedWidgetIds
string[]
Ordered array of widget IDs
data.databases
DatabaseConnection[]
Array of database connections
databases[].id
string
Connection ID
databases[].title
string
Connection name
databases[].host
string
Database host
databases[].port
number
Database port
databases[].database
string
Database name
databases[].user
string
Database username
databases[].password
string
Always empty string for security
databases[].status
'valid' | 'invalid' | 'pending'
Connection validation status
databases[].isExisting
boolean
Always true for retrieved connections
error
string
Error message (only when success is false)

Example

import { getProjectWithConnections } from '@/app/actions/project/crud'

const result = await getProjectWithConnections('clx7890abc', 'clx1234567')

if (result.success && result.data) {
  console.log('Project:', result.data.title)
  console.log('Connections:', result.data.databases.length)
  
  result.data.databases.forEach(db => {
    console.log(`${db.title}: ${db.status}`)
  })
}
Passwords are always returned as empty strings for security. Use "KEEP_CURRENT_PASSWORD" when updating.

getUserProjects

Retrieves all projects for a user with connection and widget statistics.
export async function getUserProjects(userId: string): Promise<GetUserProjectsResponse>

Parameters

userId
string
required
ID of the user whose projects to retrieve

Response

success
boolean
required
Indicates if retrieval was successful
data
ProjectWithStats[]
Array of projects with statistics
data[].id
string
Project ID
data[].title
string
Project title
data[].description
string
Project description
data[].isPublic
boolean
Public visibility status
data[].totalConnections
number
Total number of connections
data[].validConnections
number
Number of valid connections
data[].hasValidatedConnections
boolean
Whether any connections have been validated
data[].totalSchemas
number
Number of valid connections (same as validConnections)
data[].validSchemas
number
Number of connections with introspected schemas
data[].hasIntrospectedSchemas
boolean
Whether any schemas have been introspected
data[].widgetCount
number
Number of widgets in the project
data[].createdAt
Date
Project creation timestamp
data[].updatedAt
Date
Last update timestamp
error
string
Error message (only when success is false)

Example

import { getUserProjects } from '@/app/actions/project/crud'

const result = await getUserProjects('clx1234567')

if (result.success && result.data) {
  result.data.forEach(project => {
    console.log(`${project.title}: ${project.validConnections}/${project.totalConnections} valid connections`)
    console.log(`  Widgets: ${project.widgetCount}`)
    console.log(`  Schemas: ${project.validSchemas}/${project.totalSchemas}`)
  })
}

regenerateProjectSchemas

Re-introspects all valid database connections in a project to refresh schema data.
export async function regenerateProjectSchemas(
  projectId: string,
  userId: string
): Promise<RegenerateResponse>

Parameters

projectId
string
required
ID of the project to regenerate schemas for
userId
string
required
ID of the user requesting regeneration (must be owner)

Response

success
boolean
required
Indicates if regeneration was successful
data
RegenerateData
Regeneration results
data.totalConnections
number
Total connections processed
data.successfulRegeneration
number
Number of successful regenerations
data.failedRegeneration
number
Number of failed regenerations
data.details
ConnectionResult[]
Detailed results per connection
details[].connectionId
string
Connection ID
details[].connectionTitle
string
Connection name
details[].success
boolean
Whether regeneration succeeded
details[].error
string
Error message (if failed)
error
string
Error message (only when success is false)

Example

import { regenerateProjectSchemas } from '@/app/actions/project/crud'

const result = await regenerateProjectSchemas('clx7890abc', 'clx1234567')

if (result.success && result.data) {
  console.log(`Regenerated ${result.data.successfulRegeneration}/${result.data.totalConnections} schemas`)
  
  result.data.details.forEach(detail => {
    if (!detail.success) {
      console.error(`Failed: ${detail.connectionTitle} - ${detail.error}`)
    }
  })
}

isProjectOwner

Checks if a user owns a specific project.
export async function isProjectOwner(
  userId: string,
  projectId: string
): Promise<OwnershipResponse>

Parameters

userId
string
required
User ID to check
projectId
string
required
Project ID to check

Response

success
boolean
required
Indicates if the check was successful
isOwner
boolean
required
Whether the user owns the project
message
string
Error message (only when success is false)

Example

import { isProjectOwner } from '@/app/actions/project/crud'

const result = await isProjectOwner('clx1234567', 'clx7890abc')

if (result.success && result.isOwner) {
  console.log('User owns this project')
}

Type Definitions

// Input types (Zod schemas)
interface ProjectCreateData {
  title: string          // 1-100 chars, alphanumeric + spaces/dots/underscores/hyphens
  description?: string   // Max 500 chars
  isPublic?: boolean     // Default: false
  connections: DatabaseConnection[] // Min 1 required
}

interface ProjectCreateDraftData {
  title: string
  description?: string
  isPublic?: boolean
  connections?: DatabaseConnection[] // Optional for drafts
}

interface DatabaseConnection {
  title: string         // 1-50 chars
  host: string          // IP, localhost, or hostname
  port: number          // 1-65535
  database: string      // 1-60 chars, alphanumeric + hyphens/underscores
  user: string          // 1-50 chars
  password: string      // Min 1 char
}

interface UpdateProjectData {
  id: string
  title?: string
  description?: string
  isPublic?: boolean
  connections?: ConnectionUpdateData[]
}

interface ConnectionUpdateData extends DatabaseConnection {
  id?: string           // Present for existing connections
  isExisting?: boolean  // Internal flag
}

Build docs developers (and LLMs) love