Skip to main content
This guide walks you through deploying Don Palito Jr to a production environment.

Prerequisites

Before deploying to production, ensure you have:
  • Node.js 20.0.0 or higher installed
  • MongoDB Atlas account (or another MongoDB hosting service)
  • Clerk account configured
  • Cloudinary account set up
  • Stripe account in live mode
  • Inngest account configured
  • Gmail account with app password for emails

Build Process

Don Palito Jr uses a monorepo structure with a root-level build script that coordinates building both the backend and admin panel.

Build Command

From the root directory:
npm run build
This command executes the following sequence (defined in root package.json):
{
  "scripts": {
    "build": "npm install --prefix backend && npm install --prefix admin && npm run build --prefix admin"
  }
}
  1. Install backend dependencies - npm install --prefix backend
  2. Install admin dependencies - npm install --prefix admin
  3. Build admin panel - npm run build --prefix admin
The admin panel is built as a static React application and placed in admin/dist/.

Starting the Server

After building, start the production server:
npm start
This runs:
{
  "scripts": {
    "start": "npm run start --prefix backend"
  }
}
The backend server starts on port 3000 (or the port specified in PORT environment variable) and serves the built admin panel as static files.

Production Environment Setup

1. Database Configuration

Set up MongoDB Atlas for production:
1

Create MongoDB Atlas Cluster

Go to MongoDB Atlas and create a new cluster.
2

Configure Network Access

Add your production server’s IP address to the IP whitelist, or allow access from anywhere (0.0.0.0/0) if using dynamic IPs.
3

Create Database User

Create a database user with read/write permissions.
4

Get Connection String

Copy your connection string and set it as DB_URL:
DB_URL=mongodb+srv://username:password@cluster.mongodb.net/donpalitojr?retryWrites=true&w=majority
The database connection is handled in backend/src/config/db.js:
import mongoose from "mongoose";
import {ENV} from "./env.js";

export const connectDB = async () => {
    try {
        const conn = await mongoose.connect(ENV.DB_URL);
        console.log(`✅ Connected to MongoDB: ${conn.connection.host}`);
    } catch (error) {
        console.log("❌ MONGODB connection error");
        process.exit(1);
    }
}

2. Clerk Authentication

Configure Clerk for production:
1

Switch to Production Instance

In your Clerk dashboard, switch from Development to Production.
2

Update API Keys

Replace test keys with production keys:
  • CLERK_PUBLISHABLE_KEY=pk_live_...
  • CLERK_SECRET_KEY=sk_live_...
3

Configure Webhook

Add webhook endpoint: https://yourdomain.com/api/webhooks/clerkSubscribe to events:
  • user.created
  • user.deleted
Copy the webhook signing secret to CLERK_WEBHOOK_SECRET
The webhook at /api/webhooks/clerk triggers Inngest functions to sync users with MongoDB. Ensure both Clerk and Inngest are properly configured.

3. Cloudinary Setup

Configure Cloudinary for production image storage:
CLOUDINARY_CLOUD_NAME=your-production-cloud
CLOUDINARY_API_KEY=123456789012345
CLOUDINARY_API_SECRET=your-secret-key
Cloudinary is used for product images and can handle high traffic in production. Consider enabling auto-format and auto-quality optimizations.

4. Stripe Configuration

Critical: Switch from test mode to live mode in production!
1

Activate Live Mode

In your Stripe dashboard, switch to Live mode and complete account verification.
2

Update API Keys

Replace test keys with live keys:
STRIPE_SECRET_KEY=sk_live_xxxxxxxxxxxxx
STRIPE_PUBLISHABLE_KEY=pk_live_xxxxxxxxxxxxx
3

Configure Webhook

Add production webhook endpoint: https://yourdomain.com/api/payment/webhookSubscribe to these events:
  • checkout.session.completed
  • payment_intent.succeeded
  • payment_intent.payment_failed
