BookraftAI Documentation

A self-hostable AI book generation platform with KDP-ready PDF export, four payment gateways, and an admin panel β€” built on Next.js 16 and Express 5.

πŸ“– Overview

BookraftAI is a full-stack web application that turns a short brief into a finished, print-ready book. It ships as two services:

Buyers self-host both services. End users supply their own AI provider keys (OpenRouter, optionally OpenAI), so you don't pay for their inference. Books are billed via a credit system charged through Stripe, PayPal, Razorpay, or Dodo Payments.

BookraftAI landing page
Landing page

βœ… Requirements

ComponentMinimum
Node.js18.x or newer (20.x LTS recommended)
MongoDB6.x or newer (Atlas free tier works)
Disk~500 MB for source + node_modules; persistent storage for backend/uploads/ on production hosts
Memory512 MB minimum per service; 1 GB recommended
OpenRouterAccount + API key for AI generation
OpenAIOptional β€” only required for strict image-trim sizes

πŸ“¦ Installation

1. Unzip and install dependencies

cd bookraft-ai/backend
npm install

cd ../frontend
npm install

2. Configure environment files

cd backend
cp .env.example .env
# Edit .env β€” set MONGODB_URI and JWT_SECRET at minimum

cd ../frontend
cp .env.example .env.local
# Defaults to http://localhost:5001/api β€” change for production

3. Start in development

# Terminal 1 β€” backend on :5001
cd backend
npm run dev

# Terminal 2 β€” frontend on :3000
cd frontend
npm run dev

Open http://localhost:3000.

πŸš€ First run

  1. Sign up at /signup β€” the very first user is automatically promoted to admin.
  2. Open Settings β†’ paste an OpenRouter API key. Optionally add an OpenAI key.
  3. Open Admin β†’ Settings β†’ set the Support Email. Add Contact Information and Social Links if you want them on the public Contact page.
  4. Open Admin β†’ Plans β†’ create one or more credit bundles.
  5. Open Admin β†’ Payment Gateways β†’ enable any combination of Stripe, PayPal, Razorpay, Dodo and paste keys.
  6. Generate your first book from /library β†’ New book.
Bootstrap warning The first-user-is-admin rule is convenient for self-hosting but risky on a public deploy. Sign up before exposing the URL, or pre-seed an admin in MongoDB.
New book wizard
First run β€” creating your first book from the Library

βš™οΈ Backend environment variables

VariableRequiredDefaultPurpose
MONGODB_URIYesβ€”MongoDB connection string
JWT_SECRETYesβ€”Secret used to sign JWTs. In production, the server refuses to boot if this is missing or set to the example placeholder.
PORTNo5001API port
NODE_ENVNodevelopmentSet to production on production hosts.
CLIENT_URLNohttp://localhost:3000Used for CORS, payment redirects, and post-OAuth redirect.
SERVER_URLNohttp://localhost:5001Public base URL of this API. Used for the Google OAuth redirect URI.
GOOGLE_CLIENT_ID / GOOGLE_CLIENT_SECRETNoβ€”Set both to enable Google sign-in.
OPENROUTER_API_KEYNoβ€”Workspace-level fallback. Per-user keys (in /settings) take precedence.
OPENROUTER_MODELNoβ€”Default text model for users with no preference set.
OPENROUTER_IMAGE_MODELNoβ€”Default image-capable chat model.
OPENAI_API_KEYNoβ€”Optional. Enables strict image trim sizes via OpenAI's /v1/images/generations.
OPENAI_IMAGE_MODELNogpt-image-1β€”
SMTP_HOST / SMTP_PORT / SMTP_USER / SMTP_PASS / SMTP_FROM / SMTP_SECURENoβ€”Required to deliver public Contact form messages. Without these, the contact endpoint returns 503.

πŸŽ›οΈ Frontend environment variables

VariableRequiredDefaultPurpose
NEXT_PUBLIC_API_URLNohttp://localhost:5001/apiBase URL for all API calls. Must include /api.

🎨 Branding & rebrand checklist

BookraftAI is designed to be rebranded in minutes. All user-facing branding is centralised in one constants file:

frontend/lib/branding.ts

Edit these constants:

Then swap these visual assets:

Optionally, update the package names:

βœ‰οΈ Email / SMTP setup

