Skip to content

Codex/create ai demo video workflow#33

Open
amaldinesh7 wants to merge 3 commits into
mainfrom
codex/create-ai-demo-video-workflow
Open

Codex/create ai demo video workflow#33
amaldinesh7 wants to merge 3 commits into
mainfrom
codex/create-ai-demo-video-workflow

Conversation

@amaldinesh7
Copy link
Copy Markdown
Owner

@amaldinesh7 amaldinesh7 commented Feb 14, 2026

Summary by CodeRabbit

  • New Features

    • Added demo mode for capturing safe, deterministic product demo videos with simulated queue processing.
    • Added demo video recording and export workflow with optional voiceover and subtitle support.
  • Documentation

    • Added comprehensive guide for the demo video workflow using Playwright, including recording and export commands.
    • Added demo voiceover script and subtitle file for Product Hunt demo presentation.

- Added support for a demo mode in the posting queue, allowing users to simulate posting without actual uploads.
- Introduced new environment variable `NEXT_PUBLIC_QUEUE_DEMO_MODE` to toggle demo functionality.
- Updated API endpoints to handle demo requests, including special headers and responses for demo jobs.
- Enhanced the `usePostingQueue` and `useQueueJob` hooks to accommodate demo mode logic.
- Modified `.gitignore` to exclude demo output files and updated `package.json` with new demo-related scripts.

This feature improves the testing and demonstration capabilities of the application by providing a safe environment for users to explore posting functionalities without affecting real data.
- Modified test fixture values for Supabase user IDs to ensure consistency across tests.
- Enhanced the product hunt demo test to avoid strict-mode collisions by selecting the first occurrence of the "All done!" text.
- Added mock responses for new API endpoints including `/api/reddit/subreddit-info` and `/api/pricing` to prevent live calls during E2E tests.
- Implemented a mock for the `/api/admin-check` endpoint to simulate admin status.

These changes improve the reliability and accuracy of tests by ensuring that mock data and responses are correctly configured.
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Feb 14, 2026

📝 Walkthrough

Walkthrough

This PR introduces a complete demo-mode infrastructure for deterministic video capture. It adds API routes for simulated queue processing, client-side routing to demo endpoints, Playwright test configuration and test specs, documentation, and export tooling. The demo mode is controlled by the NEXT_PUBLIC_QUEUE_DEMO_MODE environment variable and prevents actual network posts while simulating queue progress via streaming responses.

Changes

Cohort / File(s) Summary
Demo API Routes
pages/api/queue/demo.ts, pages/api/queue/process.ts, pages/api/queue/submit.ts
New /api/queue/demo endpoint for streaming simulated queue processing. Modified process.ts to detect demo requests via x-rmp-demo header and stream progress updates. Modified submit.ts to block file uploads in demo mode and return mock jobId.
Client-side Demo Integration
hooks/usePostingQueue.ts, hooks/useQueueJob.ts
Updated to detect NEXT_PUBLIC_QUEUE_DEMO_MODE flag and route requests to /api/queue/demo when enabled. Added demo headers and disabled auto-subscription to realtime updates during demo mode.
Demo Pages & UI
pages/demo/cards.tsx
New page component rendering stylized demo cards with variants (hook, problem, cta) for intro/transition steps.
Test Infrastructure
tests/demo/product-hunt-demo.spec.ts, tests/fixtures/auth.ts, tests/fixtures/test-data.ts, tests/mocks/handlers.ts
Added e2e Playwright test spec for demo video capture. Updated fixture user IDs to standardized UUIDs. Standardized mock response structure for API endpoints with { success, data } wrapper.
Demo Documentation & Tooling
docs/DEMO_VIDEO.md, docs/demo/product-hunt-demo-voiceover.md, docs/demo/product-hunt-demo.srt, scripts/export-demo-video.cjs, playwright.demo.config.ts
Documentation of three-step demo workflow, voiceover script, subtitle file. New video export script handling webm/mp4 conversion with ffmpeg. Demo-specific Playwright config with port 3100 and video recording enabled.
Project Configuration
.gitignore, package.json
Added /demo-output/ to .gitignore. Added demo:video and demo:export npm scripts.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant usePostingQueue as usePostingQueue Hook
    participant API as API Route
    participant DemoQueue as Demo Queue Handler
    participant Browser as Browser (Recording)

    Client->>usePostingQueue: processBatch() with NEXT_PUBLIC_QUEUE_DEMO_MODE=1
    usePostingQueue->>usePostingQueue: Detect demo mode, compute queueEndpoint
    usePostingQueue->>API: POST /api/queue/demo (or POST /api/queue with demo headers)
    API->>DemoQueue: Route to demo handler
    DemoQueue->>DemoQueue: Simulate delays & processing
    DemoQueue->>API: Stream JSON lines (started, posting, success, complete)
    API->>Browser: Stream progress updates
    Browser->>Browser: Record video during streaming responses
    DemoQueue->>API: Return final completed status
    API->>Client: Close stream
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~30 minutes

