feat: pricing plan + usage page

This commit is contained in:
BennyKok 2024-01-25 00:34:41 +08:00
parent 14c3ca6bf5
commit 0f9e0c9c76
39 changed files with 7847 additions and 402 deletions

Binary file not shown.

View File

@ -0,0 +1,14 @@
CREATE TABLE IF NOT EXISTS "comfyui_deploy"."user_usage" (
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
"org_id" text,
"user_id" text NOT NULL,
"usage_time" real DEFAULT 0 NOT NULL,
"created_at" timestamp DEFAULT now() NOT NULL,
"ended_at" timestamp DEFAULT now() NOT NULL
);
--> statement-breakpoint
DO $$ BEGIN
ALTER TABLE "comfyui_deploy"."user_usage" ADD CONSTRAINT "user_usage_user_id_users_id_fk" FOREIGN KEY ("user_id") REFERENCES "comfyui_deploy"."users"("id") ON DELETE cascade ON UPDATE no action;
EXCEPTION
WHEN duplicate_object THEN null;
END $$;

View File

@ -0,0 +1,22 @@
DO $$ BEGIN
CREATE TYPE "subscription_plan" AS ENUM('basic', 'pro', 'enterprise');
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
--> statement-breakpoint
DO $$ BEGIN
CREATE TYPE "subscription_plan_status" AS ENUM('active', 'deleted', 'paused');
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
--> statement-breakpoint
CREATE TABLE IF NOT EXISTS "comfyui_deploy"."subscription_status" (
"stripe_customer_id" text PRIMARY KEY NOT NULL,
"user_id" text,
"org_id" text,
"plan" "subscription_plan" NOT NULL,
"status" "subscription_plan_status" NOT NULL,
"subscription_plan_id" text,
"created_at" timestamp DEFAULT now() NOT NULL,
"updated_at" timestamp DEFAULT now() NOT NULL
);

View File

@ -0,0 +1,3 @@
ALTER TABLE "comfyui_deploy"."subscription_status" RENAME COLUMN "subscription_plan_id" TO "subscription_id";--> statement-breakpoint
ALTER TABLE "comfyui_deploy"."subscription_status" ADD COLUMN "subscription_item_plan_id" text;--> statement-breakpoint
ALTER TABLE "comfyui_deploy"."subscription_status" ADD COLUMN "subscription_item_api_id" text;

View File

@ -0,0 +1 @@
ALTER TABLE "comfyui_deploy"."subscription_status" ADD COLUMN "cancel_at_period_end" boolean DEFAULT false;

View File

@ -0,0 +1,2 @@
ALTER TABLE "comfyui_deploy"."workflow_runs" ADD COLUMN "user_id" text;--> statement-breakpoint
ALTER TABLE "comfyui_deploy"."workflow_runs" ADD COLUMN "org_id" text;

View File

@ -0,0 +1 @@
ALTER TABLE "comfyui_deploy"."workflow_runs" ADD COLUMN "gpu" "machine_gpu";

View File

@ -0,0 +1 @@
ALTER TABLE "comfyui_deploy"."workflow_runs" ADD COLUMN "machine_type" "machine_type";

View File

