Build and Deploy an AI Automation Platform | Next.js 15, React, Better Auth | Zapier & N8N Clone
By Code With Antonio
Here's a comprehensive summary of the provided YouTube video transcript, focusing on depth and specificity:
Key Concepts
- Workflow Automation Platform Development
- Nodebase (N8N/Zapier alternative)
- Execution Engine
- Triggers (Manual, Google Forms, Stripe Webhooks)
- Integrations (OpenAI, Anthropic, Gemini, Discord, Slack)
- Credential Management (Encryption)
- Execution History & Error Tracking
- Real-time Updates
- Templating Language (Handlebars)
- Topological Sort
- Executor Registry
- Background Jobs (Ingest)
- Server Actions
- Authentication (GitHub, Google OAuth)
- Deployment (Vercel)
- Security Best Practices (Credential Encryption, Webhook Protection)
Summary of YouTube Video Transcript
This tutorial series focuses on building Nodebase, a workflow automation platform similar to N8N or Zapier. The transcript covers the development of the platform in two parts, with this summary focusing on the second part, which aims to complete the production-ready product.
Part 2: Core Functionality and Execution
The second part of the tutorial builds upon the editor, authentication, and payments established in Part 1. It covers the execution engine, triggers, integrations, credential management, execution history, and deployment.
1. Workflow Execution Engine
1.1. Node Data and Props Refinement
- Problem: Initial props for the HTTP request node were passed in three separate props, making them harder to manage.
- Solution: Modified
httpRequestNodeDatato consolidate these into a single prop, aligning with the form's input structure (endpoint, method, optional body). Renamed the form type tohttpRequestFormValuesfor clarity. Simplified prop handling in the dialogue component by usingdefaultValuesandoptional partialofhttpRequestFormValues.
1.2. Execute Workflow Button
- Requirement: Implement a button to trigger workflow execution.
- Implementation:
- Created a new component
executeWorkflowButton.tsx. - Added a
workflowIdprop to the button. - Rendered the button with "Execute Workflow" text and a flask icon.
- In
editor.tsx, created ahasManualTriggermemoized function to check if any node in the workflow is a manual trigger. - Conditionally rendered the
executeWorkflowButtonin the editor panel ifhasManualTriggeris true, passing theworkflowId. - Disabled the button based on the
isPendingstate of theuseExecuteWorkflowhook.
- Created a new component
1.3. Ingest Functions and Background Jobs
- Refactoring: Removed old ingest function logic and renamed
executetoexecuteWorkflow. - Event Structure: Defined the event structure as
workflows/execute.workflow. - Initial Job: The initial job simply sleeps for 5 seconds as a placeholder.
- TRPC Procedure:
- Created a protected TRPC mutation
workflows.executethat accepts a workflow ID. - Fetched the workflow using
prisma.workflow.findUniquewithinclude: { nodes: true, connections: true }. - Used
await ingest.sendto trigger the background job with the event nameworkflows/execute.workflow. - The TRPC procedure returns the fetched workflow.
- Created a protected TRPC mutation
- Custom Hook: Created a
useExecuteWorkflowhook that wraps the TRPC mutation, handling pending and error states. TheonSuccesscallback receives the workflow data.
1.4. Workflow Execution Logic (Ingest Job)
- Input Validation: Added a check for
event.data.workflowIdand throws anonRetryableErrorif missing. - Workflow Fetching: Fetched the workflow with its nodes and connections using
prisma.workflow.findUniqueor throws. - Topological Sort:
- Problem: Nodes need to be executed in a specific order, especially with branching.
- Solution: Implemented a
topologicalSortutility function using thetopo-sortpackage.- Created edges from connections (
fromNodeIdtotoNodeId). - Added self-edges for nodes without connections to ensure they are included.
- Handled cyclic dependencies by checking for "cyclic" in the error message and throwing a workflow cycle error.
- Mapped sorted node IDs back to node objects.
- Created edges from connections (
- The
executeWorkflowfunction now returns the topologically sorted nodes.
1.5. Executor Registry and Node Execution
- Executor Registry:
- Created
executorRegistry.tsinfeatures/executions/lib. - Defined
executorRegistryas aRecord<NodeType, NodeExecutor>. - Created a
getExecutorfunction to retrieve the appropriate executor based onnode.type.
- Created
- Node Executor Interface:
- Defined
NodeExecutorParamsinfeatures/executions/types.tsincludingdata,nodeId,context,step, andpublish(for real-time updates). datais a genericRecord<string, unknown>to accommodate varying node inputs.contextisWorkflowContext(initially empty, expands with each node's output).stepToolsincludesgetStepToolsandingest.
- Defined
- Executor Implementation (Manual Trigger):
- Created
manualTriggerExecutor.tsinfeatures/triggers/manualTrigger. - The executor simply passes through the context, emitting loading and success states via the
publishfunction.
- Created
- Executor Implementation (HTTP Request):
- Created
httpRequestExecutor.tsinfeatures/executions/components/httpRequest. - Defined
httpRequestDatawith optionalendpoint,method, andbody. - Error Handling: Added checks for missing
endpointandvariableName, throwingnonRetryableError. - Request Execution: Used
ky(orstep.fetch) to make HTTP requests. - Response Handling: Parsed JSON responses or fell back to text.
- Context Update: Spreads the previous context and adds the
HTTPResponseunder thevariableNameprovided by the user. - Key Collision Fix: Introduced
variableNameas a required field in the UI (dialogue) and executor to prevent overwriting results from multiple nodes with the same output key. Used Zod for validation with a regex for valid variable names. - Templating (Handlebars): Integrated Handlebars for dynamic endpoint URLs and request bodies.
- Registered a
JSON.stringifyhelper for object serialization. - Used
handlebars.compileto process template strings with context from previous nodes. - Added error handling for invalid JSON parsing and potential endpoint compilation issues.
- Registered a
- Created
- Real-time Updates (Ingest Realtime):
- Setup: Installed
ingest-realtimepackage. Configuredclient.tswithrealtimeMiddleware. - Channels: Defined channels (e.g.,
httpRequestChannel) with topics (status) and types (nodeId,status- loading, success, error). Registered channels infunctions.ts. - Publishing: Destructured
publishfrom the ingest context in executors and usedpublish(channel.topic(nodeId, status))to emit events. - Custom Hook (
useNodeStatus): Created a hook to subscribe to ingest real-time events, filter by channel, topic, and node ID, and update the node's status indicator (loading, success, error). - Server Actions (
actions.ts): Created server actions to fetch real-time subscription tokens. - UI Integration: Used
useNodeStatusin node components (e.g.,httpRequestNode.tsx) to display dynamic statuses. - Error Handling: Wrapped request execution in
try...catchblocks to publish error statuses. Configuredretries: 0in ingest functions for faster failure feedback during development.
- Setup: Installed
2. Trigger Nodes
2.1. Google Forms Trigger
- Node and Dialogue: Created
googleFormTriggerNode.tsxandgoogleFormTriggerDialogue.tsx, copying and adapting from the manual trigger. - Webhook URL Generation: Dynamically generated a webhook URL (
/api/webhooks/google-form?workflowId=...) usingprocess.env.NEXT_PUBLIC_APP_URLor localhost fallback. - UI: Included a copy-to-clipboard button for the webhook URL and detailed setup instructions for Google Apps Script.
- Google Apps Script: Provided a TypeScript utility (
generateGoogleFormScript) to generate the necessary Google Apps Script code, including replacing the webhook URL. - Webhook Route: Created
/api/webhooks/google-form/route.tsto handle POST requests.- Extracted
workflowIdfrom query parameters. - Parsed the request body, extracting relevant form data (e.g.,
formData,workflowId). - Triggered an ingest job using a new
sendWorkflowExecutionutility function, passing theworkflowIdandformDataas initial data.
- Extracted
- Executor: Created a simple
googleFormTriggerExecutorthat primarily emits loading and success states, passing context to the next node. - Ingest Integration: Registered the
googleFormChannelinfunctions.tsand updated theexecuteWorkflowfunction to handle initial data from triggers. - Testing: Used
enrofor local tunneling to expose localhost to the internet for Google Forms to send webhooks. Configured Google Apps Script with theenroURL and the workflow ID. Added anonRetryableErrorif theworkflowIdis missing in the webhook request. Added a200 OKresponse to the webhook route to prevent retries.
2.2. Stripe Trigger
- Node and Dialogue: Copied and adapted the Google Forms trigger structure for Stripe.
- Created
stripeTriggerNode.tsx,stripeTriggerDialogue.tsx,stripeTriggerExecutor.ts,stripeTriggerChannel.ts,actions.ts, and updatedfunctions.ts. - Modified the dialogue to prompt for Stripe-specific configuration (webhook URL, event types - though initially broad).
- Removed the username field and adapted instructions for Stripe dashboard setup.
- Created
- Webhook Route: Created
/api/webhooks/stripe/route.ts.- Extracted
workflowIdand parsed the request body, including event metadata (eventId,eventType) and raw data. - Triggered an ingest job with
workflowIdandstripeDataas initial context. - Added a
200 OKresponse to prevent retries.
- Extracted
- Testing: Used Stripe CLI (
stripe listen) andenrofor local testing. Configured Stripe webhooks in the Stripe dashboard to point to theenroforwarded URL. AddedpaymentIntentSucceededevent as an example. - Security: Noted the lack of webhook security (anyone could trigger the endpoint) and suggested implementing signature verification using Stripe's signing secret or a universal protection mechanism like Swix.
3. AI Nodes (Gemini, OpenAI, Anthropic)
- Prerequisites: Ensured AI SDK packages (
ai,ai-sdk-google,ai-sdk-openai,ai-sdk-anthropic) and corresponding Prisma schema types were added. - Node and Dialogue Implementation:
- Copied and adapted the HTTP request node/dialogue structure for each AI provider (Gemini, OpenAI, Anthropic).
- Form Schema: Defined schemas including
variableName,model(initially a dropdown, later hardcoded due to reliability issues),systemPrompt(optional), anduserPrompt(required). - Model Selection: Initially attempted a dynamic model selection dropdown but encountered issues with type safety and API version compatibility. Recommended hardcoding a working model (e.g.,
gemini-2.0-flash) and noted the need for future refactoring for dynamic model selection. - UI Updates: Modified node descriptions to reflect AI-specific prompts.
- Executor Implementation:
- Created specific executors (e.g.,
geminiExecutor.ts). - Templating: Used Handlebars for dynamic
systemPromptanduserPromptbased on context from previous nodes. - AI Client Initialization: Used
createGoogleGenerativeAI,createOpenAI,createAnthropicfrom AI SDK, passing API keys (initially from environment variables, later from credentials). - AI Call: Utilized
step.ai.v[Provider].generateTextfor AI model interaction. - Context Update: Stored the AI response (
textorAIResponse) in the context under thevariableName. - Error Handling: Implemented checks for missing required fields (
variableName,userPrompt,credentialId) and published error statuses. - Real-time Status: Integrated
publishcalls for loading, success, and error states using the respective AI channels.
- Created specific executors (e.g.,
- Credential Integration:
- Schema: Added
Credentialmodel toschema.prismawithname,value(API key),type(enum: OpenAI, Anthropic, Gemini),userId, and relations toUserandNode. - TRPC Router: Created
credentialsrouter with CRUD operations (create,remove,update,get,getMany,getByType). Added protection for user ID to prevent credential access across users. Noted the need for credential encryption in production. - Hooks: Developed hooks (
useCredentials,useCreateCredential,useRemoveCredential,useUpdateCredential,useSuspenseCredential,useCredentialsByType) mirroring the workflow hooks. - UI: Implemented a credentials management page (
credentials/page.tsx) with list, create, edit, and delete functionality. Added a dropdown in AI node dialogues to select stored credentials. - Executor Update: Modified AI executors to fetch the selected credential using
step.run('get-credential')and use itsvalue(API key) for AI client initialization. Removed direct reliance on environment variables for API keys.
- Schema: Added
4. Credentials Management
- Schema: Defined the
Credentialmodel inschema.prismawithid,name,value(encrypted),type(enum: OpenAI, Anthropic, Gemini),userId, and relations toUserandNode. AddedcredentialIdto theNodemodel. - TRPC Router: Implemented CRUD operations for credentials, ensuring user-specific access and protection against ID injection. Added
getByTypefor dropdown population. - Hooks: Created corresponding hooks (
useCredentials,useCreateCredential, etc.) for client-side data management. - UI: Developed a dedicated credentials management page with list, create, edit, and delete views, including pagination and search.
- Encryption:
- Problem: Storing API keys (credentials) as plain text in the database is a security risk.
- Solution: Used the
cryptornpm package to encrypt/decrypt credential values.- Generated an encryption key stored in environment variables.
- Created
encryptanddecryptutility functions inlib/encryption.ts. - Modified TRPC procedures (
create,update) to encrypt values before saving and decrypt them when fetching.
- Recommendation: Advised using more robust solutions like AWS Secrets Manager for production environments due to the limitations of symmetric encryption with a single key.
5. Authentication (GitHub & Google OAuth)
- GitHub OAuth:
- Setup: Registered a GitHub OAuth app in the GitHub Developer Portal, obtaining
client IDandclient secret. Configured homepage and callback URLs (/api/auth/callback/github). - Environment Variables: Stored
GITHUB_CLIENT_IDandGITHUB_CLIENT_SECRETin.env. - Auth.js Integration: Implemented
signIn('github')function within the login/register forms, handling success (redirect) and error (toast notification) states.
- Setup: Registered a GitHub OAuth app in the GitHub Developer Portal, obtaining
- Google OAuth:
- Setup: Configured Google OAuth credentials via the Google Cloud Console.
- Created a new project (
Nodebase prod). - Configured the OAuth consent screen (User Type: External, added app name and user email, skipped app logo for verification avoidance).
- Created an OAuth client ID for a web application, specifying JavaScript origins (
localhost:3000) and redirect URIs (/api/auth/callback/google). - Published the app to make it available to users.
- Created a new project (
- Environment Variables: Stored
GOOGLE_CLIENT_IDandGOOGLE_CLIENT_SECRETin.env. - Auth.js Integration: Implemented
signIn('google')function, similar to GitHub, handling success and error states. Noted potential issues with duplicate email addresses linking accounts and the need for proper user management.
- Setup: Configured Google OAuth credentials via the Google Cloud Console.
6. Deployment to Vercel
- Build Preparation: Ran
npm run buildlocally to catch build errors (especially type checking) before deployment. Advised against skipping type checks (typescript.ignoreBuildErrors). - Vercel Setup:
- Created a Vercel account.
- Imported the project from GitHub.
- Configured environment variables in Vercel's project settings:
- Database URL (Neon connection string).
- Better-AL URL (updated to the Vercel deployment URL).
NEXT_PUBLIC_APP_URL(updated to the Vercel deployment URL).- GitHub/Google Client IDs and Secrets (updated for production).
- Encryption Key (updated to a secure production key).
- Database: Recommended using Neon's branching feature for managing development and production databases. Used the development branch URL for the
DATABASE_URLinitially, suggesting a separate production branch for deployment.
- Redeployment: Redeployed the project on Vercel after updating environment variables.
- Post-Deployment: Verified GitHub and Google sign-in functionality with the production URLs.
7. Execution History
- Schema: Defined the
Executionmodel inschema.prismawithid,workflowId,ingestEventId,status(enum: running, success, failed),startedAt,completedAt(optional),error(optional string), anderrorStack(optional string,db.Text). Added a relation toWorkflow. - TRPC Router: Created
executionsrouter withgetandgetManyprocedures.getMany: Fetched executions with included workflow data (id,name), ordered bystartedAtdescending. Filtered byworkflow.userId.get: Fetched a single execution, including workflow data.
- Hooks: Developed
useSuspenseExecutionsanduseSuspenseExecutionhooks. - Server Components: Implemented
paramsLoaderandprefetchfunctions for fetching execution data on the server. - Client Components:
- Created
executions/page.tsxto orchestrate the loading and display of execution data. - Developed
executions/components/executions.tsx(main container),executions/components/executionsHeader.tsx,executions/components/executionsList.tsx, andexecutions/components/executionsPagination.tsx. - Created
executions/components/executionItem.tsxto display individual execution details (status icon, workflow name, timing, duration). - Implemented
getStatusIconto visually represent execution status (success, failed, running). - Developed
executions/components/execution.tsxfor the detailed view of a single execution, including workflow link, status, timing, duration, output, and error details (message and stack trace) using a collapsible component.
- Created
- Ingest Integration:
- Execution Creation: Modified
functions.tsto create anExecutionrecord withstatus: 'running'andingestEventIdupon starting a workflow job. UsedCU_ID2foringestEventIdto ensure uniqueness. - Execution Update: Added
updateExecutionstep to update theExecutionrecord withstatus: 'success',completedAt, andoutput(context) upon successful completion. - Failure Handling: Added an
onFailurehandler inexecuteWorkflowto update theExecutionrecord withstatus: 'failed',error, anderrorStack.
- Execution Creation: Modified
8. Deployment Preparation
- Code Cleanup: Removed development-specific configurations like
retries: 0in ingest functions, replacing them with conditional logic based onprocess.env.NODE_ENV. - Local Build Test: Ran
npm run buildlocally to ensure the project builds successfully, catching potential type errors or configuration issues before deploying to Vercel. - Vercel Deployment:
- Connected Vercel to GitHub repository.
- Configured environment variables for production (database URL, Better-AL URL,
NEXT_PUBLIC_APP_URL, GitHub/Google OAuth credentials, encryption key). - Updated OAuth redirect URIs and homepage URLs to production domains.
- Redeployed the project on Vercel.
- Verified functionality post-deployment.
This summary provides a detailed breakdown of the technical aspects covered in the transcript, including specific implementation details, problem-solving approaches, and architectural decisions made during the development of the Nodebase platform.
Chat with this Video
AI-PoweredLoad the transcript when you're ready to chat so the initial page stays lighter.
Related Videos

What's new in Angular
Chrome for Developers

Rachel Reeves tells Sky News she will still be chancellor for the autumn budget
Sky News

Inside the Enhanced Games, aka 'The Doping Olympics' | The Global Story
BBC News

'DHS OFFICIAL ORDERED ME TO DELETE…': Witness reveals SHOCKING details of Minnesota Child Care fraud
The Economic Times

Penélope Cruz and Glenn Close star in Spanish civil war gay drama at Cannes • FRANCE 24 English
FRANCE 24 English

Getting More from Every Copilot Interaction
GitHub

U-Haul trucks are turning around. The Exodus is OVER.
Reventure Consulting