Copy the webhook signing secret:
STRIPE_WEBHOOK_SECRET=whsec_xxxxxxxxxxxxx
The payment webhook uses raw body parsing (required by Stripe):
app.use(
  "/api/payment",
  (req, res, next) => {
    if (req.originalUrl === "/api/payment/webhook") {
      express.raw({ type: "application/json" })(req, res, next);
    } else {
      express.json()(req, res, next);
    }
  },
  paymentRoutes
);

5. Inngest Background Jobs

Configure Inngest for production:
1

Create Production Environment

In Inngest dashboard, create a production environment.
2

Update Signing Key

INNGEST_SIGNING_KEY=signkey-prod-xxxxxxxxxxxxx
3

Register Function Endpoint

Point Inngest to your production endpoint: https://yourdomain.com/api/inngest
Two background functions are configured in backend/src/config/inngest.js:
  1. User Sync (clerk.user.created)
    • Creates user in MongoDB
    • Sends welcome email
  2. User Deletion (clerk.user.deleted)
    • Removes user from MongoDB
export const inngest = new Inngest({
    id: "ecommerce-app",
});

const syncUser = inngest.createFunction(
    {id: "sync-user"},
    {event:"clerk.user.created"},
    async ({event}) => {
        await connectDB();
        const newUser = {
            clerkId: event.data.id,
            email: event.data.email_addresses[0]?.email_address,
            // ... more fields
        };
        await User.create(newUser);
        await sendWelcomeEmail({ userName, userEmail });
    }
);

6. Email Configuration

Set up Gmail for production emails:
1

Enable 2FA

Enable 2-factor authentication on your Gmail account.
2

Generate App Password

Go to Google Account Security and generate an App Password.
3

Configure Environment Variables

ADMIN_EMAIL=yourbusiness@gmail.com
EMAIL_PASSWORD=abcd efgh ijkl mnop
Gmail has sending limits (500 emails/day for free accounts). For high-volume production, consider upgrading to Google Workspace or using a dedicated email service like SendGrid.

CORS and Security

Production CORS Configuration

