Skip to content

Conversation

yashranaway
Copy link
Contributor

@yashranaway yashranaway commented Oct 8, 2025

πŸ“‹ Description

Add Express + MongoDB boilerplate guide with webhook handling and Mongo persistence. Link it under Integration Guides and Community β†’ Boilerplates.

🎯 Type of Change

  • πŸ“ Documentation update (improving existing docs)
  • ✨ New documentation (adding new guides, API docs, etc.)
  • πŸ› Bug fix (fixing errors, broken links, incorrect information)
  • 🎨 Style/formatting (improving readability, fixing formatting)
  • πŸ—οΈ Structural change (reorganizing content, navigation updates)
  • 🌐 Translation (adding or improving translations)
  • πŸ–ΌοΈ Assets (adding or updating images, diagrams)

πŸ“– What documentation does this PR affect?

  • Getting Started / Setup
  • API Reference
  • Developer Resources
  • Integration Guides
  • Features Documentation
  • External Integrations
  • Changelog
  • Other: Community β†’ Boilerplates & Starters

βœ… Checklist

  • I have read the Contributing Guidelines
  • I have tested my changes locally with mintlify dev
  • All links are working correctly
  • Images are properly displayed and optimized
  • Code examples are tested and working
  • I have updated the navigation in docs.json (if applicable)
  • My changes follow the project's style guide
  • I have performed a self-review of my changes
  • I have added appropriate frontmatter to new pages

πŸ§ͺ Testing

  • Verified locally at http://localhost:3000 (served at 3002)
  • Checked responsive design on mobile viewport
  • Tested all code examples
  • Validated all external links

πŸ“Έ Screenshots (if applicable)

N/A

πŸ”— Related Issues

Closes #99

πŸ“ Additional Notes

Includes dodopayments-webhooks usage, raw body verification, Mongo models, and routes.

Summary by CodeRabbit

  • Documentation
    • Added a comprehensive Express + MongoDB boilerplate guide covering setup, quickstart, routes for payments, subscriptions, and webhooks, plus environment configuration and deployment notes.
    • Included guidance on webhook signature verification, raw-body handling, input validation, error handling, and data-modeling recommendations.
    • Added a new card under β€œBoilerplates & Starters” highlighting the Express + MongoDB Boilerplate (Dodo Payments).
    • Updated site navigation to include the new guide under Developer Resources β†’ Integration Guides.

Copy link
Contributor

coderabbitai bot commented Oct 8, 2025

Walkthrough

Adds an Express + MongoDB boilerplate guide, inserts it into Developer Resources navigation, and adds a corresponding card under Community β†’ Boilerplates & Starters.

Changes

Cohort / File(s) Summary of edits
Community listing update
community/projects.mdx
Added a new card for "Express + MongoDB Boilerplate (Dodo Payments)" under the Boilerplates & Starters section, placed before the existing DodoPayments entry.
New integration guide content
developer-resources/express-mongodb-boilerplate.mdx
Added a new developer guide describing a TypeScript Express + MongoDB starter: project structure, env config, DB client/models, payments/subscriptions routes, webhook raw-body verification and handlers, and deployment notes with code snippets.
Docs navigation update
docs.json
Inserted developer-resources/express-mongodb-boilerplate into Developer Resources β†’ Integration Guides pages array.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor Dev as Client
  participant API as Express API
  participant Dodo as Dodo Payments
  participant DB as MongoDB

  rect rgba(200,235,255,0.25)
  note over API: Create Payment flow
  Dev->>API: POST /api/payments {amount, currency, ...}
  API->>Dodo: createPayment(payload)
  Dodo-->>API: payment {id, status, ...}
  API->>DB: upsert Payment document
  API-->>Dev: 201 Created {payment}
  end
Loading
sequenceDiagram
  autonumber
  actor Dev as Client
  participant API as Express API
  participant Dodo as Dodo Payments
  participant DB as MongoDB

  rect rgba(220,255,220,0.25)
  note over API: Create Subscription flow
  Dev->>API: POST /api/subscriptions {planId, customer, ...}
  API->>Dodo: createSubscription(payload)
  Dodo-->>API: subscription {id, status, ...}
  API->>DB: upsert Subscription document
  API-->>Dev: 201 Created {subscription}
  end