The public Contact form (POST /api/contact) and the deactivated-account "Contact Support" link both use the admin-configured Support Email. To deliver Contact messages, configure SMTP in backend/.env:

SMTP_HOST=smtp.example.com
SMTP_PORT=587
SMTP_SECURE=false
SMTP_USER=mailer@example.com
SMTP_PASS=your-smtp-password
SMTP_FROM="Your Brand <mailer@example.com>"
Gmail tip Generate a 16-character "App Password" in your Google Account β†’ Security β†’ 2-Step Verification β†’ App Passwords. Use smtp.gmail.com, port 587, SMTP_SECURE=false.

πŸ€– AI models

BookraftAI does not bundle inference. End users plug in their own keys via /settings:

ProviderUsed forDefault model
OpenRouterText + image (/chat/completions with modalities: ["image"])Text: anthropic/claude-sonnet-4.6 Β· Image: google/gemini-3.1-flash-image-preview
OpenAI (optional)Image generation only β€” direct /v1/images/generations for precise sizinggpt-image-1

If a user has no OpenAI key, image generation falls back to OpenRouter (which silently ignores the requested size β€” OpenRouter returns square images regardless of trim). Users can also force all image traffic through OpenRouter via the forceOpenRouterForImages flag in their settings.

User settings β€” bring your own AI keys
Settings β†’ bring-your-own-key for OpenRouter and OpenAI

πŸ’³ Payment gateways

Four gateways are integrated. Admins enable any combination via Admin β†’ Payment Gateways. Keys are stored in MongoDB, not in env vars, so they're shared across backend instances.

GatewayRequired keysWhere to find them
StripePublishable key, Secret keyStripe dashboard β†’ Developers β†’ API keys
PayPalClient ID, SecretPayPal Developer dashboard β†’ My Apps & Credentials
RazorpayKey ID, Key SecretRazorpay dashboard β†’ Settings β†’ API Keys
Dodo PaymentsAPI Key, Webhook SecretDodo dashboard β†’ Developers

Webhook URLs follow the pattern https://<your-api-host>/api/payments/<gateway>/webhook. Configure them in each gateway's dashboard so plan purchases get marked as completed and credits are granted.

Admin β†’ payment gateways
Admin β†’ Payment Gateways β€” enable Stripe, PayPal, Razorpay, or Dodo