Possibly related PRs

  • PR #8: Modifies queue-related files (hooks/useQueueJob.ts, pages/api/queue/process.ts) with queue error-handling changes that may interact with this PR's demo-mode modifications.
  • PR #19: Updates hooks/useQueueJob.ts with timing metadata and submit-related API changes that overlap with this PR's demo-mode header additions.
  • PR #32: Modifies pages/api/queue/process.ts with entitlement-based gating logic that shares the same file as this PR's demo streaming branch.

Poem

🐰 Hop, hop! A demo mode so fine,
Playwright captures each frame in time,
No real posts, just simulated dreams,
Video exports flow like streams,
Watch the queue dance without a care! 🎬

🚥 Pre-merge checks | ✅ 3 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 40.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Codex/create ai demo video workflow' accurately reflects the main objective of this PR: adding a complete demo video workflow with AI-assisted voiceover and caption support.
Merge Conflict Detection ✅ Passed ✅ No merge conflicts detected when merging into main

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch codex/create-ai-demo-video-workflow

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.

@amaldinesh7 amaldinesh7 changed the base branch from codex/trial-week-auto-downgrade to main February 15, 2026 12:52
Copy link
Copy Markdown

@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: 2

🤖 Fix all issues with AI agents
In `@pages/api/queue/demo.ts`:
- Around line 58-62: The handler in pages/api/queue/demo.ts lacks the demo-mode
guard, so add the same check used in pages/api/queue/submit.ts and
pages/api/queue/process.ts: verify process.env.NEXT_PUBLIC_QUEUE_DEMO_MODE ===
'true' and that the request includes the x-rmp-demo header (or return 405/403 as
those files do) before executing demo logic in the default exported async
function handler; if the guard fails, short-circuit the request with the same
response/status used by the other demo endpoints to prevent demo responses when
demo mode is disabled.

In `@pages/api/queue/submit.ts`:
- Around line 95-99: The parseInt call when deriving sharedFileCount can yield
unexpected results because it lacks an explicit radix; update the conversion in
submit.ts where sharedFileCountField is parsed (variables: sharedFileCountField,
sharedFileCount) to call parseInt(sharedFileCountField as string, 10) so the
value is always interpreted as base 10.
🧹 Nitpick comments (7)
pages/demo/cards.tsx (1)

38-38: Use const arrow function instead of function declaration.

As per coding guidelines, "Use const arrow functions instead of function declarations (e.g., const toggle = () =>)".