Loading
sequenceDiagram
  autonumber
  participant Dodo as Dodo Payments
  participant API as Express Webhook Endpoint
  participant DB as MongoDB

  rect rgba(255,245,200,0.35)
  note over API: Webhook verification using raw body
  Dodo->>API: POST /webhooks (signature header + raw body)
  API->>API: verifySignature(rawBody, header)
  alt signature valid
    API->>DB: upsert/update by event type (subscription.active, on_hold, payment.succeeded, payment.failed)
    API-->>Dodo: 200 OK
  else invalid
    API-->>Dodo: 400/401 Error
  end
  end
Loading

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Possibly related PRs

  • Update projects.mdxΒ #90 β€” Adds a Boilerplates & Starters card to community/projects.mdx (Next.js starter); touches the same community listing area and card patterns.

Poem

A rabbit hops in, docs held tight,
β€œExpress and Mongoβ€”set up tonight!”
Webhooks listen, payments arrive,
Models snug, the starter's alive.
Nibble the README, deploy with delight. πŸ₯•

Pre-merge checks and finishing touches

βœ… Passed checks (5 passed)
Check name Status Explanation
Title Check βœ… Passed The pull request title succinctly describes the primary change of adding an Express + MongoDB boilerplate to the community projects and documentation, and it uses conventional commit styling to indicate a new feature. It clearly highlights the main addition without extraneous details or generic phrasing. Therefore, it accurately reflects the contents of the changeset.
Linked Issues Check βœ… Passed The changes satisfy all coding-related objectives from issue #99 by introducing an Express + MongoDB boilerplate template in Community β†’ Boilerplates & Starters, providing TypeScript-based examples for payments, subscriptions, and webhooks with raw-body validation, persisting events to MongoDB, and recommending usage of the dodopayments-webhooks library. The PR places the new guide within the Integration Guides section and updates navigation accordingly, directly addressing the linked issue requirements.
Out of Scope Changes Check βœ… Passed All modifications are relevant to adding the new boilerplate and documentation, including updates to community projects, creation of the Express + MongoDB guide, and navigation adjustments. There are no unrelated files or features introduced outside the scope defined by the linked issue and PR objectives. Thus, the changes remain focused and appropriate.
Description Check βœ… Passed The pull request description follows the repository template by including sections for a clear description, change type, affected documentation areas, a comprehensive checklist, testing steps, related issues, and additional notes, ensuring all critical information is provided. The headings match the required template and the content under each is complete and specific to this PR’s changes. Overall, the description is thorough and structured according to the guidelines.
Docstring Coverage βœ… Passed No functions found in the changes. Docstring coverage check skipped.
✨ Finishing touches
πŸ§ͺ Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❀️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

πŸ“œ Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

πŸ“₯ Commits

Reviewing files that changed from the base of the PR and between 8ce6a50 and 2ffccc6.

πŸ“’ Files selected for processing (3)
  • community/projects.mdx (1 hunks)
  • developer-resources/express-mongodb-boilerplate.mdx (1 hunks)
  • docs.json (1 hunks)
🧰 Additional context used
πŸ““ Path-based instructions (2)
**/*.{md,mdx}

πŸ“„ CodeRabbit inference engine (.cursor/rules/mintlify.mdc)

Every documentation page must begin with YAML frontmatter containing title and description

Files:

  • community/projects.mdx
  • developer-resources/express-mongodb-boilerplate.mdx
**/*.mdx

πŸ“„ CodeRabbit inference engine (.cursor/rules/mintlify.mdc)

