Skip to content

Next.js

A production framework that would best serve the business model
WHY NEXT?
SSR - dashboard/admin interfaces with server-side rendering
Server-Side Rendering is development technique where content is generated on the server first, then sent to the user's browser offering faster initial loads.
Client-Side Rendering (CSR) which relies heavily on JavaScript to build the page in the browser
** proposal I believe would best support business requirments
** The Framewwork itself can be deployed off vercel and there no vender lock in.

Fulllstack + No Hidden Fees + Mature tooling for business SPA + Excellent DB intigration

Frontend: Next.js + React + Tailwind CSS
Backend: Next.js API Routes
Database: Neon (Postgres) or Turso (SQLite)
Hosting: Vercel
SMS/Voice: Twilio
Auth: Clerk or NextAuth.js
I dont use IDEs or software and this stack can all be done from the command line.

TWILIO APPROACH

Twilio WebhooksAPI Routes
/api/twilio/incoming-call SUPABASE DB
/api/twilio/incoming-sms SUPABASE DB
/api/twilio/status-callback SUPABASE DB

Event Triggered Flow

Missed Call → Twilio → Your webhook →
1. Log to DB (interactions table)
2. Trigger auto-SMS (Twilio API)
3. Log follow-up (follow_ups table)
4. Dashboard updates in real-time

Envronmental Variables Twilio / TRIAL ACCOUNT
token generator:
brew tap twilio/brew && brew install twilio
TWILIO_ACCOUNT_SID=ACxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
TWILIO_AUTH_TOKEN=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
TWILIO_PHONE_NUMBER=+12345678901
# production
TWILIO_MESSAGING_SERVICE_SID=MGxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
TWILIO_VERIFY_SERVICE_SID=VAxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

API CALL using curl where -u is the SID : api key
// command line twillio api call to list services

curl -X GET "https://sync.twilio.com/v1/Services?PageSize=100&Page=0" \
-u SK83c9ea5c6485378ba3ee8c1f25e52328:jDagSXEgFpTGljA4egaleYxeC7ByZboU

