Production-ready Next.js server for Bind - seamless cross-device text transfer system.
- ✅ JWT Authentication
- ✅ RESTful API for push/pull operations
- ✅ Response System with Status Tracking (pending, processing, success, failed, cancelled)
- ✅ LLM Integration (OpenAI, Gemini, Claude) for automatic responses
- ✅ Manual Response Resolution via dashboard
- ✅ Async Workflow Support with status tracking
- ✅ Chat messaging system
- ✅ User settings sync
- ✅ Modern dashboard UI
- ✅ Cloudflare D1 database integration
- ✅ TypeScript with full type safety
- ✅ Tailwind CSS for styling
- ✅ Production-ready error handling
- Framework: Next.js 16 (App Router)
- Runtime: Edge (Cloudflare Pages)
- Database: Cloudflare D1 (SQLite)
- Auth: JWT with jose
- Styling: Tailwind CSS v3
- Language: TypeScript
- Node.js 20.18+
- npm or yarn
- Cloudflare account
- Wrangler CLI installed globally
npm installThe database is already configured with:
- Database Name:
bind-database - Database ID:
3f6e853b-c79d-45d6-ace1-c47a192c3989 - Schema: Initialized with users, binds, chat_messages, user_settings tables
Create .env.local for local development:
JWT_SECRET=your-secret-key-here
# LLM API Keys (optional - only needed if using AI responses)
OPENAI_API_KEY=your-openai-api-key
GEMINI_API_KEY=your-gemini-api-key
ANTHROPIC_API_KEY=your-anthropic-api-keyFor production, set these environment variables in Cloudflare Pages settings.
npm run devnpm run buildAll API routes require authentication except /api/auth.
POST /api/auth
- Login or signup
- Headers:
X-Action: login | signup - Body:
{ email: string, password: string } - Returns:
{ token: string, userId: string }
POST /api/push
- Save a bind or provide response
- Headers:
Authorization: Bearer <token> - Body:
- Standard push:
{ id: string, group: string, content: string, metadata?: object } - With manual response:
{ id: string, group: string, content: string, res: true } - With AI response:
{ id: string, group: string, content: string, res: "ai" | "openai" | "gemini" | "claude" } - Provide response:
{ id: string, group: string, response_content: string }
- Standard push:
- Returns:
{ success: boolean, id: string, group: string, status: string } - Status values:
pending,processing,success,failed
GET /api/pull
- Retrieve binds, status, or responses
- Headers:
Authorization: Bearer <token> - Query parameters:
- Get all binds: No parameters
- Get specific bind:
?id=<id>&group=<group> - Get status:
?id=<id>&group=<group>&status=true - Get latest response:
?id=<id>&group=<group>&res=true - Get specific response:
?id=<id>&group=<group>&res=true&resIndex=<number>
- Returns:
- Binds:
{ success: boolean, binds: Array<Bind> } - Status:
{ success: boolean, status: string, status_message?: string } - Response:
{ success: boolean, content: string }
- Binds:
POST /api/chat
- Send a message
- Headers:
Authorization: Bearer <token> - Body:
{ message: string, group?: string } - Returns:
{ success: boolean }
GET /api/chat
- Get messages
- Headers:
Authorization: Bearer <token> - Query:
?group=<group>&limit=<number>(optional) - Returns:
{ success: boolean, messages: Array<Message> }
GET /api/settings
- Get user settings
- Headers:
Authorization: Bearer <token> - Returns:
{ success: boolean, settings: object }
PUT /api/settings
- Update settings
- Headers:
Authorization: Bearer <token> - Body:
{ settings: object } - Returns:
{ success: boolean, settings: object }
npm run pages:deployOr manually:
npm run build
wrangler pages deploy .next- Go to Cloudflare Pages dashboard
- Connect your GitHub repository
- Set build command:
npm run build - Set build output directory:
.next - Add environment variables:
JWT_SECRET(required)OPENAI_API_KEY(optional - for AI responses)GEMINI_API_KEY(optional - for AI responses)ANTHROPIC_API_KEY(optional - for AI responses)
- D1 database binding is configured in
wrangler.toml - Run migrations on remote database (see Development Tips)
server/
├── app/ # Next.js app directory
│ ├── api/ # API routes (edge runtime)
│ │ ├── auth/ # Authentication
│ │ ├── push/ # Push operation
│ │ ├── pull/ # Pull operation
│ │ ├── chat/ # Chat messaging
│ │ └── settings/ # User settings
│ ├── dashboard/ # Dashboard pages
│ │ ├── binds/ # Bind management
│ │ ├── groups/ # Group view
│ │ ├── chat/ # Chat interface
│ │ └── settings/ # Settings page
│ ├── login/ # Login page
│ ├── layout.tsx # Root layout
│ ├── page.tsx # Home page
│ └── globals.css # Global styles
├── lib/ # Core library code
│ ├── auth/ # JWT utilities
│ │ ├── jwt.ts # Token creation/verification
│ │ └── middleware.ts # Auth middleware
│ ├── db/ # Database layer
│ │ ├── client.ts # D1 client wrapper
│ │ ├── context.ts # Database context helper
│ │ └── migrations/ # SQL migration files
│ │ ├── 001_init.sql # Initial schema
│ │ └── 002_response_system.sql # Response system
│ ├── llm/ # LLM integration
│ │ └── service.ts # LLM providers (OpenAI, Gemini, Claude)
│ └── types/ # TypeScript types
│ ├── api.ts # API request/response types
│ └── database.ts # Database schema types
├── components/ # React components (future)
├── wrangler.toml # Cloudflare configuration
├── next.config.js # Next.js configuration
├── tailwind.config.ts # Tailwind configuration
├── tsconfig.json # TypeScript configuration
└── package.json # Dependencies
- id (TEXT, PRIMARY KEY)
- email (TEXT, UNIQUE)
- password_hash (TEXT)
- created_at (INTEGER)
- id (TEXT)
- group_name (TEXT)
- content (TEXT)
- metadata (TEXT/JSON)
- created_at (INTEGER)
- updated_at (INTEGER)
- user_id (TEXT)
- status (TEXT) - Values:
pending,processing,success,failed,cancelled - response_id (TEXT) - Links to response entry
- type (TEXT) - Values:
data,question,prompt,response - source_id (TEXT) - For response entries, links to source
- provider (TEXT) - LLM provider used:
ai,openai,gemini,claude,manual - response_count (INTEGER) - Number of responses created
- status_message (TEXT) - Detailed status/error message
- PRIMARY KEY (id, group_name, user_id)
- id (INTEGER, PRIMARY KEY, AUTOINCREMENT)
- group_name (TEXT)
- message (TEXT)
- user_id (TEXT)
- created_at (INTEGER)
- user_id (TEXT, PRIMARY KEY)
- settings (TEXT/JSON)
- updated_at (INTEGER)
The server supports an async workflow system for handling entries that require responses (manual or AI-generated).
-
Standard Push (no response needed):
POST /api/push { id: "notes", group: "work", content: "Meeting notes" } # Creates entry with status: "success", type: "data" -
Manual Response Request:
POST /api/push { id: "question1", group: "all", content: "What is the capital?", res: true } # Creates entry with status: "pending", type: "question" # User resolves from dashboard -
AI Response Request:
POST /api/push { id: "question2", group: "all", content: "Explain quantum physics", res: "openai" } # Creates entry with status: "processing", type: "question" # LLM processes asynchronously # Creates response entry (type: "response") and links it # Updates status to "success" -
Provide Manual Response:
POST /api/push { id: "question1", group: "all", response_content: "Paris" } # Creates response entry and updates status -
Check Status:
GET /api/pull?id=question2&group=all&status=true # Returns: { status: "processing", status_message: "Processing with openai..." }
-
Pull Response:
GET /api/pull?id=question2&group=all&res=true # Returns latest response content GET /api/pull?id=question2&group=all&res=true&resIndex=1 # Returns first response (res#1)
Response entries are created with IDs based on the source entry:
- Source:
question1@all - Response #1:
question1-out-1@all - Response #2:
question1-out-2@all
- JWT token-based authentication
- Password hashing with bcrypt
- Edge runtime for minimal attack surface
- Input validation with Zod
- SQL injection prevention (prepared statements)
- CORS handled by Cloudflare
- Secure headers by default
# Local database
wrangler d1 execute bind-database --command="SELECT * FROM users"
# Remote database
wrangler d1 execute bind-database --remote --command="SELECT * FROM binds LIMIT 10"# Local
wrangler d1 execute bind-database --file=./lib/db/migrations/001_init.sql
# Remote
wrangler d1 execute bind-database --remote --file=./lib/db/migrations/001_init.sqlnpm run pages:devThis starts Next.js dev server with Wrangler for D1 access.
MIT
For issues and feature requests, please create an issue on GitHub.