**/*.mdx: Use clear, direct language appropriate for technical audiences
Write instructions in second person (you)
Use active voice over passive voice
Use present tense for current states and future tense for outcomes
Maintain consistent terminology across documentation
Keep sentences concise while preserving necessary context
Use parallel structure in lists, headings, and procedures
Lead sections with the most important information (inverted pyramid)
Use progressive disclosure: introduce basics before advanced topics
Break complex procedures into numbered steps using /
Include prerequisites and context before instructions
Provide expected outcomes for each major step
End sections with next steps or related information
Use descriptive, keyword-rich headings for navigation and SEO
Focus on user goals and outcomes rather than system features
Anticipate common questions and address them proactively
Include troubleshooting for likely failure points
Provide multiple pathways (beginner vs advanced) when appropriate, with an opinionated recommended path
Use for supplementary information that supports main content
Use for expert advice, shortcuts, or best practices
Use for critical cautions, breaking changes, or destructive actions
Use for neutral background or contextual information
Use for success confirmations or achievement indicators
Use to present the same concept in multiple languages
Provide complete, runnable code examples with language specified and filename when relevant
Include RequestExample/ResponseExample blocks for API endpoint docs
Document API parameters using (path, query, header, body) with types and required/defaults
Document API responses using with names, types, and required flags
Use for nested object properties or hierarchical information
Use / for platform-specific or alternative approaches
Use / for suppl...

Files:

  • community/projects.mdx
  • developer-resources/express-mongodb-boilerplate.mdx
πŸ”‡ Additional comments (2)
community/projects.mdx (1)

52-56: Card addition looks solid.

Clear positioning, concise pitch, and consistent tag list. Nice addition.

docs.json (1)

126-126: Navigation entry added in the right slot.

Keeps the Integration Guides grouping coherent.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (2)
developer-resources/express-mongodb-boilerplate.mdx (2)

58-71: esModuleInterop guidance added β€” resolves prior blocker.

The Tip addresses the earlier default-import compilation issue and clearly sets required tsconfig flags. Good.


171-177: Fix no‑esModuleInterop example: default import of SDK will fail.

Without esModuleInterop, import DodoPayments from 'dodopayments' can break. Use TS import = require to instantiate safely.

Apply this diff:

-// src/routes/payments.ts (no esModuleInterop)
-import * as express from 'express';
-import DodoPayments from 'dodopayments';
+// src/routes/payments.ts (no esModuleInterop)
+import * as express from 'express';
+import DodoPayments = require('dodopayments');

 const client = new DodoPayments({ bearerToken: process.env.DODO_PAYMENTS_API_KEY });
 const router = express.Router();
🧹 Nitpick comments (8)
developer-resources/express-mongodb-boilerplate.mdx (8)

290-297: Add idempotency (dedup) for webhook events.

Retries can re-deliver the same event; current handler will reprocess. Dedup by webhook-id with a unique collection.

Apply these diffs to the snippets:

  1. models.ts: add ProcessedEvent model with unique _id
 // src/db/models.ts
 import mongoose from 'mongoose';
+const { Schema } = mongoose;
@@
 export const Payment = mongoose.model('Payment', PaymentSchema);
 export const Subscription = mongoose.model('Subscription', SubscriptionSchema);
+const ProcessedEventSchema = new Schema(
+  { _id: { type: String, required: true } },
+  { timestamps: true }
+);
+ProcessedEventSchema.index({ _id: 1 }, { unique: true });
+export const ProcessedEvent = mongoose.model('ProcessedEvent', ProcessedEventSchema);
  1. webhooks.ts: import and short-circuit on duplicates
-import { Subscription, Payment } from '../db/models';
+import { Subscription, Payment, ProcessedEvent } from '../db/models';
@@
-    await webhook.verify(rawBody, headers);
+    await webhook.verify(rawBody, headers);
+    // Idempotency: store event id; ignore if already processed
+    try {
+      await ProcessedEvent.create({ _id: headers['webhook-id'] });
+    } catch (e: any) {
+      if (e?.code === 11000) {
+        return res.json({ received: true });
+      }
+      throw e;
+    }

Also applies to: 299-315, 365-373


192-227: Return 500 for server errors; reserve 400 for bad input.

Currently all exceptions map to 400. Differentiate validation vs server errors.

Apply this diff in both routes:

   router.post('/', async (req, res) => {
-  try {
+  try {
     const {
@@
-    if (!billing || !customer || !product_cart) {
-      return res.status(400).json({ error: 'billing, customer, and product_cart are required' });
+    if (!billing || !customer || !product_cart) {
+      return res.status(400).json({ error: 'billing, customer, and product_cart are required' });
     }
@@
-    res.json(payment);
-  } catch (err: any) {
-    res.status(400).json({ error: err.message });
+    res.json(payment);
+  } catch (err: any) {
+    const status = err?.name === 'ValidationError' ? 400 : 500;
+    res.status(status).json({ error: err.message ?? 'Internal Server Error' });
   }

Repeat analogous change for subscriptions route (validation 400; others 500).

Also applies to: 242-279


98-121: Tighten Mongoose schema types and indexes.

Use Mixed/Map for metadata, and make ids unique for faster upserts and integrity.

Apply this diff:

-const CustomerSchema = new mongoose.Schema({
-  customerId: { type: String, index: true },
+const CustomerSchema = new mongoose.Schema({
+  customerId: { type: String, index: true, unique: true },
   email: String,
   name: String,
 });
 
-const PaymentSchema = new mongoose.Schema({
-  paymentId: { type: String, index: true },
+const PaymentSchema = new mongoose.Schema({
+  paymentId: { type: String, index: true, unique: true },
   status: String,
   amount: Number,
   currency: String,
   customerId: String,
-  metadata: {},
+  metadata: { type: mongoose.Schema.Types.Mixed, default: {} },
 });
 
-const SubscriptionSchema = new mongoose.Schema({
-  subscriptionId: { type: String, index: true },
+const SubscriptionSchema = new mongoose.Schema({
+  subscriptionId: { type: String, index: true, unique: true },
   status: String,
   productId: String,
   customerId: String,
   currentPeriodEnd: Date,
-  metadata: {},
+  metadata: { type: mongoose.Schema.Types.Mixed, default: {} },
 });

334-338: Consider upsert for state‑only updates.

If an on_hold/failed event arrives before initial creation, the update will no‑op. Upsert ensures record presence.

Apply this diff:

 await Subscription.updateOne(
   { subscriptionId: data.subscription_id },
-  { status: 'on_hold' }
+  { status: 'on_hold' },
+  { upsert: true }
 );
@@
 await Payment.updateOne(
   { paymentId: p.payment_id },
-  { status: 'failed' }
+  { status: 'failed' },
+  { upsert: true }
 );

Also applies to: 359-362


49-56: Use Steps and include a run/test step.

Make the Quickstart executable end‑to‑end with a start command and verification.

Apply this diff:

-## Quickstart
-
-```bash
-npm init -y
-npm install express mongoose cors dotenv dodopayments standardwebhooks
-npm install -D typescript ts-node @types/express @types/node @types/cors
-npx tsc --init
-```
+## Quickstart
+
+<Steps>
+  <Step title="Initialize project">
+    ```bash
+    npm init -y
+    npm install express mongoose cors dotenv dodopayments standardwebhooks
+    npm install -D typescript ts-node @types/express @types/node @types/cors
+    npx tsc --init
+    ```
+  </Step>
+  <Step title="Add a start script">
+    ```json filename="package.json"
+    {
+      "scripts": {
+        "dev": "ts-node src/app.ts"
+      }
+    }
+    ```
+  </Step>
+  <Step title="Run and verify">
+    ```bash
+    npm run dev
+    # Expect: "Server listening on :3000"
+    ```
+  </Step>
+</Steps>

73-80: Use realistic env examples and warn against committing secrets.

Prefer a local Mongo URI in examples and add a secrets warning.

Apply this diff:

-```bash
-DODO_PAYMENTS_API_KEY=sk_test_xxx
-DODO_WEBHOOK_SECRET=whsec_xxx
-MONGODB_URI=mongodb+srv://<user>:<pass>@<cluster>/dodo?retryWrites=true&w=majority
-PORT=3000
-```
+```bash
+DODO_PAYMENTS_API_KEY=sk_test_1234567890
+DODO_WEBHOOK_SECRET=whsec_1234567890
+# Local dev
+MONGODB_URI=mongodb://127.0.0.1:27017/dodo
+PORT=3000
+```
+
+<Warning>
+Never commit .env files or secrets to source control. Use environment variables in production.
+</Warning>

88-91: Handle connecting state and surface connection errors.

Avoid duplicate connects and add basic error handling.

Apply this diff:

 export async function connectDB(uri: string) {
-  if (mongoose.connection.readyState === 1) return;
-  await mongoose.connect(uri, { dbName: 'dodo' });
+  if (mongoose.connection.readyState === 1 || mongoose.connection.readyState === 2) return;
+  try {
+    await mongoose.connect(uri, { dbName: 'dodo' });
+  } catch (err) {
+    console.error('Mongo connection error', err);
+    throw err;
+  }
 }

379-381: Reinforce raw‑body constraint with a code hint.

Add a minimal snippet showing path‑scoped raw as an alternative to router‑level.

Apply this diff:

 <Warning>
 Ensure your Express app does not use `express.json()` on the webhook route, as it must read the raw body for signature verification.
+```ts
+// Alternative: path-scoped raw
+app.post('/webhooks/dodo', raw({ type: '*/*' }), webhooksRouter);
+```
 </Warning>
πŸ“œ Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

πŸ“₯ Commits

Reviewing files that changed from the base of the PR and between 2ffccc6 and 65439a4.

πŸ“’ Files selected for processing (1)
  • developer-resources/express-mongodb-boilerplate.mdx (1 hunks)
🧰 Additional context used
πŸ““ Path-based instructions (2)
**/*.{md,mdx}

πŸ“„ CodeRabbit inference engine (.cursor/rules/mintlify.mdc)

Every documentation page must begin with YAML frontmatter containing title and description

Files:

  • developer-resources/express-mongodb-boilerplate.mdx
**/*.mdx

πŸ“„ CodeRabbit inference engine (.cursor/rules/mintlify.mdc)

**/*.mdx: Use clear, direct language appropriate for technical audiences
Write instructions in second person (you)
Use active voice over passive voice
Use present tense for current states and future tense for outcomes
Maintain consistent terminology across documentation
Keep sentences concise while preserving necessary context
Use parallel structure in lists, headings, and procedures
Lead sections with the most important information (inverted pyramid)
Use progressive disclosure: introduce basics before advanced topics
Break complex procedures into numbered steps using /
Include prerequisites and context before instructions
Provide expected outcomes for each major step
End sections with next steps or related information
Use descriptive, keyword-rich headings for navigation and SEO
Focus on user goals and outcomes rather than system features
Anticipate common questions and address them proactively
Include troubleshooting for likely failure points
Provide multiple pathways (beginner vs advanced) when appropriate, with an opinionated recommended path
Use for supplementary information that supports main content
Use for expert advice, shortcuts, or best practices
Use for critical cautions, breaking changes, or destructive actions
Use for neutral background or contextual information
Use for success confirmations or achievement indicators
Use to present the same concept in multiple languages
Provide complete, runnable code examples with language specified and filename when relevant
Include RequestExample/ResponseExample blocks for API endpoint docs
Document API parameters using (path, query, header, body) with types and required/defaults
Document API responses using with names, types, and required flags
Use for nested object properties or hierarchical information
Use / for platform-specific or alternative approaches
Use / for suppl...

Files:

  • developer-resources/express-mongodb-boilerplate.mdx

Comment on lines +286 to +301
```ts
// src/routes/webhooks.ts
import { Router } from 'express';
import { raw } from 'express';
import { Subscription, Payment } from '../db/models';
import { Webhook, type WebhookUnbrandedRequiredHeaders } from 'standardwebhooks';

