Skip to content

Migrate server backend from Express to Next.js#78

Open
devin-ai-integration[bot] wants to merge 2 commits into
mainfrom
devin/1784309000-nextjs-backend
Open

Migrate server backend from Express to Next.js#78
devin-ai-integration[bot] wants to merge 2 commits into
mainfrom
devin/1784309000-nextjs-backend

Conversation

@devin-ai-integration

@devin-ai-integration devin-ai-integration Bot commented Jul 17, 2026

Copy link
Copy Markdown
Contributor

Summary

Rewrites the server/ backend from a standalone Express app to a Next.js 16 (App Router) app. All endpoints keep the exact same URL paths and payloads, so the Expo client (app/) and the CLI need no changes — the mobile app still points at DOMAIN and hits /chat/:provider, /images/:provider, /models, /health.

Endpoint mapping (paths unchanged, no /api prefix)

  • GET /healthapp/health/route.ts
  • GET /modelsapp/models/route.ts
  • POST /chat/[provider]app/chat/[provider]/route.ts (claude, gpt, gemini, glm, kimi; SSE streaming)
  • POST /images/[provider]app/images/[provider]/route.ts (gemini; multipart and JSON)

What changed structurally

  • Provider logic moved from server/src/** to framework-agnostic functions in server/lib/**:
    • Chat handlers now take a parsed ChatRequest and return a streaming Response instead of writing to an Express res. Dispatch is a CHAT_HANDLERS map in lib/chat/index.ts (replaces chatRouter).
    • Image handler takes { model, prompt, file } and returns a JSON Response (replaces multer — the route parses multipart/form-data via req.formData()).
  • lib/sse.ts rewritten around Web Streams:
    sseResponse(async (writer) => {
      // ...fetch provider, parse upstream SSE...
      writer.sendToken(text)   // -> data: {"content":"..."}\n\n
      writer.sendError(msg)    // -> data: {"error":"..."}\n\n
    }) // always terminates with data: [DONE]\n\n; returns text/event-stream Response
    createSSEParser / pumpStream (partial-line buffering across chunks) are preserved.
  • Express middleware replaced with plain helpers + Next conventions:
    • lib/auth.ts — optional Authorization: Bearer <API_AUTH_TOKEN> check (timing-safe), returns 401 Response or null.
    • lib/rateLimit.ts — in-memory fixed-window limiter keyed by client IP (RATE_LIMIT_PER_MINUTE, default 60), returns 429 with Retry-After / RateLimit-* headers.
    • proxy.ts (Next 16's renamed middleware) — CORS headers + OPTIONS preflight for the matched routes (CORS_ORIGIN, default *).
  • Zod schemas (lib/types.ts) and the model registry (lib/models.ts) are carried over unchanged; /models still omits internal modelId.

Tooling / behavior

  • package.json swaps express/cors/multer/express-rate-limit/supertest for next/react/react-dom (pinned next@16.2.10, react@19.2.3 to match the app). zod kept.
  • Scripts: dev/start run on port 3050 (next dev/start -p 3050) so the bundled ngrok flow and the CLI's EXPO_PUBLIC_DEV_API_URL=http://localhost:3050 keep working. typecheck (tsc --noEmit) and test (vitest) preserved — CI's server job is unchanged.
  • Tests rewritten to invoke the route handlers directly (no HTTP server / supertest) while asserting the same normalized SSE output, auth 401, invalid-body 400, unsupported-model and provider-error events.

Verification

  • pnpm install --frozen-lockfile, pnpm typecheck, pnpm test (9 passing), and pnpm build all green.
  • Ran next start and manually confirmed: /health, /models (no modelId leak), CORS preflight 204, SSE unsupported-model + provider-error passthrough (real upstream 401/403 without keys), invalid-body 400, unknown-provider 404, and multipart image parsing.

Note: rate limiting is in-memory (per instance) — same practical behavior as the previous single-process Express server; use a shared store if deployed to multiple instances.

Link to Devin session: https://app.devin.ai/sessions/d96e95fc4d5948e0b34d96635f14fb69
Requested by: @dabit3


Open in Devin Review

Co-Authored-By: Nader Dabit <dabit3@gmail.com>
@dabit3 dabit3 self-assigned this Jul 17, 2026
@dabit3
dabit3 self-requested a review July 17, 2026 17:28
@devin-ai-integration

Copy link
Copy Markdown
Contributor Author

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR. Add '(aside)' to your comment to have me ignore it.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment, CI, and merge conflict monitoring

devin-ai-integration[bot]

This comment was marked as resolved.

Co-Authored-By: Nader Dabit <dabit3@gmail.com>
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