Proposed fix
-export default function DemoCardsPage() {
+const DemoCardsPage = () => {

And at the end of the file:

export default DemoCardsPage;
scripts/export-demo-video.cjs (1)

40-43: hasFfmpeg may silently treat spawn errors as "not found".

When ffmpeg binary doesn't exist, spawnSync returns { status: null, error: <ENOENT> }. The status === 0 check happens to return false, which is the desired behavior, but it conflates "not installed" with "crashed on startup." For a utility script this is acceptable, but a more robust check would inspect result.error:

Optional: more explicit check
 const hasFfmpeg = () => {
   const result = spawnSync('ffmpeg', ['-version'], { stdio: 'ignore' });
-  return result.status === 0;
+  return !result.error && result.status === 0;
 };
package.json (1)

11-12: Cross-platform compatibility: inline env var syntax is Unix-only.

NEXT_PUBLIC_QUEUE_DEMO_MODE=1 npx playwright ... won't work on Windows. If Windows support matters, consider using cross-env.

Optional fix using cross-env
-    "demo:video": "NEXT_PUBLIC_QUEUE_DEMO_MODE=1 npx playwright test -c playwright.demo.config.ts tests/demo/product-hunt-demo.spec.ts --project=chromium --workers=1 --headed",
+    "demo:video": "cross-env NEXT_PUBLIC_QUEUE_DEMO_MODE=1 npx playwright test -c playwright.demo.config.ts tests/demo/product-hunt-demo.spec.ts --project=chromium --workers=1 --headed",
pages/api/queue/process.ts (2)

64-114: Demo streaming ignores submitted subreddits in favor of hardcoded list.

The demo branch streams results for a hardcoded ['pics', 'images', 'gifs'] list, regardless of which subreddits the client actually submitted. This works for the current demo test (which selects exactly those three), but if the demo spec ever changes the selected subreddits, the results will be mismatched.

Consider reading the item list from the submit payload (or the request) for resilience, or at minimum add a comment explaining the coupling.


67-69: Minor inconsistency between demo and production streaming headers.

Demo path sets text/plain; charset=utf-8, no-cache, no-transform, while production uses text/plain, no-cache. The difference is harmless but unnecessarily inconsistent.

Align headers
-      res.setHeader('Content-Type', 'text/plain; charset=utf-8');
-      res.setHeader('Cache-Control', 'no-cache, no-transform');
-      res.setHeader('Connection', 'keep-alive');
+      res.setHeader('Content-Type', 'text/plain');
+      res.setHeader('Cache-Control', 'no-cache');
+      res.setHeader('Connection', 'keep-alive');

Also applies to: 153-155

pages/api/queue/demo.ts (2)

69-73: Consider wrapping the streaming section in try/catch.

If res.write or sleep throws mid-stream (e.g., client disconnects), the error is unhandled. A defensive try/catch around the streaming logic (Lines 69–102) would let you close the response cleanly.

Proposed fix
+  try {
   res.statusCode = 200;
   res.setHeader('Content-Type', 'text/plain; charset=utf-8');
   res.setHeader('Cache-Control', 'no-cache, no-transform');
   res.setHeader('Connection', 'keep-alive');
   res.flushHeaders?.();
 
   const delaySeconds = 2;
   writeLine(res, { status: 'started', total: parsed.items.length });
   await sleep(700);
 
   for (let index = 0; index < parsed.items.length; index++) {
     ...
   }
 
   writeLine(res, { status: 'completed' });
   return res.end();
+  } catch {
+    if (!res.writableEnded) res.end();
+  }

58-58: Guideline: prefer const arrow functions over function declarations.

The coding guidelines state to use const arrow functions. However, Next.js API routes conventionally use export default function handler, so this is a minor stylistic note.

As per coding guidelines, "Use const arrow functions instead of function declarations (e.g., const toggle = () =>)".

Comment thread pages/api/queue/demo.ts
Comment on lines +58 to +62
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
if (req.method !== 'POST') {
res.setHeader('Allow', 'POST');
return res.status(405).json({ error: 'Method not allowed' });
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Missing demo-mode guard — endpoint is accessible even when demo mode is disabled.

Unlike pages/api/queue/submit.ts and pages/api/queue/process.ts, which check NEXT_PUBLIC_QUEUE_DEMO_MODE and the x-rmp-demo header before entering demo logic, this endpoint has no such guard. In production (with demo mode off), anyone can hit /api/queue/demo and get simulated responses.

Proposed fix
 export default async function handler(req: NextApiRequest, res: NextApiResponse) {
   if (req.method !== 'POST') {
     res.setHeader('Allow', 'POST');
     return res.status(405).json({ error: 'Method not allowed' });
   }
 
+  const demoEnv = process.env.NEXT_PUBLIC_QUEUE_DEMO_MODE;
+  const demoHeader = req.headers['x-rmp-demo'];
+  const demoHeaderValue = Array.isArray(demoHeader) ? demoHeader[0] : demoHeader;
+  const isDemoEnabled =
+    (demoEnv === 'true' || demoEnv === '1') && demoHeaderValue === '1';
+
+  if (!isDemoEnabled) {
+    return res.status(403).json({ error: 'Demo mode is not enabled' });
+  }
+
   const parsed = parseBody(req);
📝 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
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
if (req.method !== 'POST') {
res.setHeader('Allow', 'POST');
return res.status(405).json({ error: 'Method not allowed' });
}
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
if (req.method !== 'POST') {
res.setHeader('Allow', 'POST');
return res.status(405).json({ error: 'Method not allowed' });
}
const demoEnv = process.env.NEXT_PUBLIC_QUEUE_DEMO_MODE;
const demoHeader = req.headers['x-rmp-demo'];
const demoHeaderValue = Array.isArray(demoHeader) ? demoHeader[0] : demoHeader;
const isDemoEnabled =
(demoEnv === 'true' || demoEnv === '1') && demoHeaderValue === '1';
if (!isDemoEnabled) {
return res.status(403).json({ error: 'Demo mode is not enabled' });
}
const parsed = parseBody(req);
🤖 Prompt for AI Agents
In `@pages/api/queue/demo.ts` around lines 58 - 62, The handler in
pages/api/queue/demo.ts lacks the demo-mode guard, so add the same check used in
pages/api/queue/submit.ts and pages/api/queue/process.ts: verify
process.env.NEXT_PUBLIC_QUEUE_DEMO_MODE === 'true' and that the request includes
the x-rmp-demo header (or return 405/403 as those files do) before executing
demo logic in the default exported async function handler; if the guard fails,
short-circuit the request with the same response/status used by the other demo
endpoints to prevent demo responses when demo mode is disabled.

Comment thread pages/api/queue/submit.ts
Comment on lines +95 to +99
// Get shared file count from form data
const sharedFileCountField = Array.isArray(fields.sharedFileCount)
? fields.sharedFileCount[0]
: fields.sharedFileCount;
const sharedFileCount = sharedFileCountField ? parseInt(sharedFileCountField as string) : 0;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Missing radix parameter in parseInt.

parseInt without an explicit radix can cause unexpected behavior in edge cases. Always pass radix 10.

Proposed fix
-    const sharedFileCount = sharedFileCountField ? parseInt(sharedFileCountField as string) : 0;
+    const sharedFileCount = sharedFileCountField ? parseInt(sharedFileCountField as string, 10) : 0;
📝 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
// Get shared file count from form data
const sharedFileCountField = Array.isArray(fields.sharedFileCount)
? fields.sharedFileCount[0]
: fields.sharedFileCount;
const sharedFileCount = sharedFileCountField ? parseInt(sharedFileCountField as string) : 0;
// Get shared file count from form data
const sharedFileCountField = Array.isArray(fields.sharedFileCount)
? fields.sharedFileCount[0]
: fields.sharedFileCount;
const sharedFileCount = sharedFileCountField ? parseInt(sharedFileCountField as string, 10) : 0;
🤖 Prompt for AI Agents
In `@pages/api/queue/submit.ts` around lines 95 - 99, The parseInt call when
deriving sharedFileCount can yield unexpected results because it lacks an
explicit radix; update the conversion in submit.ts where sharedFileCountField is
parsed (variables: sharedFileCountField, sharedFileCount) to call
parseInt(sharedFileCountField as string, 10) so the value is always interpreted
as base 10.

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.

1 participant