Jake Shore 96e52666c5 MCPEngine full sync — studio scaffold, factory v2, server updates, state.json — 2026-02-12
=== NEW ===
- studio/ — MCPEngine Studio scaffold (Next.js monorepo, build plan)
- docs/FACTORY-V2.md — Factory v2 architecture doc
- docs/CALENDLY_MCP_BUILD_SUMMARY.md — Calendly MCP build report

=== UPDATED SERVERS ===
- fieldedge: Added jobs-tools, UI build script, main entry update
- lightspeed: Updated main + server entry points
- squarespace: Added collection-browser + page-manager apps
- toast: Added main + server entry points

=== INFRA ===
- infra/command-center/state.json — Updated pipeline state
- infra/command-center/FACTORY-V2.md — Factory v2 operator playbook
2026-02-12 17:58:33 -05:00

377 lines
13 KiB
TypeScript

import {
pgTable,
pgEnum,
uuid,
text,
integer,
boolean,
timestamp,
jsonb,
real,
uniqueIndex,
index,
} from 'drizzle-orm/pg-core';
import { relations } from 'drizzle-orm';
// ── Enums ──────────────────────────────────────────────────────────────────────
export const userTierEnum = pgEnum('user_tier', [
'free',
'pro',
'team',
'enterprise',
]);
export const projectStatusEnum = pgEnum('project_status', [
'draft',
'analyzed',
'generated',
'tested',
'deployed',
]);
export const deploymentStatusEnum = pgEnum('deployment_status', [
'pending',
'building',
'live',
'failed',
'stopped',
]);
export const listingStatusEnum = pgEnum('listing_status', [
'review',
'published',
'rejected',
'archived',
]);
// ── Teams ──────────────────────────────────────────────────────────────────────
export const teams = pgTable(
'teams',
{
id: uuid('id').primaryKey().defaultRandom(),
name: text('name').notNull(),
slug: text('slug').notNull(),
ownerId: uuid('owner_id'), // FK to users.id (circular ref handled in relations)
tier: userTierEnum('tier').default('team').notNull(),
stripeSubscriptionId: text('stripe_subscription_id'),
maxSeats: integer('max_seats').default(5).notNull(),
createdAt: timestamp('created_at', { withTimezone: true })
.defaultNow()
.notNull(),
},
(t) => [
uniqueIndex('teams_slug_idx').on(t.slug),
],
);
// ── Users ──────────────────────────────────────────────────────────────────────
export const users = pgTable(
'users',
{
id: uuid('id').primaryKey().defaultRandom(),
clerkId: text('clerk_id').notNull(),
email: text('email').notNull(),
name: text('name'),
avatarUrl: text('avatar_url'),
tier: userTierEnum('tier').default('free').notNull(),
stripeCustomerId: text('stripe_customer_id'),
teamId: uuid('team_id').references(() => teams.id),
createdAt: timestamp('created_at', { withTimezone: true })
.defaultNow()
.notNull(),
updatedAt: timestamp('updated_at', { withTimezone: true })
.defaultNow()
.notNull(),
},
(t) => [
uniqueIndex('users_clerk_id_idx').on(t.clerkId),
uniqueIndex('users_email_idx').on(t.email),
index('users_team_id_idx').on(t.teamId),
],
);
// ── Projects ───────────────────────────────────────────────────────────────────
export const projects = pgTable(
'projects',
{
id: uuid('id').primaryKey().defaultRandom(),
userId: uuid('user_id')
.references(() => users.id)
.notNull(),
teamId: uuid('team_id').references(() => teams.id),
name: text('name').notNull(),
slug: text('slug').notNull(),
description: text('description'),
status: projectStatusEnum('status').default('draft').notNull(),
specUrl: text('spec_url'),
specRaw: jsonb('spec_raw'),
analysis: jsonb('analysis'),
toolConfig: jsonb('tool_config'),
appConfig: jsonb('app_config'),
authConfig: jsonb('auth_config'),
serverBundle: jsonb('server_bundle'),
templateId: uuid('template_id'), // FK to marketplace_listings (circular ref handled in relations)
createdAt: timestamp('created_at', { withTimezone: true })
.defaultNow()
.notNull(),
updatedAt: timestamp('updated_at', { withTimezone: true })
.defaultNow()
.notNull(),
},
(t) => [
uniqueIndex('projects_user_slug_idx').on(t.userId, t.slug),
index('projects_user_id_idx').on(t.userId),
index('projects_team_id_idx').on(t.teamId),
index('projects_status_idx').on(t.status),
index('projects_template_id_idx').on(t.templateId),
],
);
// ── Tools ──────────────────────────────────────────────────────────────────────
export const tools = pgTable(
'tools',
{
id: uuid('id').primaryKey().defaultRandom(),
projectId: uuid('project_id')
.references(() => projects.id, { onDelete: 'cascade' })
.notNull(),
name: text('name').notNull(),
description: text('description'),
groupName: text('group_name'),
inputSchema: jsonb('input_schema'),
outputSchema: jsonb('output_schema'),
annotations: jsonb('annotations'),
enabled: boolean('enabled').default(true).notNull(),
position: integer('position').default(0).notNull(),
canvasX: real('canvas_x'),
canvasY: real('canvas_y'),
createdAt: timestamp('created_at', { withTimezone: true })
.defaultNow()
.notNull(),
},
(t) => [
index('tools_project_id_idx').on(t.projectId),
index('tools_group_name_idx').on(t.groupName),
],
);
// ── Apps ────────────────────────────────────────────────────────────────────────
export const apps = pgTable(
'apps',
{
id: uuid('id').primaryKey().defaultRandom(),
projectId: uuid('project_id')
.references(() => projects.id, { onDelete: 'cascade' })
.notNull(),
name: text('name').notNull(),
pattern: text('pattern'),
layoutConfig: jsonb('layout_config'),
htmlBundle: text('html_bundle'),
toolBindings: jsonb('tool_bindings'),
createdAt: timestamp('created_at', { withTimezone: true })
.defaultNow()
.notNull(),
},
(t) => [
index('apps_project_id_idx').on(t.projectId),
],
);
// ── Deployments ────────────────────────────────────────────────────────────────
export const deployments = pgTable(
'deployments',
{
id: uuid('id').primaryKey().defaultRandom(),
projectId: uuid('project_id')
.references(() => projects.id)
.notNull(),
userId: uuid('user_id')
.references(() => users.id)
.notNull(),
target: text('target').notNull(),
status: deploymentStatusEnum('status').default('pending').notNull(),
url: text('url'),
endpoint: text('endpoint'),
workerId: text('worker_id'),
version: text('version'),
logs: jsonb('logs'),
createdAt: timestamp('created_at', { withTimezone: true })
.defaultNow()
.notNull(),
stoppedAt: timestamp('stopped_at', { withTimezone: true }),
},
(t) => [
index('deployments_project_id_idx').on(t.projectId),
index('deployments_user_id_idx').on(t.userId),
index('deployments_status_idx').on(t.status),
],
);
// ── Marketplace Listings ───────────────────────────────────────────────────────
export const marketplaceListings = pgTable(
'marketplace_listings',
{
id: uuid('id').primaryKey().defaultRandom(),
projectId: uuid('project_id').references(() => projects.id),
authorId: uuid('author_id').references(() => users.id),
name: text('name').notNull(),
slug: text('slug').notNull(),
description: text('description'),
category: text('category'),
tags: text('tags').array(),
iconUrl: text('icon_url'),
previewUrl: text('preview_url'),
toolCount: integer('tool_count').default(0).notNull(),
appCount: integer('app_count').default(0).notNull(),
forkCount: integer('fork_count').default(0).notNull(),
isOfficial: boolean('is_official').default(false).notNull(),
isFeatured: boolean('is_featured').default(false).notNull(),
priceCents: integer('price_cents').default(0).notNull(),
status: listingStatusEnum('status').default('review').notNull(),
createdAt: timestamp('created_at', { withTimezone: true })
.defaultNow()
.notNull(),
publishedAt: timestamp('published_at', { withTimezone: true }),
},
(t) => [
uniqueIndex('marketplace_slug_idx').on(t.slug),
index('marketplace_category_idx').on(t.category),
index('marketplace_status_idx').on(t.status),
index('marketplace_is_official_idx').on(t.isOfficial),
index('marketplace_is_featured_idx').on(t.isFeatured),
index('marketplace_author_id_idx').on(t.authorId),
],
);
// ── Usage Logs ─────────────────────────────────────────────────────────────────
export const usageLogs = pgTable(
'usage_logs',
{
id: uuid('id').primaryKey().defaultRandom(),
userId: uuid('user_id')
.references(() => users.id)
.notNull(),
action: text('action').notNull(),
projectId: uuid('project_id').references(() => projects.id),
tokensUsed: integer('tokens_used').default(0),
durationMs: integer('duration_ms').default(0),
createdAt: timestamp('created_at', { withTimezone: true })
.defaultNow()
.notNull(),
},
(t) => [
index('usage_logs_user_id_idx').on(t.userId),
index('usage_logs_project_id_idx').on(t.projectId),
index('usage_logs_action_idx').on(t.action),
index('usage_logs_created_at_idx').on(t.createdAt),
],
);
// ── API Keys ───────────────────────────────────────────────────────────────────
export const apiKeys = pgTable(
'api_keys',
{
id: uuid('id').primaryKey().defaultRandom(),
projectId: uuid('project_id')
.references(() => projects.id, { onDelete: 'cascade' })
.notNull(),
userId: uuid('user_id')
.references(() => users.id)
.notNull(),
keyName: text('key_name').notNull(),
encryptedValue: text('encrypted_value').notNull(),
createdAt: timestamp('created_at', { withTimezone: true })
.defaultNow()
.notNull(),
},
(t) => [
index('api_keys_project_id_idx').on(t.projectId),
index('api_keys_user_id_idx').on(t.userId),
],
);
// ── Relations ──────────────────────────────────────────────────────────────────
export const usersRelations = relations(users, ({ one, many }) => ({
team: one(teams, { fields: [users.teamId], references: [teams.id] }),
projects: many(projects),
deployments: many(deployments),
usageLogs: many(usageLogs),
apiKeys: many(apiKeys),
}));
export const teamsRelations = relations(teams, ({ one, many }) => ({
owner: one(users, { fields: [teams.ownerId], references: [users.id] }),
members: many(users),
projects: many(projects),
}));
export const projectsRelations = relations(projects, ({ one, many }) => ({
user: one(users, { fields: [projects.userId], references: [users.id] }),
team: one(teams, { fields: [projects.teamId], references: [teams.id] }),
template: one(marketplaceListings, {
fields: [projects.templateId],
references: [marketplaceListings.id],
}),
tools: many(tools),
apps: many(apps),
deployments: many(deployments),
apiKeys: many(apiKeys),
}));
export const toolsRelations = relations(tools, ({ one }) => ({
project: one(projects, { fields: [tools.projectId], references: [projects.id] }),
}));
export const appsRelations = relations(apps, ({ one }) => ({
project: one(projects, { fields: [apps.projectId], references: [projects.id] }),
}));
export const deploymentsRelations = relations(deployments, ({ one }) => ({
project: one(projects, {
fields: [deployments.projectId],
references: [projects.id],
}),
user: one(users, { fields: [deployments.userId], references: [users.id] }),
}));
export const marketplaceListingsRelations = relations(
marketplaceListings,
({ one, many }) => ({
project: one(projects, {
fields: [marketplaceListings.projectId],
references: [projects.id],
}),
author: one(users, {
fields: [marketplaceListings.authorId],
references: [users.id],
}),
}),
);
export const usageLogsRelations = relations(usageLogs, ({ one }) => ({
user: one(users, { fields: [usageLogs.userId], references: [users.id] }),
project: one(projects, {
fields: [usageLogs.projectId],
references: [projects.id],
}),
}));
export const apiKeysRelations = relations(apiKeys, ({ one }) => ({
project: one(projects, {
fields: [apiKeys.projectId],
references: [projects.id],
}),
user: one(users, { fields: [apiKeys.userId], references: [users.id] }),
}));