const router = Router();

// Use Standard Webhooks with your secret
const webhook = new Webhook(process.env.DODO_WEBHOOK_SECRET as string);

// Use raw body for signature verification (must not be pre-parsed by express.json())
router.post('/', raw({ type: 'application/json' }), async (req, res) => {
try {
const rawBody = req.body.toString('utf8');
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Use raw('/') for robust signature verification.

Webhook providers may send content-types like application/webhook+json or include charset; raw({ type: 'application/json' }) can miss these.

Apply this diff:

-// Use raw body for signature verification (must not be pre-parsed by express.json())
-router.post('/', raw({ type: 'application/json' }), async (req, res) => {
+// Use raw body for signature verification (must not be pre-parsed by express.json())
+router.post('/', raw({ type: '*/*' }), async (req, res) => {
πŸ“ Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
```ts
// src/routes/webhooks.ts
import { Router } from 'express';
import { raw } from 'express';
import { Subscription, Payment } from '../db/models';
import { Webhook, type WebhookUnbrandedRequiredHeaders } from 'standardwebhooks';
const router = Router();
// Use Standard Webhooks with your secret
const webhook = new Webhook(process.env.DODO_WEBHOOK_SECRET as string);
// Use raw body for signature verification (must not be pre-parsed by express.json())
router.post('/', raw({ type: 'application/json' }), async (req, res) => {
try {
const rawBody = req.body.toString('utf8');
// src/routes/webhooks.ts
import { Router } from 'express';
import { raw } from 'express';
import { Subscription, Payment } from '../db/models';
import { Webhook, type WebhookUnbrandedRequiredHeaders } from 'standardwebhooks';
const router = Router();
// Use Standard Webhooks with your secret
const webhook = new Webhook(process.env.DODO_WEBHOOK_SECRET as string);
// Use raw body for signature verification (must not be pre-parsed by express.json())
router.post('/', raw({ type: '*/*' }), async (req, res) => {
try {
const rawBody = req.body.toString('utf8');
πŸ€– Prompt for AI Agents
In developer-resources/express-mongodb-boilerplate.mdx around lines 286 to 301,
the webhook route uses raw({ type: 'application/json' }) which can miss webhook
requests that use non-standard content-types (e.g., application/webhook+json or
include a charset); update the middleware to use raw({ type: '*/*' }) so the raw
body is preserved for all content-types (or an equivalent predicate that returns
true), keeping signature verification reliable, and ensure the rest of the
handler continues to call req.body.toString('utf8') as before.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feature]: Create & add an Express + MongoDB boilerplate template

1 participant