πŸ” Google OAuth

  1. Open Google Cloud Console β†’ APIs & Services β†’ Credentials.
  2. Create an OAuth 2.0 Client ID of type Web application.
  3. Authorised redirect URI: {SERVER_URL}/api/auth/google/callback (e.g. https://api.yourdomain.com/api/auth/google/callback).
  4. Copy the Client ID and Client Secret into backend/.env as GOOGLE_CLIENT_ID / GOOGLE_CLIENT_SECRET.
  5. Restart the backend. The "Sign in with Google" button on /login activates automatically.

If both env vars are unset, the route returns 503 cleanly and the button is hidden.

πŸ›  Admin panel

Pages under /admin/* are gated to users with role: "admin":

PageWhat it does
UsersList, edit credits directly, toggle active/deactivated status.
PlansCRUD credit bundles (name, price, generations granted, gateway IDs, popular flag).
GatewaysPer-gateway enable/disable, test/live toggle, key entry.
PurchasesFull purchase history with status filters.
AnalyticsPlatform totals + last 7 days breakdown of revenue and signups.
SettingsWorkspace currency, support email, contact info, social links, default user limits (signup credits).
Admin panel home
Admin panel β€” users, plans, gateways, purchases, analytics, settings

πŸ“ Book workshop

The workshop at /book/[id] is a tabbed editor:

TabWhat it does
DetailsTitle, subtitle, author, series, ISBN, publication date, language, age/grade range, KDP keywords, Amazon category.
ContentStream new pages, regenerate any page with a custom prompt, rewrite individual blocks (text / heading / image-prompt), insert / duplicate / delete pages.
CoverGenerate or remix the cover with style-guide control.
AssetsPersistent asset library β€” every generated image is saved and can be reused across pages.
PreviewFull-book preview with KDP-style page composition (backgrounds, page numbers).
ExportDownload full book / interior-only / cover-only PDF.
Book workshop β€” content editor
Workshop β†’ Content β€” stream, regenerate, and rewrite pages

πŸ“„ KDP-ready PDF export

PDF export runs entirely in the browser via jsPDF β€” manuscripts never leave the user's device during export. Three export modes:

Trim sizes (6Γ—9", 8.5Γ—11", custom), margins, bleed (0.125"), paper type, interior color, page numbering position/font/color/start-offset, and per-page background images are all configurable in the workshop's Details tab.

Workshop export β€” KDP-ready PDF
Workshop β†’ Export β€” KDP-ready full book / interior / cover PDFs

⚑ VPS install (recommended)

BookraftAI ships with two interactive Bash scripts under setup/ that take a fresh Ubuntu VPS to a live, SSL-secured deployment in under 15 minutes:

ScriptWhat it does
setup/setup.shInstalls Node.js 20, MongoDB 7, and PM2. Prompts for your domains and API keys, then writes backend/.env and frontend/.env.local, installs deps, and runs npm run build on the frontend.
setup/deploy.shInstalls Nginx + Certbot, configures reverse-proxy vhosts for the API and frontend subdomains, starts both apps under PM2, and issues Let's Encrypt SSL certificates.
Tested on Ubuntu 22.04 (jammy), 24.04 (noble), and 20.04 (focal). Run as root or with sudo.

Prerequisites

Step 1 β€” Clone the project on your VPS

cd /opt
git clone https://github.com/your-username/bookraft-ai.git
cd bookraft-ai

If you uploaded the CodeCanyon zip instead of cloning, scp or rsync it to /opt/bookraft-ai/ and unzip in place.

Step 2 β€” Run the installer

sudo bash setup/setup.sh

You'll see an interactive menu. Choose 1) Complete Installation. The script will:

  1. Install Node.js 20, MongoDB 7 (official repo), and PM2 β€” skipping anything already installed, so it's safe to re-run.
  2. Prompt for your frontend domain (e.g. app.example.com) and backend domain (e.g. api.example.com). Enter them without http://.
  3. Prompt for the MongoDB URI β€” accept the default mongodb://localhost:27017/bookraft-ai to use the local Mongo it just installed.
  4. Prompt for Google OAuth (skip with blank values to hide the Google button), OpenRouter, OpenAI (optional), and SMTP (optional β€” only required if you want the public Contact form to deliver).
  5. Generate a strong JWT_SECRET via openssl rand -base64 48.
  6. Install backend and frontend dependencies and build the frontend.
Port choice The script writes PORT=5051 for the backend and starts the frontend on port 3051. These were chosen to avoid clashing with other Node apps you may already run on the box. If you're running BookraftAI alongside other PM2 apps, verify the ports are free first: sudo ss -ltn 'sport = :5051' 'sport = :3051'. If something else is bound, edit PORT in setup/setup.sh and the proxy_pass lines in setup/deploy.sh before running them.

Step 3 β€” Point your DNS

At your DNS provider, add two A records pointing to your VPS's public IPv4:

app.example.com    A    <vps-ipv4>
api.example.com    A    <vps-ipv4>

Wait until both resolve before continuing. Verify from the VPS itself:

dig +short app.example.com @1.1.1.1
dig +short api.example.com @1.1.1.1
# both should print your VPS IP
Don't skip DNS propagation Let's Encrypt's HTTP-01 challenge fails immediately if DNS isn't pointing at the box. If dig doesn't return your VPS IP, wait 5–10 minutes before running deploy.sh.

Step 4 β€” Run the deployment wizard

sudo bash setup/deploy.sh

The script will:

  1. Confirm DNS is pointing at the server.
  2. Install Nginx and Certbot.
  3. Write Nginx vhosts at /etc/nginx/sites-available/bookraft-api and /etc/nginx/sites-available/bookraft-ui, then enable them. The API vhost includes proxy_buffering off and 3600-second timeouts so live SSE page-streaming works without chunking.
  4. Install backend dependencies and start the API under PM2 as bookraft-api.
  5. Start the Next.js frontend under PM2 as bookraft-ui on port 3051.
  6. Save the PM2 process list and configure it to auto-start on reboot.
  7. Optionally run certbot --nginx for both subdomains, then patch SERVER_URL, CLIENT_URL, and NEXT_PUBLIC_API_URL in the env files to https:// and rebuild the frontend.

At the end you'll see:

πŸš€ DEPLOYMENT SUCCESSFUL!
  Frontend URL: https://app.example.com
  Backend API:  https://api.example.com

Step 5 β€” Bootstrap the first admin

Visit https://app.example.com/signup and sign up. The first account is auto-promoted to admin. Then:

  1. Settings β†’ paste your OpenRouter key (and OpenAI key if you want strict image trim sizes).
  2. Admin β†’ Plans β†’ create at least one credit bundle.
  3. Admin β†’ Payment Gateways β†’ enable Stripe, PayPal, Razorpay, and/or Dodo Payments. Configure webhooks on each gateway dashboard to https://api.example.com/api/payments/<gateway>/webhook.
  4. Admin β†’ Settings β†’ set Support Email and any contact/social links.

If you later need to enable Google sign-in, set the redirect URI in Google Cloud Console to:

https://api.example.com/api/auth/google/callback

…then add the Client ID and Secret to backend/.env (or re-run setup.sh β†’ option 2) Update Application Configuration), and restart with pm2 restart bookraft-api.

Useful PM2 commands

pm2 list                          # show all processes
pm2 logs bookraft-api             # tail backend logs
pm2 logs bookraft-ui              # tail frontend logs
pm2 restart bookraft-api          # restart backend after .env change
pm2 restart bookraft-ui           # restart frontend (after `npm run build`)
pm2 monit                         # interactive monitor

Updating to a newer version

cd /opt/bookraft-ai
# Replace source: git pull, or upload the new CodeCanyon zip and unzip in place

cd backend  && npm install && cd ..
cd frontend && npm install && npm run build && cd ..

pm2 restart bookraft-api bookraft-ui

If env variables changed in the new release, run sudo bash setup/setup.sh β†’ 2) Update Application Configuration to merge them without overwriting your existing values.

Rolling back

Both scripts write timestamped .bak.YYYYMMDD_HHMMSS backups of any env file they touch. To roll back to a previous configuration:

ls backend/.env.bak.*
cp backend/.env.bak.20260101_120000 backend/.env
pm2 restart bookraft-api

🌐 Deployment

If you can't use the VPS scripts above (e.g. you're deploying to Vercel/Railway, Render, a managed Kubernetes cluster, or a different distro), the platform deploys cleanly as two standard Node apps. The settings below apply to any host.

Frontend

Standard Next.js 16 deployment. Recommended: Vercel.

Backend

Any Node 18+ host (Render, Railway, Fly.io, a $6 VPS, etc.). Required environment:

Persistent uploads

Important: persist backend/uploads/ Generated images are stored on disk under backend/uploads/. On ephemeral hosts (containers, serverless), mount a persistent volume to that path, or proxy uploads to S3/R2. Without persistent storage, generated images vanish on restart.

πŸ›‘ Security checklist before going live

🩺 Troubleshooting

"Server is healthy" but requests fail with CORS

Set CLIENT_URL in backend/.env to the exact origin of your frontend (no trailing slash). Restart the backend.

Google sign-in returns 503

Both GOOGLE_CLIENT_ID and GOOGLE_CLIENT_SECRET must be set. Restart after editing .env.

Image generation returns square images at the wrong size

OpenRouter's chat-completions image modality silently ignores the size parameter. To get the trim size you asked for, add an OPENAI_API_KEY in user Settings β€” the server will route image calls through OpenAI's strict /v1/images/generations.

Contact form returns 503 "not configured"

Either the admin Support Email or the SMTP env vars are missing. Set both: Admin β†’ Settings β†’ Support Email, and SMTP_HOST/SMTP_PORT/SMTP_USER/SMTP_PASS in backend/.env.

Generated images disappear after server restart

You're on an ephemeral filesystem. Mount a persistent volume to backend/uploads/ or change the storage backend.

Backend refuses to boot in production with "JWT_SECRET is missing or set to the placeholder"

This is the intended safeguard. Set a strong unique JWT_SECRET in your production environment.

πŸ“œ Third-party licenses

BookraftAI bundles or depends on the following open-source projects. All are CodeCanyon-compatible (MIT, ISC, Apache 2.0, OFL):

πŸ—’ Changelog

See CHANGELOG.md in the project root for the full version history.

v1.0.0 β€” Initial release

πŸ’¬ Support

For installation help, bugs, and feature questions, contact us via your CodeCanyon item's Comments tab or the Support tab on the item page.

Before opening a support ticket Please include: your Node version (node -v), the relevant log lines from the backend or browser console, and which page or API call surfaced the issue. That cuts the back-and-forth in half.