In production, CORS is restricted to your frontend domain:
const corsOptions = {
  origin: ENV.NODE_ENV === "production" 
    ? ENV.CLIENT_URL  // Only allow your production domain
    : function (origin, callback) {
        // Development allows multiple origins
      },
  credentials: true,
  methods: ['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'OPTIONS'],
  allowedHeaders: ['Content-Type', 'Authorization', 'clerk-session-id']
};
Set your production frontend URL:
CLIENT_URL=https://www.donpalitojr.com

Security Checklist

Before going live, verify these security measures:
  • All API keys are production keys (not test keys)
  • Environment variables are secured (not in version control)
  • CORS is configured for production domain only
  • MongoDB network access is restricted
  • Clerk webhook secret is configured
  • Stripe webhook secret is configured
  • HTTPS is enabled on production domain
  • Rate limiting is configured (if needed)
  • Error messages don’t expose sensitive data

Static File Serving

In production, the backend serves the admin panel as static files:
// backend/src/server.js
if (ENV.NODE_ENV === "production") {
    app.use(express.static(path.join(__dirname, "../admin/dist")));
    app.get("/{*any}", (req, res) => {
        res.sendFile(path.join(__dirname, "../admin", "dist", "index.html"));
    });
}
This serves the built React app from admin/dist/ for all non-API routes.

Hosting Recommendations

Don Palito Jr can be deployed to various platforms:
1

Connect Repository

Connect your GitHub repository to Railway.
2

Configure Build

Railway will automatically detect Node.js. Set:
  • Build Command: npm run build
  • Start Command: npm start
3

Add Environment Variables

Add all required environment variables from the Environment Variables page.
4

Deploy

Railway will build and deploy your application.

Render

1

Create Web Service

Create a new Web Service and connect your repository.
2

Configure Service

  • Build Command: npm run build
  • Start Command: npm start
  • Environment: Node
3

Set Environment Variables

Add all environment variables in the Environment section.

DigitalOcean App Platform

1

Create App

Connect your GitHub repository.
2

Configure Component

  • Type: Web Service
  • Build Command: npm run build
  • Run Command: npm start
3

Add Environment Variables

Configure all required environment variables.

VPS (Ubuntu Server)

For self-hosted deployment:
# Install Node.js 20
curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -
sudo apt-get install -y nodejs

# Clone repository
git clone https://github.com/yourusername/donpalitojr.git
cd donpalitojr

# Create .env file
nano backend/.env
# Add all environment variables

# Build and start
npm run build
npm start
Use PM2 for process management:
sudo npm install -g pm2
cd backend
pm2 start npm --name "donpalitojr" -- start
pm2 startup
pm2 save
For VPS deployment, also configure:
  • Nginx as reverse proxy
  • SSL certificate (Let’s Encrypt)
  • Firewall (UFW)
  • Automatic security updates

Health Check

The application includes a health check endpoint:
curl https://yourdomain.com/api/health
Expected response:
{
  "message": "Success"
}
Root endpoint (/) also returns API information:
{
  "message": "API funcionando correctamente",
  "status": "ok",
  "endpoints": ["/api/health", "/api/products", "/api/cart"]
}

Post-Deployment Verification

After deployment, verify these components:
1

Database Connection

Check server logs for MongoDB connection confirmation:
✅ Connected to MongoDB: cluster0-xxxxx.mongodb.net
2

API Endpoints

Test critical endpoints:
  • GET /api/health
  • GET /api/products
3

Admin Panel

Navigate to your domain and verify the admin panel loads.
4

Webhooks

Test webhooks:
  • Create a test user in Clerk → verify webhook triggers
  • Make a test payment in Stripe → verify webhook processes
5

Background Jobs

Check Inngest dashboard for function execution logs.
6

Email Delivery

Create a test user and verify welcome email is sent.

Monitoring and Logs

Server Startup Logs

When the server starts successfully, you should see:
✅ Connected to MongoDB: cluster0-xxxxx.mongodb.net
🚀 Server is up and running!
💻 Local:        http://localhost:3000
🌍 Environment:  production

Important Log Points

  • MongoDB connection: backend/src/config/db.js:7
  • Server startup: backend/src/server.js:124-136
  • Webhook events: backend/src/server.js:78
  • Inngest sync: backend/src/config/inngest.js:15,42
  • Application monitoring: Use services like Sentry or LogRocket
  • Uptime monitoring: UptimeRobot or Pingdom
  • Performance: New Relic or Datadog
  • Error tracking: Sentry integration

Troubleshooting

Symptoms: Server exits with “MONGODB connection error”Solutions:
  • Verify DB_URL is correct
  • Check MongoDB Atlas IP whitelist
  • Verify database user credentials
  • Ensure cluster is active
Symptoms: Users not syncing to databaseSolutions:
  • Verify CLERK_WEBHOOK_SECRET matches dashboard
  • Check webhook endpoint URL is correct
  • Ensure Inngest is configured
  • Review webhook logs in Clerk dashboard
Symptoms: Checkout not completingSolutions:
  • Verify using live keys (not test keys)
  • Check webhook endpoint is configured
  • Verify STRIPE_WEBHOOK_SECRET
  • Review webhook logs in Stripe dashboard
Symptoms: Frontend can’t connect to APISolutions:
  • Verify CLIENT_URL matches your frontend domain
  • Ensure NODE_ENV=production
  • Check frontend is using correct API URL
  • Verify credentials are enabled in fetch requests
Symptoms: Admin routes return 404Solutions:
  • Ensure npm run build completed successfully
  • Verify admin/dist/ directory exists
  • Check NODE_ENV=production is set
  • Restart the server after building

Next Steps

After successful deployment:
  • Set up automated backups for MongoDB
  • Configure domain and SSL certificate
  • Set up monitoring and alerts
  • Implement rate limiting if needed
  • Review and optimize performance
  • Set up CI/CD pipeline for automated deployments
For development workflow, see the API Reference documentation.

Build docs developers (and LLMs) love