afterFiles ordering was insufficient in Next.js 14 — the catch-all
/api/v1/* rewrite still intercepted SSE requests before route handlers.
Fix: add a `missing` condition on `Accept: text/event-stream` to the
rewrite rule. EventSource always sends this header, so SSE requests now
skip the rewrite entirely and are handled by the existing route handlers
(app/api/v1/ppt/outlines/stream, presentation/stream, jobs/stream).
Normal JSON API requests are unaffected.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The flat-array form of rewrites() runs as beforeFiles, intercepting /api/v1/*
requests before Next.js can match route handlers. This caused the SSE stream
endpoints (outlines/stream, presentation/stream, jobs/stream) to be handled
by the buffering HTTP proxy instead of the custom streaming route handlers,
resulting in ECONNRESET → 500 on the browser.
afterFiles rewrites only apply when no matching app/api/ file exists, so
route handlers now win over the backend proxy for all /api/v1/* paths that
have explicit handlers.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- New POST /api/generate-pptx route (Next.js) uses PptxGenJS to build
PPTX directly from the Phase 8 JSON element model — no headless Chrome
- export_utils.py queries DB for slides + layout codes, POSTs payload to
Next.js, saves binary response to disk (removes python-pptx/Puppeteer)
- Coordinate conversion: px / 96 → inches (1280×720 = 13.333×7.5 in)
- CSS color/font-size parsing (hex, rgb/rgba, px→pt at 0.75pt/px)
- Fallback renderer for slides without a JSON layout schema
- PDF export (Puppeteer) unchanged
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Next.js rewrites() buffer HTTP responses and drop long-lived connections,
making SSE (text/event-stream) impossible. The backend never even received
the request (no log entry in API, ECONNRESET in web proxy logs).
Create dedicated route.ts files for all 3 SSE endpoints:
- /api/v1/ppt/outlines/stream/[id]
- /api/v1/ppt/presentation/stream/[id]
- /api/v1/ppt/jobs/[job_id]/stream
Each route forwards cookies for auth and returns backend's ReadableStream
directly as a Response, preventing any buffering. Sets X-Accel-Buffering: no
to also disable nginx buffering.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- outlines.py: Fix ECONNRESET/socket-hang-up — Depends session closes before
StreamingResponse generator runs; capture presentation data upfront, use
async_session_maker() inside inner() for the final DB commit (same pattern as Phase 4)
- useCustomTemplates.ts: Filter null-template items in summary map (crashed on
presentations without a TemplateModel); use item.layout_count instead of hardcoded 0
- TemplateSelection.tsx: Move custom AI templates section above built-in templates
- presentationGeneration.ts + OutlinePage.tsx: Add selectedTemplateId to Redux so
template selection persists when navigating away and back to /outline; clearOutlines
also resets selectedTemplateId for new presentation flows
- DocumentPreviewPage.tsx: Detect JSON file content (table decomposition output) and
convert to markdown table or pretty-printed code block before passing to MarkdownRenderer
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- documents_loader: skip missing files (print warning + continue) instead
of raising HTTPException inside SSE generator — prevents "response
already started" runtime error when temp files are wiped on restart
- V1ContentRender: wrap non-edit mode render in SlideErrorBoundary so
broken custom layout components show a red placeholder instead of
crashing the page (React error #62)
- CustomTemplateCard: wrap LayoutPreview in SlideErrorBoundary for the
same reason — bad compiled TSX from master deck parsing no longer
crashes the outline template picker
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Keep asyncio import for future timeout implementation.
Handle TimeoutError and other exceptions properly.
Co-Authored-By: Claude Sonnet 4.5 (1M context) <noreply@anthropic.com>
Prevents socket hang up when LLM is slow or unavailable.
- Timeout: 120 seconds (configurable via OUTLINE_TIMEOUT_SECONDS)
- Returns 504 Gateway Timeout error if exceeded
- Fixes: socket hang up errors in Next.js proxy
Co-Authored-By: Claude Sonnet 4.5 (1M context) <noreply@anthropic.com>
- Added PARSING_MODEL env var (default: gemini-2.5-flash-lite)
- Master deck parser now uses fast lite model
- 3-4x faster than gemini-3.1-pro: 22 layouts = 8-12 min vs 44-60 min
- Keep gemini-3.1-pro for presentation generation (quality)
Co-Authored-By: Claude Sonnet 4.5 (1M context) <noreply@anthropic.com>
- PostgreSQL SET LOCAL doesn't support parameterized queries
- Use string formatting (safe: user.id is UUID, role is enum)
- Fixes 'syntax error at or near $1' error
Co-Authored-By: Claude Sonnet 4.5 (1M context) <noreply@anthropic.com>
- Strip 'models/' prefix from Google API response for consistency
- Model names in .env should be without prefix (e.g., gemini-3.1-pro-preview)
- Fixes startup failure when checking model availability
Co-Authored-By: Claude Sonnet 4.5 (1M context) <noreply@anthropic.com>
Security Improvements (P0.0-P0.4):
- P0.0: Migrate to Gemini-only AI stack (simplified, single billing)
- P0.1: Fix CORS to restrict allowed origins from env (was *)
- P0.2: Remove hardcoded dev password, require env var
- P0.3: Add rate limiting (slowapi) - 3-10 req/min on sensitive endpoints
- P0.4: Add request size limits (100MB default via middleware)
New Features:
- Unified LLM service with Google Gemini priority
- OXML geometry extractor for layout parsing
- TSX validator for generated React components
- Client ID support in presentation requests with access control
- Configurable LLM/image timeouts via env vars
Modern Design System (P0.9 - partial):
- Enhanced CSS design tokens (primary, semantic colors, shadows)
- Typography scale (h1-h4, body variants, caption)
- Modern animations (fadeIn, slideIn, scaleIn)
- Updated Button component with better variants and hover effects
- Created unified Card and StatusBadge components
- Applied design system to Dashboard and Settings pages
Backend Improvements:
- Master deck parser simplification
- Slide-to-HTML endpoint cleanup (325 lines removed)
- Better error handling in prompts endpoint
Frontend Improvements:
- Settings UI simplified to show only Google/Gemini
- Dashboard uses CSS variables instead of hardcoded colors
- Improved button transitions and hover states
Co-Authored-By: Claude Sonnet 4.5 (1M context) <noreply@anthropic.com>
- Fix image path handling in purge (remove incorrect lstrip)
- Add hard-delete of presentation records from database after file cleanup
- Add debug logging throughout purge process
- Fix outline parsing when LLM returns slides as JSON string
- Fix purge success message to show total files count
Co-Authored-By: Claude Sonnet 4.5 (1M context) <noreply@anthropic.com>
- Change NanoBanana Pro model from gemini-3-pro-image-preview to gemini-2.0-flash-exp-image (previous model doesn't exist)
- Purge endpoint now deletes generated images from /app_data/images/ when soft-deleted presentations are purged
- Add purged_images counter to purge response
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
PDF documents with Mermaid diagrams, styled with purple theme.
Includes build script for regenerating PDFs from Markdown sources.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Fix PPTX/PDF export: Puppeteer URL port mismatch (80 → 3000)
- Fix backend export_utils to use NEXT_INTERNAL_URL env var
- Add Chromium to frontend Dockerfile for Docker-based export
- Fix slide edit socket hang up with asyncio.wait_for() timeouts
- Add FastAPI StaticFiles mounts for /static and /app_data
- Add Next.js rewrite for /static/ to proxy to backend
- Show template thumbnail in master decks admin page
- Add error logging to ReviewWorkflow component
- Add Docker env vars for web service (APP_DATA_DIRECTORY, app_data volume)
- Add project README in English
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
In layouts mode, screenshots were matched by array index (0,1,2...)
which broke when PPTX had more slideLayouts than actual slides.
Now builds an explicit mapping from slideLayout filename to the
first slide that uses it, so each layout gets the correct screenshot.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Connect AuthGuard in providers.tsx so all pages enforce authentication
- Root page redirects to /dashboard instead of rendering old Home.tsx
- ConfigurationInitializer and login page redirect to /dashboard (not /upload)
- Create reusable Logo component with "Oliver DeckForge" text branding
- Replace Presenton logo-white.png with Logo component in all 3 headers
- Remove old "Create Template" / "Templates" nav links from dashboard header
- Replace presenton@gmail.com/www.presenton.com in template placeholders
- Fix DashboardPage heading "Slide Presentation" → "Recent Presentations"
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Replace all Presenton branding with Oliver DeckForge (metadata, headers, titles, logos)
- Pass CAN_CHANGE_KEYS=false to web container so setup page redirects to /upload
- Switch image provider from gemini_flash to nanobanana_pro
- Update default fallback paths from /tmp/presenton to /tmp/deckforge
- Rename packages: presenton → oliver-deckforge, presenton-backend → oliver-deckforge-backend
- Remove external presenton.ai URLs from metadata (canonical, OG, Twitter)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Fix UV index strategy: mark PyTorch CPU index as explicit with name
- Add --index-strategy unsafe-best-match to Dockerfile uv pip install
- Fix redis version constraint (>=5.0,<6) for ARQ compatibility
- Fix Anthropic model name (claude-sonnet-4-5-20250929)
- Fix IMAGE_PROVIDER enum value (gemini_flash, not google)
- Resolve middlewares.py vs middlewares/ package conflict
- Fix worker import paths (models.sql.presentation, models.sql.slide, utils split)
- Fix seed script FK resolution by importing all related models
- Fix test suite: async fixture scoping, greenlet dep, regex patterns, fixture params
- Fix frontend TypeScript error (Boolean cast for layout.react_code)
- Regenerate package-lock.json with i18n packages
- Add initial Alembic migration (autogenerated from all models)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Brand-enforced export pipeline (PPTX/PDF with auto brand fonts/colors/logo)
- Client library dashboard with two-level navigation (client grid → detail tabs)
- Data retention service with ARQ cron jobs (daily cleanup + weekly purge)
- Brand-adaptive UI theme via CSS custom properties (dynamic per client)
- Analytics dashboard with overview, usage, quality, and performance metrics
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>