@ -0,0 +1,894 @@
{
"id": "2b2a5d0a-2494-45ea-9d4a-58a70df97829",
"prevId": "8d654f92-7f7e-420f-bbd3-73b6b27adf35",
"version": "5",
"dialect": "pg",
"tables": {
"api_keys": {
"name": "api_keys",
"schema": "comfyui_deploy",
"columns": {
"id": {
"name": "id",
"type": "uuid",
"primaryKey": true,
"notNull": true,
"default": "gen_random_uuid()"
},
"key": {
"name": "key",
"type": "text",
"primaryKey": false,
"notNull": true
},
"name": {
"name": "name",
"type": "text",
"primaryKey": false,
"notNull": true
},
"user_id": {
"name": "user_id",
"type": "text",
"primaryKey": false,
"notNull": true
},
"org_id": {
"name": "org_id",
"type": "text",
"primaryKey": false,
"notNull": false
},
"revoked": {
"name": "revoked",
"type": "boolean",
"primaryKey": false,
"notNull": true,
"default": false
},
"created_at": {
"name": "created_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"updated_at": {
"name": "updated_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
}
},
"indexes": {},
"foreignKeys": {
"api_keys_user_id_users_id_fk": {
"name": "api_keys_user_id_users_id_fk",
"tableFrom": "api_keys",
"tableTo": "users",
"columnsFrom": [
"user_id"
],
"columnsTo": [
"id"
],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {
"api_keys_key_unique": {
"name": "api_keys_key_unique",
"nullsNotDistinct": false,
"columns": [
"key"
]
}
}
},
"auth_requests": {
"name": "auth_requests",
"schema": "comfyui_deploy",
"columns": {
"request_id": {
"name": "request_id",
"type": "text",
"primaryKey": true,
"notNull": true
},
"user_id": {
"name": "user_id",
"type": "text",
"primaryKey": false,
"notNull": false
},
"org_id": {
"name": "org_id",
"type": "text",
"primaryKey": false,
"notNull": false
},
"api_hash": {
"name": "api_hash",
"type": "text",
"primaryKey": false,
"notNull": false
},
"created_at": {
"name": "created_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"expired_date": {
"name": "expired_date",
"type": "timestamp",
"primaryKey": false,
"notNull": false
},
"updated_at": {
"name": "updated_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {}
},
"deployments": {
"name": "deployments",
"schema": "comfyui_deploy",
"columns": {
"id": {
"name": "id",
"type": "uuid",
"primaryKey": true,
"notNull": true,
"default": "gen_random_uuid()"
},
"user_id": {
"name": "user_id",
"type": "text",
"primaryKey": false,
"notNull": true
},
"org_id": {
"name": "org_id",
"type": "text",
"primaryKey": false,
"notNull": false
},
"workflow_version_id": {
"name": "workflow_version_id",
"type": "uuid",
"primaryKey": false,
"notNull": true
},
"workflow_id": {
"name": "workflow_id",
"type": "uuid",
"primaryKey": false,
"notNull": true
},
"machine_id": {
"name": "machine_id",
"type": "uuid",
"primaryKey": false,
"notNull": true
},
"share_slug": {
"name": "share_slug",
"type": "text",
"primaryKey": false,
"notNull": false
},
"description": {
"name": "description",
"type": "text",
"primaryKey": false,
"notNull": false
},
"showcase_media": {
"name": "showcase_media",
"type": "jsonb",
"primaryKey": false,
"notNull": false
},
"environment": {
"name": "environment",
"type": "deployment_environment",
"primaryKey": false,
"notNull": true
},
"created_at": {
"name": "created_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"updated_at": {
"name": "updated_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
}
},
"indexes": {},
"foreignKeys": {
"deployments_user_id_users_id_fk": {
"name": "deployments_user_id_users_id_fk",
"tableFrom": "deployments",
"tableTo": "users",
"columnsFrom": [
"user_id"
],
"columnsTo": [
"id"
],
"onDelete": "cascade",
"onUpdate": "no action"
},
"deployments_workflow_version_id_workflow_versions_id_fk": {
"name": "deployments_workflow_version_id_workflow_versions_id_fk",
"tableFrom": "deployments",
"tableTo": "workflow_versions",
"columnsFrom": [
"workflow_version_id"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
},
"deployments_workflow_id_workflows_id_fk": {
"name": "deployments_workflow_id_workflows_id_fk",
"tableFrom": "deployments",
"tableTo": "workflows",
"columnsFrom": [
"workflow_id"
],
"columnsTo": [
"id"
],
"onDelete": "cascade",
"onUpdate": "no action"
},
"deployments_machine_id_machines_id_fk": {
"name": "deployments_machine_id_machines_id_fk",
"tableFrom": "deployments",
"tableTo": "machines",
"columnsFrom": [
"machine_id"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {
"deployments_share_slug_unique": {
"name": "deployments_share_slug_unique",
"nullsNotDistinct": false,
"columns": [
"share_slug"
]
}
}
},
"machines": {
"name": "machines",
"schema": "comfyui_deploy",
"columns": {
"id": {
"name": "id",
"type": "uuid",
"primaryKey": true,
"notNull": true,
"default": "gen_random_uuid()"
},
"user_id": {
"name": "user_id",
"type": "text",
"primaryKey": false,
"notNull": true
},
"name": {
"name": "name",
"type": "text",
"primaryKey": false,
"notNull": true
},
"org_id": {
"name": "org_id",
"type": "text",
"primaryKey": false,
"notNull": false
},
"endpoint": {
"name": "endpoint",
"type": "text",
"primaryKey": false,
"notNull": true
},
"created_at": {
"name": "created_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"updated_at": {
"name": "updated_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"disabled": {
"name": "disabled",
"type": "boolean",
"primaryKey": false,
"notNull": true,
"default": false
},
"auth_token": {
"name": "auth_token",
"type": "text",
"primaryKey": false,
"notNull": false
},
"type": {
"name": "type",
"type": "machine_type",
"primaryKey": false,
"notNull": true,
"default": "'classic'"
},
"status": {
"name": "status",
"type": "machine_status",
"primaryKey": false,
"notNull": true,
"default": "'ready'"
},
"snapshot": {
"name": "snapshot",
"type": "jsonb",
"primaryKey": false,
"notNull": false
},
"models": {
"name": "models",
"type": "jsonb",
"primaryKey": false,
"notNull": false
},
"gpu": {
"name": "gpu",
"type": "machine_gpu",
"primaryKey": false,
"notNull": false
},
"build_machine_instance_id": {
"name": "build_machine_instance_id",
"type": "text",
"primaryKey": false,
"notNull": false
},
"build_log": {
"name": "build_log",
"type": "text",
"primaryKey": false,
"notNull": false
}
},
"indexes": {},
"foreignKeys": {
"machines_user_id_users_id_fk": {
"name": "machines_user_id_users_id_fk",
"tableFrom": "machines",
"tableTo": "users",
"columnsFrom": [
"user_id"
],
"columnsTo": [
"id"
],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {}
},
"user_usage": {
"name": "user_usage",
"schema": "comfyui_deploy",
"columns": {
"id": {
"name": "id",
"type": "uuid",
"primaryKey": true,
"notNull": true,
"default": "gen_random_uuid()"
},
"org_id": {
"name": "org_id",
"type": "text",
"primaryKey": false,
"notNull": false
},
"user_id": {
"name": "user_id",
"type": "text",
"primaryKey": false,
"notNull": true
},
"usage_time": {
"name": "usage_time",
"type": "real",
"primaryKey": false,
"notNull": true,
"default": 0
},
"created_at": {
"name": "created_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"ended_at": {
"name": "ended_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
}
},
"indexes": {},
"foreignKeys": {
"user_usage_user_id_users_id_fk": {
"name": "user_usage_user_id_users_id_fk",
"tableFrom": "user_usage",
"tableTo": "users",
"columnsFrom": [
"user_id"
],
"columnsTo": [
"id"
],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {}
},
"users": {
"name": "users",
"schema": "comfyui_deploy",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true
},
"username": {
"name": "username",
"type": "text",
"primaryKey": false,
"notNull": true
},
"name": {
"name": "name",
"type": "text",
"primaryKey": false,
"notNull": true
},
"created_at": {
"name": "created_at",
"type": "timestamp",
"primaryKey": false,
"notNull": false,
"default": "now()"
},
"updated_at": {
"name": "updated_at",
"type": "timestamp",
"primaryKey": false,
"notNull": false,
"default": "now()"
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {}
},
"workflow_run_outputs": {
"name": "workflow_run_outputs",
"schema": "comfyui_deploy",
"columns": {
"id": {
"name": "id",
"type": "uuid",
"primaryKey": true,
"notNull": true,
"default": "gen_random_uuid()"
},
"run_id": {
"name": "run_id",
"type": "uuid",
"primaryKey": false,
"notNull": true
},
"data": {
"name": "data",
"type": "jsonb",
"primaryKey": false,
"notNull": false
},
"created_at": {
"name": "created_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"updated_at": {
"name": "updated_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
}
},
"indexes": {},
"foreignKeys": {
"workflow_run_outputs_run_id_workflow_runs_id_fk": {
"name": "workflow_run_outputs_run_id_workflow_runs_id_fk",
"tableFrom": "workflow_run_outputs",
"tableTo": "workflow_runs",
"columnsFrom": [
"run_id"
],
"columnsTo": [
"id"
],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {}
},
"workflow_runs": {
"name": "workflow_runs",
"schema": "comfyui_deploy",
"columns": {
"id": {
"name": "id",
"type": "uuid",
"primaryKey": true,
"notNull": true,
"default": "gen_random_uuid()"
},
"workflow_version_id": {
"name": "workflow_version_id",
"type": "uuid",
"primaryKey": false,
"notNull": false
},
"workflow_inputs": {
"name": "workflow_inputs",
"type": "jsonb",
"primaryKey": false,
"notNull": false
},
"workflow_id": {
"name": "workflow_id",
"type": "uuid",
"primaryKey": false,
"notNull": true
},
"machine_id": {
"name": "machine_id",
"type": "uuid",
"primaryKey": false,
"notNull": false
},
"origin": {
"name": "origin",
"type": "workflow_run_origin",
"primaryKey": false,
"notNull": true,
"default": "'api'"
},
"status": {
"name": "status",
"type": "workflow_run_status",
"primaryKey": false,
"notNull": true,
"default": "'not-started'"
},
"ended_at": {
"name": "ended_at",
"type": "timestamp",
"primaryKey": false,
"notNull": false
},
"created_at": {
"name": "created_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"started_at": {
"name": "started_at",
"type": "timestamp",
"primaryKey": false,
"notNull": false
}
},
"indexes": {},
"foreignKeys": {
"workflow_runs_workflow_version_id_workflow_versions_id_fk": {
"name": "workflow_runs_workflow_version_id_workflow_versions_id_fk",
"tableFrom": "workflow_runs",
"tableTo": "workflow_versions",
"columnsFrom": [
"workflow_version_id"
],
"columnsTo": [
"id"
],
"onDelete": "set null",
"onUpdate": "no action"
},
"workflow_runs_workflow_id_workflows_id_fk": {
"name": "workflow_runs_workflow_id_workflows_id_fk",
"tableFrom": "workflow_runs",
"tableTo": "workflows",
"columnsFrom": [
"workflow_id"
],
"columnsTo": [
"id"
],
"onDelete": "cascade",
"onUpdate": "no action"
},
"workflow_runs_machine_id_machines_id_fk": {
"name": "workflow_runs_machine_id_machines_id_fk",
"tableFrom": "workflow_runs",
"tableTo": "machines",
"columnsFrom": [
"machine_id"
],
"columnsTo": [
"id"
],
"onDelete": "set null",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {}
},
"workflows": {
"name": "workflows",
"schema": "comfyui_deploy",
"columns": {
"id": {
"name": "id",
"type": "uuid",
"primaryKey": true,
"notNull": true,
"default": "gen_random_uuid()"
},
"user_id": {
"name": "user_id",
"type": "text",
"primaryKey": false,
"notNull": true
},
"org_id": {
"name": "org_id",
"type": "text",
"primaryKey": false,
"notNull": false
},
"name": {
"name": "name",
"type": "text",
"primaryKey": false,
"notNull": true
},
"created_at": {
"name": "created_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"updated_at": {
"name": "updated_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
}
},
"indexes": {},
"foreignKeys": {
"workflows_user_id_users_id_fk": {
"name": "workflows_user_id_users_id_fk",
"tableFrom": "workflows",
"tableTo": "users",
"columnsFrom": [
"user_id"
],
"columnsTo": [
"id"
],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {}
},
"workflow_versions": {
"name": "workflow_versions",
"schema": "comfyui_deploy",
"columns": {
"workflow_id": {
"name": "workflow_id",
"type": "uuid",
"primaryKey": false,
"notNull": true
},
"id": {
"name": "id",
"type": "uuid",
"primaryKey": true,
"notNull": true,
"default": "gen_random_uuid()"
},
"workflow": {
"name": "workflow",
"type": "jsonb",
"primaryKey": false,
"notNull": false
},
"workflow_api": {
"name": "workflow_api",
"type": "jsonb",
"primaryKey": false,
"notNull": false
},
"version": {
"name": "version",
"type": "integer",
"primaryKey": false,
"notNull": true
},
"snapshot": {
"name": "snapshot",
"type": "jsonb",
"primaryKey": false,
"notNull": false
},
"created_at": {
"name": "created_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"updated_at": {
"name": "updated_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
}
},
"indexes": {},
"foreignKeys": {
"workflow_versions_workflow_id_workflows_id_fk": {
"name": "workflow_versions_workflow_id_workflows_id_fk",
"tableFrom": "workflow_versions",
"tableTo": "workflows",
"columnsFrom": [
"workflow_id"
],
"columnsTo": [
"id"
],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {}
}
},
"enums": {
"deployment_environment": {
"name": "deployment_environment",
"values": {
"staging": "staging",
"production": "production",
"public-share": "public-share"
}
},
"machine_gpu": {
"name": "machine_gpu",
"values": {
"T4": "T4",
"A10G": "A10G",
"A100": "A100"
}
},
"machine_status": {
"name": "machine_status",
"values": {
"ready": "ready",
"building": "building",
"error": "error"
}
},
"machine_type": {
"name": "machine_type",
"values": {
"classic": "classic",
"runpod-serverless": "runpod-serverless",
"modal-serverless": "modal-serverless",
"comfy-deploy-serverless": "comfy-deploy-serverless"
}
},
"workflow_run_origin": {
"name": "workflow_run_origin",
"values": {
"manual": "manual",
"api": "api",
"public-share": "public-share"
}
},
"workflow_run_status": {
"name": "workflow_run_status",
"values": {
"not-started": "not-started",
"running": "running",
"uploading": "uploading",
"success": "success",
"failed": "failed"
}
}
},
"schemas": {
"comfyui_deploy": "comfyui_deploy"
},
"_meta": {
"schemas": {},
"tables": {},
"columns": {}
}
}

View File

@ -0,0 +1,970 @@
{
"id": "4db08fc3-2444-42da-b742-f1832ad8caf1",
"prevId": "2b2a5d0a-2494-45ea-9d4a-58a70df97829",
"version": "5",
"dialect": "pg",
"tables": {
"api_keys": {
"name": "api_keys",
"schema": "comfyui_deploy",
"columns": {
"id": {
"name": "id",
"type": "uuid",
"primaryKey": true,
"notNull": true,
"default": "gen_random_uuid()"
},
"key": {
"name": "key",
"type": "text",
"primaryKey": false,
"notNull": true
},
"name": {
"name": "name",
"type": "text",
"primaryKey": false,
"notNull": true
},
"user_id": {
"name": "user_id",
"type": "text",
"primaryKey": false,
"notNull": true
},
"org_id": {
"name": "org_id",
"type": "text",
"primaryKey": false,
"notNull": false
},
"revoked": {
"name": "revoked",
"type": "boolean",
"primaryKey": false,
"notNull": true,
"default": false
},
"created_at": {
"name": "created_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"updated_at": {
"name": "updated_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
}
},
"indexes": {},
"foreignKeys": {
"api_keys_user_id_users_id_fk": {
"name": "api_keys_user_id_users_id_fk",
"tableFrom": "api_keys",
"tableTo": "users",
"columnsFrom": [
"user_id"
],
"columnsTo": [
"id"
],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {
"api_keys_key_unique": {
"name": "api_keys_key_unique",
"nullsNotDistinct": false,
"columns": [
"key"
]
}
}
},
"auth_requests": {
"name": "auth_requests",
"schema": "comfyui_deploy",
"columns": {
"request_id": {
"name": "request_id",
"type": "text",
"primaryKey": true,
"notNull": true
},
"user_id": {
"name": "user_id",
"type": "text",
"primaryKey": false,
"notNull": false
},
"org_id": {
"name": "org_id",
"type": "text",
"primaryKey": false,
"notNull": false
},
"api_hash": {
"name": "api_hash",
"type": "text",
"primaryKey": false,
"notNull": false
},
"created_at": {
"name": "created_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"expired_date": {
"name": "expired_date",
"type": "timestamp",
"primaryKey": false,
"notNull": false
},
"updated_at": {
"name": "updated_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {}
},
"deployments": {
"name": "deployments",
"schema": "comfyui_deploy",
"columns": {
"id": {
"name": "id",
"type": "uuid",
"primaryKey": true,
"notNull": true,
"default": "gen_random_uuid()"
},
"user_id": {
"name": "user_id",
"type": "text",
"primaryKey": false,
"notNull": true
},
"org_id": {
"name": "org_id",
"type": "text",
"primaryKey": false,
"notNull": false
},
"workflow_version_id": {
"name": "workflow_version_id",
"type": "uuid",
"primaryKey": false,
"notNull": true
},
"workflow_id": {
"name": "workflow_id",
"type": "uuid",
"primaryKey": false,
"notNull": true
},
"machine_id": {
"name": "machine_id",
"type": "uuid",
"primaryKey": false,
"notNull": true
},
"share_slug": {
"name": "share_slug",
"type": "text",
"primaryKey": false,
"notNull": false
},
"description": {
"name": "description",
"type": "text",
"primaryKey": false,
"notNull": false
},
"showcase_media": {
"name": "showcase_media",
"type": "jsonb",
"primaryKey": false,
"notNull": false
},
"environment": {
"name": "environment",
"type": "deployment_environment",
"primaryKey": false,
"notNull": true
},
"created_at": {
"name": "created_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"updated_at": {
"name": "updated_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
}
},
"indexes": {},
"foreignKeys": {
"deployments_user_id_users_id_fk": {
"name": "deployments_user_id_users_id_fk",
"tableFrom": "deployments",
"tableTo": "users",
"columnsFrom": [
"user_id"
],
"columnsTo": [
"id"
],
"onDelete": "cascade",
"onUpdate": "no action"
},
"deployments_workflow_version_id_workflow_versions_id_fk": {
"name": "deployments_workflow_version_id_workflow_versions_id_fk",
"tableFrom": "deployments",
"tableTo": "workflow_versions",
"columnsFrom": [
"workflow_version_id"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
},
"deployments_workflow_id_workflows_id_fk": {
"name": "deployments_workflow_id_workflows_id_fk",
"tableFrom": "deployments",
"tableTo": "workflows",
"columnsFrom": [
"workflow_id"
],
"columnsTo": [
"id"
],
"onDelete": "cascade",
"onUpdate": "no action"
},
"deployments_machine_id_machines_id_fk": {
"name": "deployments_machine_id_machines_id_fk",
"tableFrom": "deployments",
"tableTo": "machines",
"columnsFrom": [
"machine_id"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {
"deployments_share_slug_unique": {
"name": "deployments_share_slug_unique",
"nullsNotDistinct": false,
"columns": [
"share_slug"
]
}
}
},
"machines": {
"name": "machines",
"schema": "comfyui_deploy",
"columns": {
"id": {
"name": "id",
"type": "uuid",
"primaryKey": true,
"notNull": true,
"default": "gen_random_uuid()"
},
"user_id": {
"name": "user_id",
"type": "text",
"primaryKey": false,
"notNull": true
},
"name": {
"name": "name",
"type": "text",
"primaryKey": false,
"notNull": true
},
"org_id": {
"name": "org_id",
"type": "text",
"primaryKey": false,
"notNull": false
},
"endpoint": {
"name": "endpoint",
"type": "text",
"primaryKey": false,
"notNull": true
},
"created_at": {
"name": "created_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"updated_at": {
"name": "updated_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"disabled": {
"name": "disabled",
"type": "boolean",
"primaryKey": false,
"notNull": true,
"default": false
},
"auth_token": {
"name": "auth_token",
"type": "text",
"primaryKey": false,
"notNull": false
},
"type": {
"name": "type",
"type": "machine_type",
"primaryKey": false,
"notNull": true,
"default": "'classic'"
},
"status": {
"name": "status",
"type": "machine_status",
"primaryKey": false,
"notNull": true,
"default": "'ready'"
},
"snapshot": {
"name": "snapshot",
"type": "jsonb",
"primaryKey": false,
"notNull": false
},
"models": {
"name": "models",
"type": "jsonb",
"primaryKey": false,
"notNull": false
},
"gpu": {
"name": "gpu",
"type": "machine_gpu",
"primaryKey": false,
"notNull": false
},
"build_machine_instance_id": {
"name": "build_machine_instance_id",
"type": "text",
"primaryKey": false,
"notNull": false
},
"build_log": {
"name": "build_log",
"type": "text",
"primaryKey": false,
"notNull": false
}
},
"indexes": {},
"foreignKeys": {
"machines_user_id_users_id_fk": {
"name": "machines_user_id_users_id_fk",
"tableFrom": "machines",
"tableTo": "users",
"columnsFrom": [
"user_id"
],
"columnsTo": [
"id"
],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {}
},
"subscription_status": {
"name": "subscription_status",
"schema": "comfyui_deploy",
"columns": {
"stripe_customer_id": {
"name": "stripe_customer_id",
"type": "text",
"primaryKey": true,
"notNull": true
},
"user_id": {
"name": "user_id",
"type": "text",
"primaryKey": false,
"notNull": false
},
"org_id": {
"name": "org_id",
"type": "text",
"primaryKey": false,
"notNull": false
},
"plan": {
"name": "plan",
"type": "subscription_plan",
"primaryKey": false,
"notNull": true
},
"status": {
"name": "status",
"type": "subscription_plan_status",
"primaryKey": false,
"notNull": true
},
"subscription_plan_id": {
"name": "subscription_plan_id",
"type": "text",
"primaryKey": false,
"notNull": false
},
"created_at": {
"name": "created_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"updated_at": {
"name": "updated_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {}
},
"user_usage": {
"name": "user_usage",
"schema": "comfyui_deploy",
"columns": {
"id": {
"name": "id",
"type": "uuid",
"primaryKey": true,
"notNull": true,
"default": "gen_random_uuid()"
},
"org_id": {
"name": "org_id",
"type": "text",
"primaryKey": false,
"notNull": false
},
"user_id": {
"name": "user_id",
"type": "text",
"primaryKey": false,
"notNull": true
},
"usage_time": {
"name": "usage_time",
"type": "real",
"primaryKey": false,
"notNull": true,
"default": 0
},
"created_at": {
"name": "created_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"ended_at": {
"name": "ended_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
}
},
"indexes": {},
"foreignKeys": {
"user_usage_user_id_users_id_fk": {
"name": "user_usage_user_id_users_id_fk",
"tableFrom": "user_usage",
"tableTo": "users",
"columnsFrom": [
"user_id"
],
"columnsTo": [
"id"
],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {}
},
"users": {
"name": "users",
"schema": "comfyui_deploy",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true
},
"username": {
"name": "username",
"type": "text",
"primaryKey": false,
"notNull": true
},
"name": {
"name": "name",
"type": "text",
"primaryKey": false,
"notNull": true
},
"created_at": {
"name": "created_at",
"type": "timestamp",
"primaryKey": false,
"notNull": false,
"default": "now()"
},
"updated_at": {
"name": "updated_at",
"type": "timestamp",
"primaryKey": false,
"notNull": false,
"default": "now()"
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {}
},
"workflow_run_outputs": {
"name": "workflow_run_outputs",
"schema": "comfyui_deploy",
"columns": {
"id": {
"name": "id",
"type": "uuid",
"primaryKey": true,
"notNull": true,
"default": "gen_random_uuid()"
},
"run_id": {
"name": "run_id",
"type": "uuid",
"primaryKey": false,
"notNull": true
},
"data": {
"name": "data",
"type": "jsonb",
"primaryKey": false,
"notNull": false
},
"created_at": {
"name": "created_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"updated_at": {
"name": "updated_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
}
},
"indexes": {},
"foreignKeys": {
"workflow_run_outputs_run_id_workflow_runs_id_fk": {
"name": "workflow_run_outputs_run_id_workflow_runs_id_fk",
"tableFrom": "workflow_run_outputs",
"tableTo": "workflow_runs",
"columnsFrom": [
"run_id"
],
"columnsTo": [
"id"
],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {}
},
"workflow_runs": {
"name": "workflow_runs",
"schema": "comfyui_deploy",
"columns": {
"id": {
"name": "id",
"type": "uuid",
"primaryKey": true,
"notNull": true,
"default": "gen_random_uuid()"
},
"workflow_version_id": {
"name": "workflow_version_id",
"type": "uuid",
"primaryKey": false,
"notNull": false
},
"workflow_inputs": {
"name": "workflow_inputs",
"type": "jsonb",
"primaryKey": false,
"notNull": false
},
"workflow_id": {
"name": "workflow_id",
"type": "uuid",
"primaryKey": false,
"notNull": true
},
"machine_id": {
"name": "machine_id",
"type": "uuid",
"primaryKey": false,
"notNull": false
},
"origin": {
"name": "origin",
"type": "workflow_run_origin",
"primaryKey": false,
"notNull": true,
"default": "'api'"
},
"status": {
"name": "status",
"type": "workflow_run_status",
"primaryKey": false,
"notNull": true,
"default": "'not-started'"
},
"ended_at": {
"name": "ended_at",
"type": "timestamp",
"primaryKey": false,
"notNull": false
},
"created_at": {
"name": "created_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"started_at": {
"name": "started_at",
"type": "timestamp",
"primaryKey": false,
"notNull": false
}
},
"indexes": {},
"foreignKeys": {
"workflow_runs_workflow_version_id_workflow_versions_id_fk": {
"name": "workflow_runs_workflow_version_id_workflow_versions_id_fk",
"tableFrom": "workflow_runs",
"tableTo": "workflow_versions",
"columnsFrom": [
"workflow_version_id"
],
"columnsTo": [
"id"
],
"onDelete": "set null",
"onUpdate": "no action"
},
"workflow_runs_workflow_id_workflows_id_fk": {
"name": "workflow_runs_workflow_id_workflows_id_fk",
"tableFrom": "workflow_runs",
"tableTo": "workflows",
"columnsFrom": [
"workflow_id"
],
"columnsTo": [
"id"
],
"onDelete": "cascade",
"onUpdate": "no action"
},
"workflow_runs_machine_id_machines_id_fk": {
"name": "workflow_runs_machine_id_machines_id_fk",
"tableFrom": "workflow_runs",
"tableTo": "machines",
"columnsFrom": [
"machine_id"
],
"columnsTo": [
"id"
],
"onDelete": "set null",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {}
},
"workflows": {
"name": "workflows",
"schema": "comfyui_deploy",
"columns": {
"id": {
"name": "id",
"type": "uuid",
"primaryKey": true,
"notNull": true,
"default": "gen_random_uuid()"
},
"user_id": {
"name": "user_id",
"type": "text",
"primaryKey": false,
"notNull": true
},
"org_id": {
"name": "org_id",
"type": "text",
"primaryKey": false,
"notNull": false
},
"name": {
"name": "name",
"type": "text",
"primaryKey": false,
"notNull": true
},
"created_at": {
"name": "created_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"updated_at": {
"name": "updated_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
}
},
"indexes": {},
"foreignKeys": {
"workflows_user_id_users_id_fk": {
"name": "workflows_user_id_users_id_fk",
"tableFrom": "workflows",
"tableTo": "users",
"columnsFrom": [
"user_id"
],
"columnsTo": [
"id"
],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {}
},
"workflow_versions": {
"name": "workflow_versions",
"schema": "comfyui_deploy",
"columns": {
"workflow_id": {
"name": "workflow_id",
"type": "uuid",
"primaryKey": false,
"notNull": true
},
"id": {
"name": "id",
"type": "uuid",
"primaryKey": true,
"notNull": true,
"default": "gen_random_uuid()"
},
"workflow": {
"name": "workflow",
"type": "jsonb",
"primaryKey": false,
"notNull": false
},
"workflow_api": {
"name": "workflow_api",
"type": "jsonb",
"primaryKey": false,
"notNull": false
},
"version": {
"name": "version",
"type": "integer",
"primaryKey": false,
"notNull": true
},
"snapshot": {
"name": "snapshot",
"type": "jsonb",
"primaryKey": false,
"notNull": false
},
"created_at": {
"name": "created_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"updated_at": {
"name": "updated_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
}
},
"indexes": {},
"foreignKeys": {
"workflow_versions_workflow_id_workflows_id_fk": {
"name": "workflow_versions_workflow_id_workflows_id_fk",
"tableFrom": "workflow_versions",
"tableTo": "workflows",
"columnsFrom": [
"workflow_id"
],
"columnsTo": [
"id"
],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {}
}
},
"enums": {
"deployment_environment": {
"name": "deployment_environment",
"values": {
"staging": "staging",
"production": "production",
"public-share": "public-share"
}
},
"machine_gpu": {
"name": "machine_gpu",
"values": {
"T4": "T4",
"A10G": "A10G",
"A100": "A100"
}
},
"machine_status": {
"name": "machine_status",
"values": {
"ready": "ready",
"building": "building",
"error": "error"
}
},
"machine_type": {
"name": "machine_type",
"values": {
"classic": "classic",
"runpod-serverless": "runpod-serverless",
"modal-serverless": "modal-serverless",
"comfy-deploy-serverless": "comfy-deploy-serverless"
}
},
"subscription_plan": {
"name": "subscription_plan",
"values": {
"basic": "basic",
"pro": "pro",
"enterprise": "enterprise"
}
},
"subscription_plan_status": {
"name": "subscription_plan_status",
"values": {
"active": "active",
"deleted": "deleted",
"paused": "paused"
}
},
"workflow_run_origin": {
"name": "workflow_run_origin",
"values": {
"manual": "manual",
"api": "api",
"public-share": "public-share"
}
},
"workflow_run_status": {
"name": "workflow_run_status",
"values": {
"not-started": "not-started",
"running": "running",
"uploading": "uploading",
"success": "success",
"failed": "failed"
}
}
},
"schemas": {
"comfyui_deploy": "comfyui_deploy"
},
"_meta": {
"schemas": {},
"tables": {},
"columns": {}
}
}

View File

@ -0,0 +1,984 @@
{
"id": "cde8f758-0055-4326-981d-293ac84db54a",
"prevId": "4db08fc3-2444-42da-b742-f1832ad8caf1",
"version": "5",
"dialect": "pg",
"tables": {
"api_keys": {
"name": "api_keys",
"schema": "comfyui_deploy",
"columns": {
"id": {
"name": "id",
"type": "uuid",
"primaryKey": true,
"notNull": true,
"default": "gen_random_uuid()"
},
"key": {
"name": "key",
"type": "text",
"primaryKey": false,
"notNull": true
},
"name": {
"name": "name",
"type": "text",
"primaryKey": false,
"notNull": true
},
"user_id": {
"name": "user_id",
"type": "text",
"primaryKey": false,
"notNull": true
},
"org_id": {
"name": "org_id",
"type": "text",
"primaryKey": false,
"notNull": false
},
"revoked": {
"name": "revoked",
"type": "boolean",
"primaryKey": false,
"notNull": true,
"default": false
},
"created_at": {
"name": "created_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"updated_at": {
"name": "updated_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
}
},
"indexes": {},
"foreignKeys": {
"api_keys_user_id_users_id_fk": {
"name": "api_keys_user_id_users_id_fk",
"tableFrom": "api_keys",
"tableTo": "users",
"columnsFrom": [
"user_id"
],
"columnsTo": [
"id"
],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {
"api_keys_key_unique": {
"name": "api_keys_key_unique",
"nullsNotDistinct": false,
"columns": [
"key"
]
}
}
},
"auth_requests": {
"name": "auth_requests",
"schema": "comfyui_deploy",
"columns": {
"request_id": {
"name": "request_id",
"type": "text",
"primaryKey": true,
"notNull": true
},
"user_id": {
"name": "user_id",
"type": "text",
"primaryKey": false,
"notNull": false
},
"org_id": {
"name": "org_id",
"type": "text",
"primaryKey": false,
"notNull": false
},
"api_hash": {
"name": "api_hash",
"type": "text",
"primaryKey": false,
"notNull": false
},
"created_at": {
"name": "created_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"expired_date": {
"name": "expired_date",
"type": "timestamp",
"primaryKey": false,
"notNull": false
},
"updated_at": {
"name": "updated_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {}
},
"deployments": {
"name": "deployments",
"schema": "comfyui_deploy",
"columns": {
"id": {
"name": "id",
"type": "uuid",
"primaryKey": true,
"notNull": true,
"default": "gen_random_uuid()"
},
"user_id": {
"name": "user_id",
"type": "text",
"primaryKey": false,
"notNull": true
},
"org_id": {
"name": "org_id",
"type": "text",
"primaryKey": false,
"notNull": false
},
"workflow_version_id": {
"name": "workflow_version_id",
"type": "uuid",
"primaryKey": false,
"notNull": true
},
"workflow_id": {
"name": "workflow_id",
"type": "uuid",
"primaryKey": false,
"notNull": true
},
"machine_id": {
"name": "machine_id",
"type": "uuid",
"primaryKey": false,
"notNull": true
},
"share_slug": {
"name": "share_slug",
"type": "text",
"primaryKey": false,
"notNull": false
},
"description": {
"name": "description",
"type": "text",
"primaryKey": false,
"notNull": false
},
"showcase_media": {
"name": "showcase_media",
"type": "jsonb",
"primaryKey": false,
"notNull": false
},
"environment": {
"name": "environment",
"type": "deployment_environment",
"primaryKey": false,
"notNull": true
},
"created_at": {
"name": "created_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"updated_at": {
"name": "updated_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
}
},
"indexes": {},
"foreignKeys": {
"deployments_user_id_users_id_fk": {
"name": "deployments_user_id_users_id_fk",
"tableFrom": "deployments",
"tableTo": "users",
"columnsFrom": [
"user_id"
],
"columnsTo": [
"id"
],
"onDelete": "cascade",
"onUpdate": "no action"
},
"deployments_workflow_version_id_workflow_versions_id_fk": {
"name": "deployments_workflow_version_id_workflow_versions_id_fk",
"tableFrom": "deployments",
"tableTo": "workflow_versions",
"columnsFrom": [
"workflow_version_id"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
},
"deployments_workflow_id_workflows_id_fk": {
"name": "deployments_workflow_id_workflows_id_fk",
"tableFrom": "deployments",
"tableTo": "workflows",
"columnsFrom": [
"workflow_id"
],
"columnsTo": [
"id"
],
"onDelete": "cascade",
"onUpdate": "no action"
},
"deployments_machine_id_machines_id_fk": {
"name": "deployments_machine_id_machines_id_fk",
"tableFrom": "deployments",
"tableTo": "machines",
"columnsFrom": [
"machine_id"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {
"deployments_share_slug_unique": {
"name": "deployments_share_slug_unique",
"nullsNotDistinct": false,
"columns": [
"share_slug"
]
}
}
},
"machines": {
"name": "machines",
"schema": "comfyui_deploy",
"columns": {
"id": {
"name": "id",
"type": "uuid",
"primaryKey": true,
"notNull": true,
"default": "gen_random_uuid()"
},
"user_id": {
"name": "user_id",
"type": "text",
"primaryKey": false,
"notNull": true
},
"name": {
"name": "name",
"type": "text",
"primaryKey": false,
"notNull": true
},
"org_id": {
"name": "org_id",
"type": "text",
"primaryKey": false,
"notNull": false
},
"endpoint": {
"name": "endpoint",
"type": "text",
"primaryKey": false,
"notNull": true
},
"created_at": {
"name": "created_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"updated_at": {
"name": "updated_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"disabled": {
"name": "disabled",
"type": "boolean",
"primaryKey": false,
"notNull": true,
"default": false
},
"auth_token": {
"name": "auth_token",
"type": "text",
"primaryKey": false,
"notNull": false
},
"type": {
"name": "type",
"type": "machine_type",
"primaryKey": false,
"notNull": true,
"default": "'classic'"
},
"status": {
"name": "status",
"type": "machine_status",
"primaryKey": false,
"notNull": true,
"default": "'ready'"
},
"snapshot": {
"name": "snapshot",
"type": "jsonb",
"primaryKey": false,
"notNull": false
},
"models": {
"name": "models",
"type": "jsonb",
"primaryKey": false,
"notNull": false
},
"gpu": {
"name": "gpu",
"type": "machine_gpu",
"primaryKey": false,
"notNull": false
},
"build_machine_instance_id": {
"name": "build_machine_instance_id",
"type": "text",
"primaryKey": false,
"notNull": false
},
"build_log": {
"name": "build_log",
"type": "text",
"primaryKey": false,
"notNull": false
}
},
"indexes": {},
"foreignKeys": {
"machines_user_id_users_id_fk": {
"name": "machines_user_id_users_id_fk",
"tableFrom": "machines",
"tableTo": "users",
"columnsFrom": [
"user_id"
],
"columnsTo": [
"id"
],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {}
},
"subscription_status": {
"name": "subscription_status",
"schema": "comfyui_deploy",
"columns": {
"stripe_customer_id": {
"name": "stripe_customer_id",
"type": "text",
"primaryKey": true,
"notNull": true
},
"user_id": {
"name": "user_id",
"type": "text",
"primaryKey": false,
"notNull": false
},
"org_id": {
"name": "org_id",
"type": "text",
"primaryKey": false,
"notNull": false
},
"plan": {
"name": "plan",
"type": "subscription_plan",
"primaryKey": false,
"notNull": true
},
"status": {
"name": "status",
"type": "subscription_plan_status",
"primaryKey": false,
"notNull": true
},
"subscription_id": {
"name": "subscription_id",
"type": "text",
"primaryKey": false,
"notNull": false
},
"subscription_item_plan_id": {
"name": "subscription_item_plan_id",
"type": "text",
"primaryKey": false,
"notNull": false
},
"subscription_item_api_id": {
"name": "subscription_item_api_id",
"type": "text",
"primaryKey": false,
"notNull": false
},
"created_at": {
"name": "created_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"updated_at": {
"name": "updated_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {}
},
"user_usage": {
"name": "user_usage",
"schema": "comfyui_deploy",
"columns": {
"id": {
"name": "id",
"type": "uuid",
"primaryKey": true,
"notNull": true,
"default": "gen_random_uuid()"
},
"org_id": {
"name": "org_id",
"type": "text",
"primaryKey": false,
"notNull": false
},
"user_id": {
"name": "user_id",
"type": "text",
"primaryKey": false,
"notNull": true
},
"usage_time": {
"name": "usage_time",
"type": "real",
"primaryKey": false,
"notNull": true,
"default": 0
},
"created_at": {
"name": "created_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"ended_at": {
"name": "ended_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
}
},
"indexes": {},
"foreignKeys": {
"user_usage_user_id_users_id_fk": {
"name": "user_usage_user_id_users_id_fk",
"tableFrom": "user_usage",
"tableTo": "users",
"columnsFrom": [
"user_id"
],
"columnsTo": [
"id"
],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {}
},
"users": {
"name": "users",
"schema": "comfyui_deploy",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true
},
"username": {
"name": "username",
"type": "text",
"primaryKey": false,
"notNull": true
},
"name": {
"name": "name",
"type": "text",
"primaryKey": false,
"notNull": true
},
"created_at": {
"name": "created_at",
"type": "timestamp",
"primaryKey": false,
"notNull": false,
"default": "now()"
},
"updated_at": {
"name": "updated_at",
"type": "timestamp",
"primaryKey": false,
"notNull": false,
"default": "now()"
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {}
},
"workflow_run_outputs": {
"name": "workflow_run_outputs",
"schema": "comfyui_deploy",
"columns": {
"id": {
"name": "id",
"type": "uuid",
"primaryKey": true,
"notNull": true,
"default": "gen_random_uuid()"
},
"run_id": {
"name": "run_id",
"type": "uuid",
"primaryKey": false,
"notNull": true
},
"data": {
"name": "data",
"type": "jsonb",
"primaryKey": false,
"notNull": false
},
"created_at": {
"name": "created_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"updated_at": {
"name": "updated_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
}
},
"indexes": {},
"foreignKeys": {
"workflow_run_outputs_run_id_workflow_runs_id_fk": {
"name": "workflow_run_outputs_run_id_workflow_runs_id_fk",
"tableFrom": "workflow_run_outputs",
"tableTo": "workflow_runs",
"columnsFrom": [
"run_id"
],
"columnsTo": [
"id"
],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {}
},
"workflow_runs": {
"name": "workflow_runs",
"schema": "comfyui_deploy",
"columns": {
"id": {
"name": "id",
"type": "uuid",
"primaryKey": true,
"notNull": true,
"default": "gen_random_uuid()"
},
"workflow_version_id": {
"name": "workflow_version_id",
"type": "uuid",
"primaryKey": false,
"notNull": false
},
"workflow_inputs": {
"name": "workflow_inputs",
"type": "jsonb",
"primaryKey": false,
"notNull": false
},
"workflow_id": {
"name": "workflow_id",
"type": "uuid",
"primaryKey": false,
"notNull": true
},
"machine_id": {
"name": "machine_id",
"type": "uuid",
"primaryKey": false,
"notNull": false
},
"origin": {
"name": "origin",
"type": "workflow_run_origin",
"primaryKey": false,
"notNull": true,
"default": "'api'"
},
"status": {
"name": "status",
"type": "workflow_run_status",
"primaryKey": false,
"notNull": true,
"default": "'not-started'"
},
"ended_at": {
"name": "ended_at",
"type": "timestamp",
"primaryKey": false,
"notNull": false
},
"created_at": {
"name": "created_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"started_at": {
"name": "started_at",
"type": "timestamp",
"primaryKey": false,
"notNull": false
}
},
"indexes": {},
"foreignKeys": {
"workflow_runs_workflow_version_id_workflow_versions_id_fk": {
"name": "workflow_runs_workflow_version_id_workflow_versions_id_fk",
"tableFrom": "workflow_runs",
"tableTo": "workflow_versions",
"columnsFrom": [
"workflow_version_id"
],
"columnsTo": [
"id"
],
"onDelete": "set null",
"onUpdate": "no action"
},
"workflow_runs_workflow_id_workflows_id_fk": {
"name": "workflow_runs_workflow_id_workflows_id_fk",
"tableFrom": "workflow_runs",
"tableTo": "workflows",
"columnsFrom": [
"workflow_id"
],
"columnsTo": [
"id"
],
"onDelete": "cascade",
"onUpdate": "no action"
},
"workflow_runs_machine_id_machines_id_fk": {
"name": "workflow_runs_machine_id_machines_id_fk",
"tableFrom": "workflow_runs",
"tableTo": "machines",
"columnsFrom": [
"machine_id"
],
"columnsTo": [
"id"
],
"onDelete": "set null",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {}
},
"workflows": {
"name": "workflows",
"schema": "comfyui_deploy",
"columns": {
"id": {
"name": "id",
"type": "uuid",
"primaryKey": true,
"notNull": true,
"default": "gen_random_uuid()"
},
"user_id": {
"name": "user_id",
"type": "text",
"primaryKey": false,
"notNull": true
},
"org_id": {
"name": "org_id",
"type": "text",
"primaryKey": false,
"notNull": false
},
"name": {
"name": "name",
"type": "text",
"primaryKey": false,
"notNull": true
},
"created_at": {
"name": "created_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"updated_at": {
"name": "updated_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
}
},
"indexes": {},
"foreignKeys": {
"workflows_user_id_users_id_fk": {
"name": "workflows_user_id_users_id_fk",
"tableFrom": "workflows",
"tableTo": "users",
"columnsFrom": [
"user_id"
],
"columnsTo": [
"id"
],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {}
},
"workflow_versions": {
"name": "workflow_versions",
"schema": "comfyui_deploy",
"columns": {
"workflow_id": {
"name": "workflow_id",
"type": "uuid",
"primaryKey": false,
"notNull": true
},
"id": {
"name": "id",
"type": "uuid",
"primaryKey": true,
"notNull": true,
"default": "gen_random_uuid()"
},
"workflow": {
"name": "workflow",
"type": "jsonb",
"primaryKey": false,
"notNull": false
},
"workflow_api": {
"name": "workflow_api",
"type": "jsonb",
"primaryKey": false,
"notNull": false
},
"version": {
"name": "version",
"type": "integer",
"primaryKey": false,
"notNull": true
},
"snapshot": {
"name": "snapshot",
"type": "jsonb",
"primaryKey": false,
"notNull": false
},
"created_at": {
"name": "created_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"updated_at": {
"name": "updated_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
}
},
"indexes": {},
"foreignKeys": {
"workflow_versions_workflow_id_workflows_id_fk": {
"name": "workflow_versions_workflow_id_workflows_id_fk",
"tableFrom": "workflow_versions",
"tableTo": "workflows",
"columnsFrom": [
"workflow_id"
],
"columnsTo": [
"id"
],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {}
}
},
"enums": {
"deployment_environment": {
"name": "deployment_environment",
"values": {
"staging": "staging",
"production": "production",
"public-share": "public-share"
}
},
"machine_gpu": {
"name": "machine_gpu",
"values": {
"T4": "T4",
"A10G": "A10G",
"A100": "A100"
}
},
"machine_status": {
"name": "machine_status",
"values": {
"ready": "ready",
"building": "building",
"error": "error"
}
},
"machine_type": {
"name": "machine_type",
"values": {
"classic": "classic",
"runpod-serverless": "runpod-serverless",
"modal-serverless": "modal-serverless",
"comfy-deploy-serverless": "comfy-deploy-serverless"
}
},
"subscription_plan": {
"name": "subscription_plan",
"values": {
"basic": "basic",
"pro": "pro",
"enterprise": "enterprise"
}
},
"subscription_plan_status": {
"name": "subscription_plan_status",
"values": {
"active": "active",
"deleted": "deleted",
"paused": "paused"
}
},
"workflow_run_origin": {
"name": "workflow_run_origin",
"values": {
"manual": "manual",
"api": "api",
"public-share": "public-share"
}
},
"workflow_run_status": {
"name": "workflow_run_status",
"values": {
"not-started": "not-started",
"running": "running",
"uploading": "uploading",
"success": "success",
"failed": "failed"
}
}
},
"schemas": {
"comfyui_deploy": "comfyui_deploy"
},
"_meta": {
"schemas": {},
"tables": {},
"columns": {
"\"comfyui_deploy\".\"subscription_status\".\"subscription_plan_id\"": "\"comfyui_deploy\".\"subscription_status\".\"subscription_id\""
}
}
}

View File

@ -0,0 +1,989 @@
{
"id": "bd893271-b9ea-4832-a3e8-a6970b9f20d9",
"prevId": "cde8f758-0055-4326-981d-293ac84db54a",
"version": "5",
"dialect": "pg",
"tables": {
"api_keys": {
"name": "api_keys",
"schema": "comfyui_deploy",
"columns": {
"id": {
"name": "id",
"type": "uuid",
"primaryKey": true,
"notNull": true,
"default": "gen_random_uuid()"
},
"key": {
"name": "key",
"type": "text",
"primaryKey": false,
"notNull": true
},
"name": {
"name": "name",
"type": "text",
"primaryKey": false,
"notNull": true
},
"user_id": {
"name": "user_id",
"type": "text",
"primaryKey": false,
"notNull": true
},
"org_id": {
"name": "org_id",
"type": "text",
"primaryKey": false,
"notNull": false
},
"revoked": {
"name": "revoked",
"type": "boolean",
"primaryKey": false,
"notNull": true,
"default": false
},
"created_at": {
"name": "created_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"updated_at": {
"name": "updated_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
}
},
"indexes": {},
"foreignKeys": {
"api_keys_user_id_users_id_fk": {
"name": "api_keys_user_id_users_id_fk",
"tableFrom": "api_keys",
"tableTo": "users",
"columnsFrom": [
"user_id"
],
"columnsTo": [
"id"
],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {
"api_keys_key_unique": {
"name": "api_keys_key_unique",
"nullsNotDistinct": false,
"columns": [
"key"
]
}
}
},
"auth_requests": {
"name": "auth_requests",
"schema": "comfyui_deploy",
"columns": {
"request_id": {
"name": "request_id",
"type": "text",
"primaryKey": true,
"notNull": true
},
"user_id": {
"name": "user_id",
"type": "text",
"primaryKey": false,
"notNull": false
},
"org_id": {
"name": "org_id",
"type": "text",
"primaryKey": false,
"notNull": false
},
"api_hash": {
"name": "api_hash",
"type": "text",
"primaryKey": false,
"notNull": false
},
"created_at": {
"name": "created_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"expired_date": {
"name": "expired_date",
"type": "timestamp",
"primaryKey": false,
"notNull": false
},
"updated_at": {
"name": "updated_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {}
},
"deployments": {
"name": "deployments",
"schema": "comfyui_deploy",
"columns": {
"id": {
"name": "id",
"type": "uuid",
"primaryKey": true,
"notNull": true,
"default": "gen_random_uuid()"
},
"user_id": {
"name": "user_id",
"type": "text",
"primaryKey": false,
"notNull": true
},
"org_id": {
"name": "org_id",
"type": "text",
"primaryKey": false,
"notNull": false
},
"workflow_version_id": {
"name": "workflow_version_id",
"type": "uuid",
"primaryKey": false,
"notNull": true
},
"workflow_id": {
"name": "workflow_id",
"type": "uuid",
"primaryKey": false,
"notNull": true
},
"machine_id": {
"name": "machine_id",
"type": "uuid",
"primaryKey": false,
"notNull": true
},
"share_slug": {
"name": "share_slug",
"type": "text",
"primaryKey": false,
"notNull": false
},
"description": {
"name": "description",
"type": "text",
"primaryKey": false,
"notNull": false
},
"showcase_media": {
"name": "showcase_media",
"type": "jsonb",
"primaryKey": false,
"notNull": false
},
"environment": {
"name": "environment",
"type": "deployment_environment",
"primaryKey": false,
"notNull": true
},
"created_at": {
"name": "created_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"updated_at": {
"name": "updated_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
}
},
"indexes": {},
"foreignKeys": {
"deployments_user_id_users_id_fk": {
"name": "deployments_user_id_users_id_fk",
"tableFrom": "deployments",
"tableTo": "users",
"columnsFrom": [
"user_id"
],
"columnsTo": [
"id"
],
"onDelete": "cascade",
"onUpdate": "no action"
},
"deployments_workflow_version_id_workflow_versions_id_fk": {
"name": "deployments_workflow_version_id_workflow_versions_id_fk",
"tableFrom": "deployments",
"tableTo": "workflow_versions",
"columnsFrom": [
"workflow_version_id"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
},
"deployments_workflow_id_workflows_id_fk": {
"name": "deployments_workflow_id_workflows_id_fk",
"tableFrom": "deployments",
"tableTo": "workflows",
"columnsFrom": [
"workflow_id"
],
"columnsTo": [
"id"
],
"onDelete": "cascade",
"onUpdate": "no action"
},
"deployments_machine_id_machines_id_fk": {
"name": "deployments_machine_id_machines_id_fk",
"tableFrom": "deployments",
"tableTo": "machines",
"columnsFrom": [
"machine_id"
],
"columnsTo": [
"id"
],
"onDelete": "no action",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {
"deployments_share_slug_unique": {
"name": "deployments_share_slug_unique",
"nullsNotDistinct": false,
"columns": [
"share_slug"
]
}
}
},
"machines": {
"name": "machines",
"schema": "comfyui_deploy",
"columns": {
"id": {
"name": "id",
"type": "uuid",
"primaryKey": true,
"notNull": true,
"default": "gen_random_uuid()"
},
"user_id": {
"name": "user_id",
"type": "text",
"primaryKey": false,
"notNull": true
},
"name": {
"name": "name",
"type": "text",
"primaryKey": false,
"notNull": true
},
"org_id": {
"name": "org_id",
"type": "text",
"primaryKey": false,
"notNull": false
},
"endpoint": {
"name": "endpoint",
"type": "text",
"primaryKey": false,
"notNull": true
},
"created_at": {
"name": "created_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"updated_at": {
"name": "updated_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"disabled": {
"name": "disabled",
"type": "boolean",
"primaryKey": false,
"notNull": true,
"default": false
},
"auth_token": {
"name": "auth_token",
"type": "text",
"primaryKey": false,
"notNull": false
},
"type": {
"name": "type",
"type": "machine_type",
"primaryKey": false,
"notNull": true,
"default": "'classic'"
},
"status": {
"name": "status",
"type": "machine_status",
"primaryKey": false,
"notNull": true,
"default": "'ready'"
},
"snapshot": {
"name": "snapshot",
"type": "jsonb",
"primaryKey": false,
"notNull": false
},
"models": {
"name": "models",
"type": "jsonb",
"primaryKey": false,
"notNull": false
},
"gpu": {
"name": "gpu",
"type": "machine_gpu",
"primaryKey": false,
"notNull": false
},
"build_machine_instance_id": {
"name": "build_machine_instance_id",
"type": "text",
"primaryKey": false,
"notNull": false
},
"build_log": {
"name": "build_log",
"type": "text",
"primaryKey": false,
"notNull": false
}
},
"indexes": {},
"foreignKeys": {
"machines_user_id_users_id_fk": {
"name": "machines_user_id_users_id_fk",
"tableFrom": "machines",
"tableTo": "users",
"columnsFrom": [
"user_id"
],
"columnsTo": [
"id"
],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {}
},
"subscription_status": {
"name": "subscription_status",
"schema": "comfyui_deploy",
"columns": {
"stripe_customer_id": {
"name": "stripe_customer_id",
"type": "text",
"primaryKey": true,
"notNull": true
},
"user_id": {
"name": "user_id",
"type": "text",
"primaryKey": false,
"notNull": false
},
"org_id": {
"name": "org_id",
"type": "text",
"primaryKey": false,
"notNull": false
},
"plan": {
"name": "plan",
"type": "subscription_plan",
"primaryKey": false,
"notNull": true
},
"status": {
"name": "status",
"type": "subscription_plan_status",
"primaryKey": false,
"notNull": true
},
"subscription_id": {
"name": "subscription_id",
"type": "text",
"primaryKey": false,
"notNull": false
},
"subscription_item_plan_id": {
"name": "subscription_item_plan_id",
"type": "text",
"primaryKey": false,
"notNull": false
},
"subscription_item_api_id": {
"name": "subscription_item_api_id",
"type": "text",
"primaryKey": false,
"notNull": false
},
"cancel_at_period_end": {
"name": "cancel_at_period_end",
"type": "boolean",
"primaryKey": false,
"notNull": false,
"default": false
},
"created_at": {
"name": "created_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"updated_at": {
"name": "updated_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {}
},
"user_usage": {
"name": "user_usage",
"schema": "comfyui_deploy",
"columns": {
"id": {
"name": "id",
"type": "uuid",
"primaryKey": true,
"notNull": true,
"default": "gen_random_uuid()"
},
"org_id": {
"name": "org_id",
"type": "text",
"primaryKey": false,
"notNull": false
},
"user_id": {
"name": "user_id",
"type": "text",
"primaryKey": false,
"notNull": true
},
"usage_time": {
"name": "usage_time",
"type": "real",
"primaryKey": false,
"notNull": true,
"default": 0
},
"created_at": {
"name": "created_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"ended_at": {
"name": "ended_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
}
},
"indexes": {},
"foreignKeys": {
"user_usage_user_id_users_id_fk": {
"name": "user_usage_user_id_users_id_fk",
"tableFrom": "user_usage",
"tableTo": "users",
"columnsFrom": [
"user_id"
],
"columnsTo": [
"id"
],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {}
},
"users": {
"name": "users",
"schema": "comfyui_deploy",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true
},
"username": {
"name": "username",
"type": "text",
"primaryKey": false,
"notNull": true
},
"name": {
"name": "name",
"type": "text",
"primaryKey": false,
"notNull": true
},
"created_at": {
"name": "created_at",
"type": "timestamp",
"primaryKey": false,
"notNull": false,
"default": "now()"
},
"updated_at": {
"name": "updated_at",
"type": "timestamp",
"primaryKey": false,
"notNull": false,
"default": "now()"
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {}
},
"workflow_run_outputs": {
"name": "workflow_run_outputs",
"schema": "comfyui_deploy",
"columns": {
"id": {
"name": "id",
"type": "uuid",
"primaryKey": true,
"notNull": true,
"default": "gen_random_uuid()"
},
"run_id": {
"name": "run_id",
"type": "uuid",
"primaryKey": false,
"notNull": true
},
"data": {
"name": "data",
"type": "jsonb",
"primaryKey": false,
"notNull": false
},
"created_at": {
"name": "created_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"updated_at": {
"name": "updated_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
}
},
"indexes": {},
"foreignKeys": {
"workflow_run_outputs_run_id_workflow_runs_id_fk": {
"name": "workflow_run_outputs_run_id_workflow_runs_id_fk",
"tableFrom": "workflow_run_outputs",
"tableTo": "workflow_runs",
"columnsFrom": [
"run_id"
],
"columnsTo": [
"id"
],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {}
},
"workflow_runs": {
"name": "workflow_runs",
"schema": "comfyui_deploy",
"columns": {
"id": {
"name": "id",
"type": "uuid",
"primaryKey": true,
"notNull": true,
"default": "gen_random_uuid()"
},
"workflow_version_id": {
"name": "workflow_version_id",
"type": "uuid",
"primaryKey": false,
"notNull": false
},
"workflow_inputs": {
"name": "workflow_inputs",
"type": "jsonb",
"primaryKey": false,
"notNull": false
},
"workflow_id": {
"name": "workflow_id",
"type": "uuid",
"primaryKey": false,
"notNull": true
},
"machine_id": {
"name": "machine_id",
"type": "uuid",
"primaryKey": false,
"notNull": false
},
"origin": {
"name": "origin",
"type": "workflow_run_origin",
"primaryKey": false,
"notNull": true,
"default": "'api'"
},
"status": {
"name": "status",
"type": "workflow_run_status",
"primaryKey": false,
"notNull": true,
"default": "'not-started'"
},
"ended_at": {
"name": "ended_at",
"type": "timestamp",
"primaryKey": false,
"notNull": false
},
"created_at": {
"name": "created_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"started_at": {
"name": "started_at",
"type": "timestamp",
"primaryKey": false,
"notNull": false
}
},
"indexes": {},
"foreignKeys": {
"workflow_runs_workflow_version_id_workflow_versions_id_fk": {
"name": "workflow_runs_workflow_version_id_workflow_versions_id_fk",
"tableFrom": "workflow_runs",
"tableTo": "workflow_versions",
"columnsFrom": [
"workflow_version_id"
],
"columnsTo": [
"id"
],
"onDelete": "set null",
"onUpdate": "no action"
},
"workflow_runs_workflow_id_workflows_id_fk": {
"name": "workflow_runs_workflow_id_workflows_id_fk",
"tableFrom": "workflow_runs",
"tableTo": "workflows",
"columnsFrom": [
"workflow_id"
],
"columnsTo": [
"id"
],
"onDelete": "cascade",
"onUpdate": "no action"
},
"workflow_runs_machine_id_machines_id_fk": {
"name": "workflow_runs_machine_id_machines_id_fk",
"tableFrom": "workflow_runs",
"tableTo": "machines",
"columnsFrom": [
"machine_id"
],
"columnsTo": [
"id"
],
"onDelete": "set null",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {}
},
"workflows": {
"name": "workflows",
"schema": "comfyui_deploy",
"columns": {
"id": {
"name": "id",
"type": "uuid",
"primaryKey": true,
"notNull": true,
"default": "gen_random_uuid()"
},
"user_id": {
"name": "user_id",
"type": "text",
"primaryKey": false,
"notNull": true
},
"org_id": {
"name": "org_id",
"type": "text",
"primaryKey": false,
"notNull": false
},
"name": {
"name": "name",
"type": "text",
"primaryKey": false,
"notNull": true
},
"created_at": {
"name": "created_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"updated_at": {
"name": "updated_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
}
},
"indexes": {},
"foreignKeys": {
"workflows_user_id_users_id_fk": {
"name": "workflows_user_id_users_id_fk",
"tableFrom": "workflows",
"tableTo": "users",
"columnsFrom": [
"user_id"
],
"columnsTo": [
"id"
],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {}
},
"workflow_versions": {
"name": "workflow_versions",
"schema": "comfyui_deploy",
"columns": {
"workflow_id": {
"name": "workflow_id",
"type": "uuid",
"primaryKey": false,
"notNull": true
},
"id": {
"name": "id",
"type": "uuid",
"primaryKey": true,
"notNull": true,
"default": "gen_random_uuid()"
},
"workflow": {
"name": "workflow",
"type": "jsonb",
"primaryKey": false,
"notNull": false
},
"workflow_api": {
"name": "workflow_api",
"type": "jsonb",
"primaryKey": false,
"notNull": false
},
"version": {
"name": "version",
"type": "integer",
"primaryKey": false,
"notNull": true
},
"snapshot": {
"name": "snapshot",
"type": "jsonb",
"primaryKey": false,
"notNull": false
},
"created_at": {
"name": "created_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"updated_at": {
"name": "updated_at",
"type": "timestamp",
"primaryKey": false,
"notNull": true,
"default": "now()"
}
},
"indexes": {},
"foreignKeys": {
"workflow_versions_workflow_id_workflows_id_fk": {
"name": "workflow_versions_workflow_id_workflows_id_fk",
"tableFrom": "workflow_versions",
"tableTo": "workflows",
"columnsFrom": [
"workflow_id"
],
"columnsTo": [
"id"
],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {}
}
},
"enums": {
"deployment_environment": {
"name": "deployment_environment",
"values": {
"staging": "staging",
"production": "production",
"public-share": "public-share"
}
},
"machine_gpu": {
"name": "machine_gpu",
"values": {
"T4": "T4",
"A10G": "A10G",
"A100": "A100"
}
},
"machine_status": {
"name": "machine_status",
"values": {
"ready": "ready",
"building": "building",
"error": "error"
}
},
"machine_type": {
"name": "machine_type",
"values": {
"classic": "classic",
"runpod-serverless": "runpod-serverless",
"modal-serverless": "modal-serverless",
"comfy-deploy-serverless": "comfy-deploy-serverless"
}
},
"subscription_plan": {
"name": "subscription_plan",
"values": {
"basic": "basic",
"pro": "pro",
"enterprise": "enterprise"
}
},
"subscription_plan_status": {
"name": "subscription_plan_status",
"values": {
"active": "active",
"deleted": "deleted",
"paused": "paused"
}
},
"workflow_run_origin": {
"name": "workflow_run_origin",
"values": {
"manual": "manual",
"api": "api",
"public-share": "public-share"
}
},
"workflow_run_status": {
"name": "workflow_run_status",
"values": {
"not-started": "not-started",
"running": "running",
"uploading": "uploading",
"success": "success",
"failed": "failed"
}
}
},
"schemas": {
"comfyui_deploy": "comfyui_deploy"
},
"_meta": {
"schemas": {},
"tables": {},
"columns": {}
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -246,6 +246,55 @@
"when": 1705902960991,
"tag": "0034_even_lady_ursula",
"breakpoints": true
},
{
"idx": 35,
"version": "5",
"when": 1705981452482,
"tag": "0035_fearless_golden_guardian",
"breakpoints": true
},
{
"idx": 36,
"version": "5",
"when": 1706081335387,
"tag": "0036_flippant_meltdown",
"breakpoints": true
},
{
"idx": 37,
"version": "5",
"when": 1706086271525,
"tag": "0037_eager_cyclops",
"breakpoints": true
},
{
"idx": 38,
"version": "5",
"when": 1706095853896,
"tag": "0038_yummy_darkhawk",
"breakpoints": true
},
{
"idx": 39,
"version": "5",
"when": 1706109812261,
"tag": "0039_nostalgic_lyja",
"breakpoints": true
},
{
"idx": 40,
"version": "5",
"when": 1706110859352,
"tag": "0040_salty_archangel",
"breakpoints": true
},
{
"idx": 41,
"version": "5",
"when": 1706111421524,
"tag": "0041_thick_norrin_radd",
"breakpoints": true
}
]
}
}

View File

@ -37,6 +37,7 @@
"@radix-ui/react-dropdown-menu": "^2.0.6",
"@radix-ui/react-label": "^2.0.2",
"@radix-ui/react-popover": "^1.0.7",
"@radix-ui/react-progress": "^1.0.3",
"@radix-ui/react-radio-group": "^1.1.3",
"@radix-ui/react-scroll-area": "^1.0.5",
"@radix-ui/react-select": "^2.0.0",
@ -47,6 +48,7 @@
"@radix-ui/react-toggle": "^1.0.3",
"@radix-ui/react-tooltip": "^1.0.7",
"@sindresorhus/slugify": "^2.2.1",
"@stripe/stripe-js": "^2.4.0",
"@tailwindcss/typography": "^0.5.10",
"@tanstack/react-table": "^8.10.7",
"@tanstack/react-virtual": "beta",
@ -95,6 +97,7 @@
"shikiji": "^0.9.3",
"simple-functional-loader": "^1.2.1",
"sonner": "^1.2.4",
"stripe": "^14.13.0",
"swagger-ui-react": "^5.11.0",
"swr": "^2.2.4",
"tailwind-merge": "^2.1.0",

View File

@ -0,0 +1,175 @@
import { auth, clerkClient } from "@clerk/nextjs";
import { headers } from "next/headers";
import { redirect } from "next/navigation";
import { stripe } from "../../../../../server/stripe";
import { NextResponse } from "next/server";
import { db } from "@/db/db";
import { subscriptionStatusTable } from "@/db/schema";
import { eq } from "drizzle-orm";
const secret = process.env.STRIPE_WEBHOOK_SECRET || "";
export async function POST(req: Request) {
try {
const body = await req.text();
const signature = headers().get("stripe-signature");
if (!signature)
return new NextResponse("Signature not found.", {
status: 500,
});
const event = stripe.webhooks.constructEvent(body, signature, secret);
console.log(event);
if (event.type === "checkout.session.completed") {
if (!event.data.object.customer_details?.email) {
throw new Error(`missing user email, ${event.id}`);
}
const userId = event.data.object.metadata?.userId;
const plan = event.data.object.metadata?.plan;
if (!userId) {
throw new Error(`missing itinerary_id on metadata, ${event.id}`);
}
if (!plan) {
throw new Error(`missing plan on metadata, ${event.id}`);
}
const orgId = event.data.object.metadata?.orgId;
const customerId =
typeof event.data.object.customer == "string"
? event.data.object.customer
: event.data.object.customer?.id;
const subscriptionId =
typeof event.data.object.subscription == "string"
? event.data.object.subscription
: event.data.object.subscription?.id;
if (!customerId) {
throw new Error(`missing customerId, ${event.id}`);
}
if (!subscriptionId) {
throw new Error(`missing subscriptionId, ${event.id}`);
}
const items = await stripe.subscriptionItems.list({
subscription: subscriptionId,
limit: 5,
});
// getting the subscription item id for the api plan
const subscription_item_api_id = items.data.find(
(x) => x.price.id === process.env.STRIPE_PR_API,
)?.id;
// the plan could be either pro or enterprise
const subscription_item_plan_id =
items.data.find((x) => x.price.id === process.env.STRIPE_PR_PRO)?.id ??
items.data.find((x) => x.price.id === process.env.STRIPE_PR_ENTERPRISE)
?.id;
if (!subscription_item_api_id) {
throw new Error(
`missing plan on subscription_item_api_id, ${event.id}`,
);
}
if (!subscription_item_plan_id) {
throw new Error(
`missing plan on subscription_item_plan_id, ${event.id}`,
);
}
console.log(items);
await db
.insert(subscriptionStatusTable)
.values({
stripe_customer_id: customerId,
org_id: orgId,
user_id: userId,
subscription_id: subscriptionId,
plan: plan as "pro" | "enterprise" | "basic",
status: "active",
subscription_item_api_id: subscription_item_api_id,
subscription_item_plan_id: subscription_item_plan_id,
})
.onConflictDoNothing();
// updateDatabase(event.data.object.metadata.itinerary_id);
// sendEmail(event.data.object.customer_details.email);
} else if (event.type === "customer.subscription.paused") {
const customerId =
typeof event.data.object.customer == "string"
? event.data.object.customer
: event.data.object.customer?.id;
if (!customerId) {
throw new Error(`missing customerId, ${event.id}`);
}
await db
.update(subscriptionStatusTable)
.set({ status: "paused" })
.where(eq(subscriptionStatusTable.stripe_customer_id, customerId));
} else if (event.type === "customer.subscription.resumed") {
const customerId =
typeof event.data.object.customer == "string"
? event.data.object.customer
: event.data.object.customer?.id;
if (!customerId) {
throw new Error(`missing customerId, ${event.id}`);
}
await db
.update(subscriptionStatusTable)
.set({ status: "active" })
.where(eq(subscriptionStatusTable.stripe_customer_id, customerId));
} else if (event.type === "customer.subscription.deleted") {
const customerId =
typeof event.data.object.customer == "string"
? event.data.object.customer
: event.data.object.customer?.id;
if (!customerId) {
throw new Error(`missing customerId, ${event.id}`);
}
await db
.update(subscriptionStatusTable)
.set({ status: "deleted" })
.where(eq(subscriptionStatusTable.stripe_customer_id, customerId));
} else if (event.type === "customer.subscription.updated") {
const customerId =
typeof event.data.object.customer == "string"
? event.data.object.customer
: event.data.object.customer?.id;
if (!customerId) {
throw new Error(`missing customerId, ${event.id}`);
}
const cancel_at_period_end = event.data.object.cancel_at_period_end;
await db
.update(subscriptionStatusTable)
.set({ cancel_at_period_end: cancel_at_period_end })
.where(eq(subscriptionStatusTable.stripe_customer_id, customerId));
}
return NextResponse.json({ result: event, ok: true });
} catch (error) {
console.error(error);
return NextResponse.json(
{
message: `Something went wrong: ${error}`,
ok: false,
},
{ status: 500 },
);
}
}

View File

@ -0,0 +1,46 @@
import { stripe } from "@/server/stripe";
import { createCheckout } from "@/server/linkToPricing";
import { auth, clerkClient } from "@clerk/nextjs";
import { redirect } from "next/navigation";
import { getUrlServerSide } from "@/server/getUrlServerSide";
export async function GET(req: Request) {
const { userId, orgId } = auth();
const plan = new URL(req.url).searchParams.get("plan");
if (!userId) return redirect("/");
if (!plan) return redirect("/pricing");
const user = await clerkClient.users.getUser(userId);
const mapping = {
pro: process.env.STRIPE_PR_PRO,
enterprise: process.env.STRIPE_PR_ENTERPRISE,
};
const api = process.env.STRIPE_PR_API;
const session = await stripe.checkout.sessions.create({
success_url: getUrlServerSide(),
line_items: [
{
price: mapping[plan as "pro" | "enterprise"],
quantity: 1,
},
{
price: api,
},
],
metadata: {
userId: userId,
orgId: orgId ?? null,
plan: plan,
},
client_reference_id: orgId ?? userId,
customer_email: user.emailAddresses[0].emailAddress,
mode: "subscription",
});
if (session.url) redirect(session.url);
}

View File

@ -0,0 +1,41 @@
import { stripe } from "@/server/stripe";
import { createCheckout } from "@/server/linkToPricing";
import { auth, clerkClient } from "@clerk/nextjs";
import { redirect } from "next/navigation";
import { getUrlServerSide } from "@/server/getUrlServerSide";
import { db } from "@/db/db";
import { and, eq, isNull } from "drizzle-orm";
import { subscriptionStatusTable } from "@/db/schema";
import { getCurrentPlan } from "@/server/getCurrentPlan";
export async function GET(req: Request) {
const { userId, orgId } = auth();
if (!userId) return redirect("/");
const change = new URL(req.url).searchParams.get("change");
const sub = await getCurrentPlan({
org_id: orgId,
user_id: userId,
});
if (!sub) return redirect("/pricing");
const session = await stripe.billingPortal.sessions.create({
customer: sub.stripe_customer_id,
return_url: getUrlServerSide() + "/pricing",
// flow_data:
// change === "true" && sub.subscription_id
// ? {
// type: "subscription_update",
// subscription_update: {
// subscription: sub.subscription_id,
// },
// }
// : undefined,
});
redirect(session.url);
// if (session.url) redirect(session.url);
}

View File

@ -6,8 +6,8 @@ import {
workflowRunsTable,
workflowTable,
} from "@/db/schema";
import { getDuration } from "@/lib/getRelativeTime";
import { getSubscription, setUsage } from "@/server/linkToPricing";
import { getCurrentPlan } from "@/server/getCurrentPlan";
import { stripe } from "@/server/stripe";
import { eq } from "drizzle-orm";
import { NextResponse } from "next/server";
import { z } from "zod";
@ -34,21 +34,51 @@ export async function POST(request: Request) {
data: output_data,
});
} else if (status) {
const workflow_run = await db
const [workflow_run] = await db
.update(workflowRunsTable)
.set({
status: status,
ended_at:
status === "success" || status === "failed" ? new Date() : null,
})
.where(eq(workflowRunsTable.id, run_id));
.where(eq(workflowRunsTable.id, run_id))
.returning();
// get data from workflowRunsTable
const userUsageTime = await importUserUsageData(run_id);
// Need to filter out only comfy deploy serverless
// Also multiply with the gpu selection
if (workflow_run.machine_type == "comfy-deploy-serverless") {
if (
(status === "success" || status === "failed") &&
workflow_run.user_id
) {
const sub = await getCurrentPlan({
user_id: workflow_run.user_id,
org_id: workflow_run.org_id,
});
if (userUsageTime) {
// get the usage_time from userUsage
await addSubscriptionUnit(userUsageTime);
if (sub && sub.subscription_item_api_id && workflow_run.ended_at) {
let durationInSec = Math.abs(
(workflow_run.ended_at.getTime() -
workflow_run.created_at.getTime()) /
1000,
);
durationInSec = Math.ceil(durationInSec);
switch (workflow_run.gpu) {
case "A100":
durationInSec *= 7;
break;
case "A10G":
durationInSec *= 4;
break;
}
await stripe.subscriptionItems.createUsageRecord(
sub.subscription_item_api_id,
{
quantity: durationInSec,
},
);
}
}
}
}
@ -64,50 +94,6 @@ export async function POST(request: Request) {
},
{
status: 200,
}
},
);
}
async function addSubscriptionUnit(userUsageTime: number) {
const subscription = await getSubscription();
// round up userUsageTime to the nearest integer
const roundedUsageTime = Math.ceil(userUsageTime);
if (subscription) {
const usage = await setUsage(
subscription.data[0].attributes.first_subscription_item.id,
roundedUsageTime
);
}
}
async function importUserUsageData(run_id: string) {
const workflowRuns = await db.query.workflowRunsTable.findFirst({
where: eq(workflowRunsTable.id, run_id),
});
if (!workflowRuns?.workflow_id) return;
// find if workflowTable id column contains workflowRunsTable workflow_id
const workflow = await db.query.workflowTable.findFirst({
where: eq(workflowTable.id, workflowRuns.workflow_id),
});
if (workflowRuns?.ended_at === null || workflow == null) return;
const usageTime = parseFloat(
getDuration((workflowRuns?.ended_at - workflowRuns?.started_at) / 1000)
);
// add data to userUsageTable
const user_usage = await db.insert(userUsageTable).values({
user_id: workflow.user_id,
created_at: workflowRuns.ended_at,
org_id: workflow.org_id,
ended_at: workflowRuns.ended_at,
usage_time: usageTime,
});
return usageTime;
}

View File

@ -1,81 +0,0 @@
const people = [
{
name: "Nvidia T4 GPU",
gpu: "1x",
ram: "16GB",
price: "$0.000225/sec",
},
{
name: "Nvidia A40 GPU",
gpu: "1x",
ram: "48GB",
price: "$0.000575/sec",
},
];
export function GpuPricingPlan() {
return (
<div className="flex justify-center w-full py-8">
<div className="w-full max-w-4xl">
<table className="min-w-full divide-y divide-gray-300">
<thead>
<tr>
<th
scope="col"
className="py-3.5 pl-4 pr-3 text-left text-sm font-semibold text-gray-900 sm:pl-6"
>
GPU
</th>
<th
scope="col"
className="hidden px-3 py-3.5 text-left text-sm font-semibold text-gray-900 lg:table-cell"
>
No.
</th>
<th
scope="col"
className="hidden px-3 py-3.5 text-left text-sm font-semibold text-gray-900 sm:table-cell"
>
RAM
</th>
<th
scope="col"
className="px-3 py-3.5 text-left text-sm font-semibold text-gray-900"
>
Price
</th>
</tr>
</thead>
<tbody className="divide-y divide-gray-200 bg-white">
{people.map((person) => (
<tr key={person.ram} className="even:bg-gray-50">
<td className="w-full max-w-0 py-4 pl-4 pr-3 text-sm font-medium text-gray-900 sm:w-auto sm:max-w-none sm:pl-6">
{person.name}
<dl className="font-normal lg:hidden">
<dt className="sr-only">No.</dt>
<dd className="mt-1 truncate text-gray-700">
{person.gpu}
</dd>
<dt className="sr-only sm:hidden">RAM</dt>
<dd className="mt-1 truncate text-gray-500 sm:hidden">
{person.ram}
</dd>
</dl>
</td>
<td className="hidden px-3 py-4 text-sm text-gray-500 lg:table-cell">
{person.gpu}
</td>
<td className="hidden px-3 py-4 text-sm text-gray-500 sm:table-cell">
{person.ram}
</td>
<td className="px-3 py-4 text-sm text-gray-500">
{person.price}
</td>
</tr>
))}
</tbody>
</table>
</div>
</div>
);
}

View File

@ -1,157 +0,0 @@
import { checkMarkIcon, crossMarkIcon } from "../const/Icon";
import { cn } from "@/lib/utils";
import { getPricing } from "@/server/linkToPricing";
import { useEffect, useState } from "react";
type Tier = {
name: string;
id: string;
href: string;
priceMonthly: string;
description: string;
features: string[];
featured: boolean;
priority?: TierPriority;
};
enum TierPriority {
Free = "free",
Pro = "pro",
Enterprise = "enterprise",
}
export default function PricingList() {
const [productTiers, setProductTiers] = useState<Tier[]>();
useEffect(() => {
(async () => {
const product = await getPricing();
if (!product) return;
const newProductTiers: Tier[] = product.data.map((item) => {
// Create a new DOMParser instance
const parser = new DOMParser();
// Parse the description HTML string to a new document
const doc = parser.parseFromString(
item.attributes.description,
"text/html"
);
// Extract the description and features
const description = doc.querySelector("p")?.textContent || "";
const features = Array.from(doc.querySelectorAll("ul > li")).map(
(li) => li.textContent || ""
);
return {
name: item.attributes.name,
id: item.id,
href: item.attributes.buy_now_url,
priceMonthly:
item.attributes.price_formatted.split("/")[0] == "Usage-based"
? "$20.00"
: item.attributes.price_formatted.split("/")[0],
description: description,
features: features,
// if name contains pro, it's featured
featured: item.attributes.name.toLowerCase().includes("pro"),
// give priority if name contain in enum
priority: Object.values(TierPriority).find((priority) =>
item.attributes.name.toLowerCase().includes(priority)
),
};
});
// sort newProductTiers by priority
newProductTiers.sort((a, b) => {
if (!a.priority) return 1;
if (!b.priority) return -1;
return (
Object.values(TierPriority).indexOf(a.priority) -
Object.values(TierPriority).indexOf(b.priority)
);
});
setProductTiers(newProductTiers);
})();
}, []);
return (
<div className="relative isolate px-6 py-24 lg:px-8">
<div className="mx-auto max-w-2xl text-center lg:max-w-4xl">
<h2 className="text-base font-semibold leading-7 text-indigo-600">
Pricing
</h2>
<p className="mt-2 text-4xl font-bold tracking-tight text-gray-900 sm:text-5xl">
The right price for you, whoever you are
</p>
</div>
<p className="mx-auto mt-6 max-w-2xl text-center text-lg leading-8 text-gray-600">
Qui iusto aut est earum eos quae. Eligendi est at nam aliquid ad quo
reprehenderit in aliquid fugiat dolorum voluptatibus.
</p>
<div className="mx-auto mt-16 grid max-w-lg grid-cols-1 items-center gap-y-6 sm:mt-20 sm:gap-y-0 lg:max-w-4xl lg:grid-cols-2 xl:max-w-6xl xl:grid-cols-3">
{productTiers &&
productTiers.map((tier, tierIdx) => (
<div
key={tier.id}
className={cn(
tier.featured
? "relative bg-white shadow-2xl"
: "bg-white/60 sm:mx-8 lg:mx-0",
tier.featured
? ""
: tierIdx === 0
? "rounded-t-3xl sm:rounded-b-none lg:rounded-tr-none lg:rounded-bl-3xl"
: "sm:rounded-t-none lg:rounded-tr-3xl lg:rounded-bl-none",
"rounded-3xl p-8 ring-1 ring-gray-900/10 sm:p-10"
)}
>
<h3
id={tier.id}
className="text-base font-semibold leading-7 text-indigo-600"
>
{tier.name}
</h3>
<p className="mt-4 flex items-baseline gap-x-2">
<span className="text-5xl font-bold tracking-tight text-gray-900">
{tier.priceMonthly}
</span>
<span className="text-base text-gray-500">/month</span>
</p>
<p className="mt-6 text-base leading-7 text-gray-600">
{tier.description}
</p>
<ul
role="list"
className="mt-8 space-y-3 text-sm leading-6 text-gray-600 sm:mt-10"
>
{tier.features.map((feature) => (
<li key={feature} className="flex gap-x-3">
<div className="flex justify-center items-center">
{feature.includes("[x]") ? crossMarkIcon : checkMarkIcon}
</div>
{feature.replace("[x]", "")}
</li>
))}
</ul>
<a
href={tier.href}
aria-describedby={tier.id}
className={cn(
tier.featured
? "bg-indigo-600 text-white shadow hover:bg-indigo-500"
: "text-indigo-600 ring-1 ring-inset ring-indigo-200 hover:ring-indigo-300",
"mt-8 block rounded-md py-2.5 px-3.5 text-center text-sm font-semibold focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600 sm:mt-10"
)}
>
Get started today
</a>
</div>
))}
</div>
</div>
);
}

View File

@ -1,37 +0,0 @@
export const checkMarkIcon = (
<svg
className="h-5 w-5 flex-shrink-0 text-green-500"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 20 20"
fill="currentColor"
aria-hidden="true"
>
<path
fillRule="evenodd"
d="M16.704 4.153a.75.75 0 01.143 1.052l-8 10.5a.75.75 0 01-1.127.075l-4.5-4.5a.75.75 0 011.06-1.06l3.894 3.893 7.48-9.817a.75.75 0 011.05-.143z"
clipRule="evenodd"
/>
</svg>
);
export const crossMarkIcon = (
<svg
xmlns="http://www.w3.org/2000/svg"
x="0px"
y="0px"
width="20"
height="20"
viewBox="0 0 48 48"
>
<path
fill="#F44336"
d="M21.5 4.5H26.501V43.5H21.5z"
transform="rotate(45.001 24 24)"
/>
<path
fill="#F44336"
d="M21.5 4.5H26.5V43.501H21.5z"
transform="rotate(135.008 24 24)"
/>
</svg>
);

View File

@ -1,13 +1,9 @@
"use client";
import { GpuPricingPlan } from "@/app/(app)/pricing/components/gpuPricingTable";
import PricingList from "@/app/(app)/pricing/components/pricePlanList";
import PricingList from "@/components/PricingPlan";
export default function Home() {
return (
<div>
<PricingList />
<GpuPricingPlan />
</div>
);
}

View File

@ -1,19 +1,19 @@
// app/providers.tsx
'use client'
import posthog from 'posthog-js'
import { PostHogProvider } from 'posthog-js/react'
"use client";
import posthog from "posthog-js";
import { PostHogProvider } from "posthog-js/react";
if (typeof window !== 'undefined') {
if (typeof window !== "undefined") {
posthog.init(process.env.NEXT_PUBLIC_POSTHOG_KEY!, {
api_host: process.env.NEXT_PUBLIC_POSTHOG_HOST,
capture_pageview: false // Disable automatic pageview capture, as we capture manually
})
capture_pageview: false, // Disable automatic pageview capture, as we capture manually
});
}
export function PHProvider({
children,
}: {
children: React.ReactNode
children: React.ReactNode;
}) {
return <PostHogProvider client={posthog}>{children}</PostHogProvider>
return <PostHogProvider client={posthog}>{children}</PostHogProvider>;
}

View File

@ -0,0 +1,9 @@
"use client";
import { LoadingPageWrapper } from "@/components/LoadingWrapper";
import { usePathname } from "next/navigation";
export default function Loading() {
const pathName = usePathname();
return <LoadingPageWrapper className="h-full" tag={pathName.toLowerCase()} />;
}

View File

@ -0,0 +1,57 @@
import PricingList from "@/components/PricingPlan";
import { Badge } from "@/components/ui/badge";
import {
Card,
CardContent,
CardDescription,
CardHeader,
CardTitle,
} from "@/components/ui/card";
import { Progress } from "@/components/ui/progress";
import { getCurrentPlanWithAuth } from "@/server/getCurrentPlan";
import { stripe } from "@/server/stripe";
const freeTierSeconds = 30000;
export default async function Home() {
const sub = await getCurrentPlanWithAuth();
const data = sub?.subscription_item_api_id
? await stripe.subscriptionItems.listUsageRecordSummaries(
sub?.subscription_item_api_id,
)
: null;
return (
<div className="mt-4 flex items-center justify-center">
<Card className="p-4 w-full max-w-[600px]">
<CardHeader>
<CardTitle>Account Usage</CardTitle>
<CardDescription>View you account usage</CardDescription>
<Badge className="w-fit">{sub?.plan}</Badge>
</CardHeader>
{data && (
<CardContent className="text-sm flex flex-col gap-2">
<div className="flex justify-between gap-2">
<span>Current free gpu usage:</span>
{
<div className="flex gap-2">
<Badge>
{data.data[0].total_usage}s /{Math.floor(freeTierSeconds)}s
</Badge>
<Badge>
{Math.floor(data.data[0].total_usage / 60 / 60)}hr /
{Math.floor(freeTierSeconds / 60 / 60)}hr
</Badge>
</div>
}
</div>
<Progress
value={(data.data[0].total_usage / freeTierSeconds) * 100}
></Progress>
</CardContent>
)}
</Card>
</div>
);
}

View File

@ -91,13 +91,22 @@ export function Navbar() {
<div className="flex flex-row items-center gap-2">
{isDesktop && <NavbarMenu />}
{pricingPlanFlagEnable && (
<Button
asChild
variant="link"
className="rounded-full aspect-square p-2 mr-4"
>
<a href="/pricing">Pricing</a>
</Button>
<>
<Button
asChild
variant="link"
className="rounded-full aspect-square p-2 mr-4"
>
<a href="/pricing">Pricing</a>
</Button>
<Button
asChild
variant="link"
className="rounded-full aspect-square p-2 mr-4"
>
<a href="/usage">Usage</a>
</Button>
</>
)}
<Button
asChild

View File

@ -0,0 +1,381 @@
import {
Tooltip,
TooltipContent,
TooltipTrigger,
} from "@/components/ui/tooltip";
import { cn } from "@/lib/utils";
import { Check, Info, Minus } from "lucide-react";
import { Fragment } from "react";
import { auth } from "@clerk/nextjs";
import { subscriptionPlanStatus } from "@/db/schema";
import { getCurrentPlan } from "../server/getCurrentPlan";
const tiers = [
{
name: "Basic",
id: "basic",
// href: "/api/checkout?plan=basic",
href: "/workflows",
priceMonthly: "$0",
description: "Instant Comfy UI API",
mostPopular: false,
},
{
name: "Pro",
id: "pro",
href: "/api/stripe/checkout?plan=pro",
priceMonthly: "$20",
description: "Accelerate Comfy UI",
mostPopular: false,
},
{
name: "Enterprise",
id: "enterprise",
href: "/api/stripe/checkout?plan=enterprise",
priceMonthly: "$100",
description: "Scale your Products",
mostPopular: true,
},
];
const sections = [
{
name: "Features",
features: [
{
name: "GPU",
tiers: { Basic: "T4", Pro: "T4, A10G", Enterprise: "T4, A10G, A100" },
},
{
name: "Compute Credit",
tiers: {
Basic: (
<Tooltip>
<TooltipTrigger className="flex items-center justify-center gap-2">
30k secs free + usage <Info size={14} />
</TooltipTrigger>
<TooltipContent>
<ul className="flex flex-col items-start justify-start">
GPU Price /s = $0.00015
<li>- T4 Multiplier = x1</li>
</ul>
</TooltipContent>
</Tooltip>
),
Pro: (
<Tooltip>
<TooltipTrigger className="flex items-center justify-center gap-2">
30k secs free + usage <Info size={14} />
</TooltipTrigger>
<TooltipContent>
<ul className="flex flex-col items-start justify-start">
GPU Price /s = $0.00015
<li>- T4 Multiplier = x1</li>
<li>- A10G Multiplier = x4</li>
</ul>
</TooltipContent>
</Tooltip>
),
Enterprise: (
<Tooltip>
<TooltipTrigger className="flex items-center justify-center gap-2">
30k secs free + usage <Info size={14} />
</TooltipTrigger>
<TooltipContent>
<ul className="flex flex-col items-start justify-start">
GPU Price /s = $0.00015
<li>- T4 Multiplier = x1</li>
<li>- A10G Multiplier = x4</li>
<li>- A100 Multiplier = x7</li>
</ul>
</TooltipContent>
</Tooltip>
),
},
},
{
name: "Workflows",
tiers: { Basic: "2", Pro: "25", Enterprise: "Unlimited" },
},
{
name: "Serverless Machines",
tiers: { Basic: "2", Pro: "10", Enterprise: "Unlimited" },
},
{
name: "Outputs Storage",
tiers: { Basic: "2 GB", Pro: "10 GB", Enterprise: "Unlimited" },
},
{
name: "Dedicated Support",
tiers: { Enterprise: true },
},
{
name: "Private Model Hosting",
tiers: { Enterprise: "Coming Soon" },
},
],
},
];
export default async function PricingList() {
const { userId, orgId } = auth();
if (!userId) {
return <>No user id</>;
}
const sub = await getCurrentPlan({ user_id: userId, org_id: orgId });
const getHrefFromTier = (tier: (typeof tiers)[0]) => {
if (sub?.status == "active") {
if (tier.id == sub?.plan) return "/api/stripe/dashboard";
// This is actually cancelled
if (sub.cancel_at_period_end) return tier.href;
return "/api/stripe/dashboard?change=true";
} else {
return tier.href;
}
};
const getNameFromTier = (tier: (typeof tiers)[0]) => {
if (tier.id == sub?.plan && sub.status == "active") {
return sub.cancel_at_period_end ? (
<>
Current <span className="text-2xs"> - Ending this period</span>
</>
) : (
"Current"
);
}
if (sub?.status == "active") {
return "Get Started";
} else {
return "Get Started";
}
};
return (
<div className="bg-white py-24 sm:py-32">
<div className="mx-auto max-w-7xl px-6 lg:px-8">
<div className="mx-auto max-w-4xl text-center">
<h2 className="text-base font-semibold leading-7 text-indigo-600">
Pricing
</h2>
<p className="mt-2 text-4xl font-bold tracking-tight text-gray-900 sm:text-5xl">
Turn any workflow into API
</p>
</div>
<p className="mx-auto mt-6 max-w-2xl text-center text-lg leading-8 text-gray-600">
ComfyDeploy is now under technical preview.
</p>
{/* xs to lg */}
<div className="mx-auto mt-12 max-w-md space-y-8 sm:mt-16 lg:hidden">
{tiers.map((tier) => (
<section
key={tier.id}
className={cn(
tier.mostPopular
? "rounded-xl bg-gray-400/5 ring-1 ring-inset ring-gray-200"
: "",
"p-8",
)}
>
<h3
id={tier.id}
className="text-sm font-semibold leading-6 text-gray-900"
>
{tier.name}
</h3>
<p className="mt-2 flex items-baseline gap-x-1 text-gray-900">
<span className="text-4xl font-bold">{tier.priceMonthly}</span>
<span className="text-sm font-semibold">/month</span>
</p>
<br></br>
<div className="text-xl font-semibold">{tier.description}</div>
<a
href={getHrefFromTier(tier)}
aria-describedby={tier.id}
className={cn(
tier.mostPopular
? "bg-indigo-600 text-white hover:bg-indigo-500"
: "text-indigo-600 ring-1 ring-inset ring-indigo-200 hover:ring-indigo-300",
"mt-8 block rounded-md py-2 px-3 text-center text-sm font-semibold leading-6 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600",
)}
>
{getNameFromTier(tier)}
</a>
<ul
role="list"
className="mt-10 space-y-4 text-sm leading-6 text-gray-900"
>
{sections.map((section) => (
<li key={section.name}>
<ul role="list" className="space-y-4">
{section.features.map((feature) =>
feature.tiers[tier.name] ? (
<li key={feature.name} className="flex gap-x-3">
<Check
className="h-6 w-5 flex-none text-indigo-600"
aria-hidden="true"
/>
<span>
{feature.name}{" "}
{typeof feature.tiers[tier.name] === "string" ? (
<span className="text-sm leading-6 text-gray-500">
({feature.tiers[tier.name]})
</span>
) : null}
</span>
</li>
) : null,
)}
</ul>
</li>
))}
</ul>
</section>
))}
</div>
{/* lg+ */}
<div className="isolate mt-20 hidden lg:block border-gray-100 border p-6 shadow-md rounded-lg">
<div className="relative -mx-8">
{tiers.some((tier) => tier.mostPopular) ? (
<div className="absolute inset-x-4 inset-y-0 -z-10 flex">
<div
className="flex w-1/4 px-4"
aria-hidden="true"
style={{
marginLeft: `${
(tiers.findIndex((tier) => tier.mostPopular) + 1) * 25
}%`,
}}
>
<div className="w-full rounded-t-xl border-x border-t border-gray-900/10 bg-gray-400/5" />
</div>
</div>
) : null}
<table className="w-full table-fixed border-separate border-spacing-x-8 text-left">
<caption className="sr-only">Pricing plan comparison</caption>
<colgroup>
<col className="w-1/4" />
<col className="w-1/4" />
<col className="w-1/4" />
<col className="w-1/4" />
</colgroup>
<thead>
<tr>
<td />
{tiers.map((tier) => (
<th
key={tier.id}
scope="col"
className="px-6 pt-6 xl:px-8 xl:pt-8"
>
<div className="text-sm font-semibold leading-7 text-gray-900">
{tier.name}
</div>
</th>
))}
</tr>
</thead>
<tbody>
<tr>
<th scope="row">
<span className="sr-only">Price</span>
</th>
{tiers.map((tier) => (
<td key={tier.id} className="px-6 pt-2 xl:px-8">
<div className="flex items-baseline gap-x-1 text-gray-900">
<span className="text-4xl font-bold">
{tier.priceMonthly}
</span>
<span className="text-sm font-semibold leading-6">
/month
</span>
</div>
<br></br>
<div className="text-md font-semibold">
{tier.description}
</div>
<a
href={getHrefFromTier(tier)}
className={cn(
tier.mostPopular
? "bg-indigo-600 text-white hover:bg-indigo-500"
: "text-indigo-600 ring-1 ring-inset ring-indigo-200 hover:ring-indigo-300",
"mt-8 block rounded-md py-2 px-3 text-center text-sm font-semibold leading-6 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600",
)}
>
{getNameFromTier(tier)}
</a>
</td>
))}
</tr>
{sections.map((section, sectionIdx) => (
<Fragment key={section.name}>
<tr>
<th
scope="colgroup"
colSpan={4}
className={cn(
sectionIdx === 0 ? "pt-8" : "pt-16",
"pb-4 text-sm font-semibold leading-6 text-gray-900",
)}
>
{section.name}
<div className="absolute inset-x-8 mt-4 h-px bg-gray-900/10" />
</th>
</tr>
{section.features.map((feature) => (
<tr key={feature.name}>
<th
scope="row"
className="py-4 text-sm font-normal leading-6 text-gray-900"
>
{feature.name}
<div className="absolute inset-x-8 mt-4 h-px bg-gray-900/5" />
</th>
{tiers.map((tier) => (
<td key={tier.id} className="px-6 py-4 xl:px-8">
{typeof feature.tiers[tier.name] === "string" ||
typeof feature.tiers[tier.name] === "object" ? (
<div className="flex items-center justify-center text-center text-sm leading-6 text-gray-500">
{feature.tiers[tier.name]}
</div>
) : (
<>
{feature.tiers[tier.name] === true ? (
<Check
className="mx-auto h-5 w-5 text-indigo-600"
aria-hidden="true"
/>
) : (
<Minus
className="mx-auto h-5 w-5 text-gray-400"
aria-hidden="true"
/>
)}
<span className="sr-only">
{feature.tiers[tier.name] === true
? "Included"
: "Not included"}{" "}
in {tier.name}
</span>
</>
)}
</td>
))}
</tr>
))}
</Fragment>
))}
</tbody>
</table>
</div>
</div>
</div>
</div>
);
}

View File

@ -0,0 +1,28 @@
"use client"
import * as React from "react"
import * as ProgressPrimitive from "@radix-ui/react-progress"
import { cn } from "@/lib/utils"
const Progress = React.forwardRef<
React.ElementRef<typeof ProgressPrimitive.Root>,
React.ComponentPropsWithoutRef<typeof ProgressPrimitive.Root>
>(({ className, value, ...props }, ref) => (
<ProgressPrimitive.Root
ref={ref}
className={cn(
"relative h-4 w-full overflow-hidden rounded-full bg-secondary",
className
)}
{...props}
>
<ProgressPrimitive.Indicator
className="h-full w-full flex-1 bg-primary transition-all"
style={{ transform: `translateX(-${100 - (value || 0)}%)` }}
/>
</ProgressPrimitive.Root>
))
Progress.displayName = ProgressPrimitive.Root.displayName
export { Progress }

View File

@ -82,6 +82,7 @@ export const workflowVersionTable = dbSchema.table("workflow_versions", {
created_at: timestamp("created_at").defaultNow().notNull(),
updated_at: timestamp("updated_at").defaultNow().notNull(),
});
export const workflowVersionSchema = createSelectSchema(workflowVersionTable);
export const workflowVersionRelations = relations(
@ -158,6 +159,10 @@ export const workflowRunsTable = dbSchema.table("workflow_runs", {
ended_at: timestamp("ended_at"),
created_at: timestamp("created_at").defaultNow().notNull(),
started_at: timestamp("started_at"),
gpu: machineGPUOptions("gpu"),
machine_type: machinesType("machine_type"),
user_id: text("user_id"),
org_id: text("org_id"),
});
export const workflowRunRelations = relations(
@ -358,6 +363,32 @@ export const authRequestsTable = dbSchema.table("auth_requests", {
updated_at: timestamp("updated_at").defaultNow().notNull(),
});
export const subscriptionPlan = pgEnum("subscription_plan", [
"basic",
"pro",
"enterprise",
]);
export const subscriptionPlanStatus = pgEnum("subscription_plan_status", [
"active",
"deleted",
"paused",
]);
export const subscriptionStatusTable = dbSchema.table("subscription_status", {
stripe_customer_id: text("stripe_customer_id").primaryKey().notNull(),
user_id: text("user_id"),
org_id: text("org_id"),
plan: subscriptionPlan("plan").notNull(),
status: subscriptionPlanStatus("status").notNull(),
subscription_id: text("subscription_id"),
subscription_item_plan_id: text("subscription_item_plan_id"),
subscription_item_api_id: text("subscription_item_api_id"),
cancel_at_period_end: boolean("cancel_at_period_end").default(false),
created_at: timestamp("created_at").defaultNow().notNull(),
updated_at: timestamp("updated_at").defaultNow().notNull(),
});
export type UserType = InferSelectModel<typeof usersTable>;
export type WorkflowType = InferSelectModel<typeof workflowTable>;
export type MachineType = InferSelectModel<typeof machinesTable>;

View File

@ -3,7 +3,7 @@ import { z } from "zod";
export const APIKeyBodyRequest = z.object({
user_id: z.string().optional().nullable(),
org_id: z.string().optional().nullable(),
iat: z.number(),
iat: z.number().optional(),
exp: z.number().optional(),
});

View File

@ -66,7 +66,12 @@ export const createRun = withServerPromise(
throw new Error("Workflow version not found");
}
if (apiUser)
let { userId, orgId } = auth();
// If is API user, check if they have access to the workflow
if (apiUser) {
userId = apiUser.user_id ?? null;
orgId = apiUser.org_id;
if (apiUser.org_id) {
// is org api call, check org only
if (apiUser.org_id != workflow_version_data.workflow.org_id) {
@ -81,6 +86,7 @@ export const createRun = withServerPromise(
throw new Error("Workflow not found");
}
}
}
const workflow_api = workflow_version_data.workflow_api;
@ -114,6 +120,10 @@ export const createRun = withServerPromise(
workflow_inputs: inputs,
machine_id: machine.id,
origin: runOrigin,
org_id: orgId,
user_id: userId,
gpu: machine.gpu,
machine_type: machine.type,
})
.returning();

View File

@ -6,16 +6,13 @@ import jwt from "jsonwebtoken";
import { getOrgOrUserDisplayName } from "@/server/getOrgOrUserDisplayName";
import { withServerPromise } from "@/server/withServerPromise";
import "server-only";
import { headers } from "next/headers";
import { getUrlServerSide } from "./getUrlServerSide";
export const editWorkflowOnMachine = withServerPromise(
async (workflow_version_id: string, machine_id: string) => {
const { userId, orgId } = auth();
const headersList = headers();
const host = headersList.get("host") || "";
const protocol = headersList.get("x-forwarded-proto") || "";
const domain = `${protocol}://${host}`;
const domain = getUrlServerSide();
if (!userId) {
throw new Error("No user id");

View File

@ -0,0 +1,32 @@
import { db } from "@/db/db";
import { and, desc, eq, isNull } from "drizzle-orm";
import { subscriptionStatusTable } from "@/db/schema";
import { APIKeyUserType } from "@/server/APIKeyBodyRequest";
import { auth } from "@clerk/nextjs";
export async function getCurrentPlanWithAuth() {
const { userId, orgId } = auth();
const sub = await getCurrentPlan({
org_id: orgId,
user_id: userId,
});
return sub;
}
export async function getCurrentPlan({ user_id, org_id }: APIKeyUserType) {
if (!user_id) throw new Error("No user id");
const sub = await db.query.subscriptionStatusTable.findFirst({
where: and(
eq(subscriptionStatusTable.user_id, user_id),
org_id
? eq(subscriptionStatusTable.org_id, org_id)
: isNull(subscriptionStatusTable.org_id),
),
orderBy: desc(subscriptionStatusTable.created_at),
});
return sub;
}

View File

@ -0,0 +1,10 @@
import { headers } from "next/headers";
export function getUrlServerSide() {
const headersList = headers();
const host = headersList.get("host") || "";
const protocol = headersList.get("x-forwarded-proto") || "";
const domain = `${protocol}://${host}`;
return domain;
}

View File

@ -1,45 +0,0 @@
"use server";
import { LemonSqueezy } from "@lemonsqueezy/lemonsqueezy.js";
import "server-only";
const ls = new LemonSqueezy(process.env.LEMONSQUEEZY_API_KEY || "");
export async function getPricing() {
const products = await ls.getProducts();
return products;
}
export async function getUsage() {
const usageRecord = await ls.getUsageRecords();
return usageRecord;
}
export async function setUsage(id: number, quantity: number) {
const setUsage = await ls.createUsageRecord({
subscriptionItemId: id,
quantity: quantity,
});
return setUsage;
}
export async function getSubscription() {
const subscription = await ls.getSubscriptions();
return subscription;
}
export async function getSubscriptionItem() {
const subscriptionItem = await ls.getSubscriptionItems();
return subscriptionItem;
}
export async function getUserData() {
const user = await ls.getUser();
return user;
}

3
web/src/server/stripe.ts Normal file
View File

@ -0,0 +1,3 @@
import Stripe from "stripe";
export const stripe = new Stripe(process.env.STRIPE_API_KEY!);