based on the responce im able to build the endpoints for automation inside the app.
▲ Next.js 16.1.4 (Turbopack)
Route (pages)
┌ ○ /
├ ○ /404
├ ƒ /api/send-followup
├ ƒ /api/twilio/incoming-call
├ ƒ /api/twilio/incoming-sms
├ ƒ /api/twilio/status
├ ƒ /api/user/[id]
├ ƒ /api/users
├ ○ /dashboard
└ ○ /user/[id]
F = SSR Server Side route
so the dash is nearly completly SSR!
COMMAND LINE
npx create-next-app@latest callaback
Would you like to use TypeScript? No / YES
Which linter would you like to use? ESLint / Biome / None
Would you like to use React Compiler? No / Yes
Would you like to use Tailwind CSS? No / Yes
Would you like your code inside a `src/` directory? No / Yes
Would you like to use App Router? (recommended) No / Yes
Would you like to customize the import alias (`@/*` by default)? No / Yes
What import alias would you like configured? @/* YES


Why This Over Zapier + Sheets

Cost: After initial dev, just Twilio + Vercel costs
Speed: Direct DB writes vs Zapier delays
Reliability: No Zapier rate limits or connection breaks
Customization: Full control over business logic
Scalability: Handles way more businesses/leads

DATABASE = SUPABASE
chat_messages
contacts
follow-ups
interactions
leads
notifications
sms metrics
S3 bucket file storage

schema.sql

-- WARNING: This schema is for context only and is not meant to be run.

CREATE TABLE public.chat_messages (
id uuid NOT NULL DEFAULT gen_random_uuid(),
session_id text NOT NULL,
sender_identity text NOT NULL,
message text NOT NULL,
created_at timestamp with time zone DEFAULT now(),
metadata jsonb DEFAULT '{}'::jsonb,
CONSTRAINT chat_messages_pkey PRIMARY KEY (id)
);
CREATE TABLE public.contacts (
id uuid NOT NULL DEFAULT gen_random_uuid(),
name text NOT NULL,
phone text NOT NULL,
email text,
company text,
notes text,
created_at timestamp with time zone DEFAULT now(),
updated_at timestamp with time zone DEFAULT now(),
sms_opt_out boolean DEFAULT false,
tags ARRAY DEFAULT '{}'::text[],
source text,
metadata jsonb DEFAULT '{}'::jsonb,
CONSTRAINT contacts_pkey PRIMARY KEY (id)
);
CREATE TABLE public.follow_ups (
id uuid NOT NULL DEFAULT gen_random_uuid(),
interaction_id uuid,
contact_id uuid,
type text NOT NULL CHECK (type = ANY (ARRAY['auto_sms'::text, 'manual'::text, 'callback'::text, 'email'::text])),
status text NOT NULL DEFAULT 'pending'::text CHECK (status = ANY (ARRAY['pending'::text, 'completed'::text, 'failed'::text])),
message text,
scheduled_for timestamp with time zone,
completed_at timestamp with time zone,
created_at timestamp with time zone DEFAULT now(),
priority text DEFAULT 'medium'::text,
metadata jsonb DEFAULT '{}'::jsonb,
due_date timestamp with time zone,
CONSTRAINT follow_ups_pkey PRIMARY KEY (id),
CONSTRAINT follow_ups_interaction_id_fkey FOREIGN KEY (interaction_id) REFERENCES public.interactions(id),
CONSTRAINT follow_ups_contact_id_fkey FOREIGN KEY (contact_id) REFERENCES public.contacts(id)
);
CREATE TABLE public.interactions (
id uuid NOT NULL DEFAULT gen_random_uuid(),
type text NOT NULL CHECK (type = ANY (ARRAY['call'::text, 'sms'::text])),
direction text NOT NULL CHECK (direction = ANY (ARRAY['inbound'::text, 'outbound'::text])),
from_number text NOT NULL,
to_number text NOT NULL,
status text NOT NULL,
duration integer,
body text,
twilio_sid text,
contact_id uuid,
created_at timestamp with time zone DEFAULT now(),
num_media integer DEFAULT 0,
metadata jsonb DEFAULT '{}'::jsonb,
CONSTRAINT interactions_pkey PRIMARY KEY (id),
CONSTRAINT interactions_contact_id_fkey FOREIGN KEY (contact_id) REFERENCES public.contacts(id)
);
CREATE TABLE public.leads (
id uuid NOT NULL DEFAULT gen_random_uuid(),
contact_id uuid,
title text NOT NULL,
description text,
status text NOT NULL DEFAULT 'new'::text CHECK (status = ANY (ARRAY['new'::text, 'contacted'::text, 'qualified'::text, 'converted'::text, 'lost'::text])),
priority text DEFAULT 'medium'::text CHECK (priority = ANY (ARRAY['low'::text, 'medium'::text, 'high'::text])),
source text,
value numeric,
created_at timestamp with time zone DEFAULT now(),
updated_at timestamp with time zone DEFAULT now(),
CONSTRAINT leads_pkey PRIMARY KEY (id),
CONSTRAINT leads_contact_id_fkey FOREIGN KEY (contact_id) REFERENCES public.contacts(id)
);
CREATE TABLE public.notifications (
id uuid NOT NULL DEFAULT uuid_generate_v4(),
type text NOT NULL,
severity text DEFAULT 'info'::text,
title text NOT NULL,
message text,
metadata jsonb DEFAULT '{}'::jsonb,
read boolean DEFAULT false,
created_at timestamp with time zone DEFAULT now(),
CONSTRAINT notifications_pkey PRIMARY KEY (id)
);
CREATE TABLE public.sms_metrics (
id uuid NOT NULL DEFAULT uuid_generate_v4(),
message_sid text NOT NULL UNIQUE,
status text NOT NULL,
is_delivered boolean DEFAULT false,
is_failed boolean DEFAULT false,
error_code text,
num_segments integer DEFAULT 1,
price numeric,
price_unit text,
delivery_time_ms integer,
created_at timestamp with time zone DEFAULT now(),
CONSTRAINT sms_metrics_pkey PRIMARY KEY (id)
);


ACCOUNT_SID=ONTHE LOGIN PAGE
API_KEY=API KEY SECTION
API_SECRET=THIS API SECRET ONLY SHOWS ONE TIME
SYNC_SERVICE_SID=THIS SID STARTS WITH AN "IS" and is default or one you create
TWILIO_NUMBER=
WEBHOOK INPUTS TO ADD IN TWILIO CONSOLE
** with https://
calls
callaback.com/api/twilio/incoming-call/
SMS
callaback.com/api/twilio/incoming-sms/
sms-send
callaback.com/api/twilio/sms-send/
Fallback

API OVERVIEW
what is working now.

on an incoming call to the toll free number
A contact is created from the phone number
A contact is saved to the DATABASE
The interaction is saved to a seperate table
The interaction is catgorized LEAD, APPT, Callback

A contact is created DASHBOARD
Screenshot 2026-01-23 at 19.21.58.png
A contact is saved to the DATABASE
Screenshot 2026-01-23 at 19.25.37.png
The interaction is saved to a seperate table
(with its own UUID unique to that exact call)

Screenshot 2026-01-23 at 19.27.02.png
The interaction is catgorized LEAD, APPT, Callback
all this happens automatically.
Screenshot 2026-01-23 at 19.29.25.png

THIS IS ROCK SOLID DUE TO HOW IT IS BUILT

What this is NOT....”hey GPT Build me an api for twillio”

I imported every single API that twilio supports in postman

Screenshot 2026-01-23 at 19.36.02.png
Then Started API calls based on there documentation. so that is why it just works.

EXAMPLE

** it is from a trial account but you can see that it returns every single service the API supports and that is how the APP is built. From mthe inside out.
This call is a Request to list all services
TERMINAL using Curl
curl -X GET "https://sync.twilio.com/v1/Services?PageSize=100&Page=0" \
-u SK83c9ea5c6485378ba3ee8c1f25e52328:jDagSXEgFpTGljA4egaleYxeC7ByZboU


Screenshot 2026-01-23 at 18.41.05.png
And it returns all services GET HTTP /200 OK

carbon (1).png
Almost every route is SSR
Route (app)
Want to print your doc?
This is not the way.
Try clicking the ··· in the right corner or using a keyboard shortcut (
CtrlP
) instead.