Prepare the app for production

This commit is contained in:
Moshfegh Hamedani 2026-03-03 14:18:20 -08:00
parent f72e08ff59
commit a757ed7f9c
4 changed files with 72 additions and 0 deletions

12
.dockerignore Normal file
View file

@ -0,0 +1,12 @@
node_modules
.env*
.git
e2e
dist
*.test.ts
*.test.tsx
*.spec.ts
*.spec.tsx
.vscode
.idea
.claude

40
Dockerfile Normal file
View file

@ -0,0 +1,40 @@
# Stage 1: Install dependencies
FROM oven/bun:1 AS install
WORKDIR /app
COPY package.json bun.lock ./
COPY client/package.json ./client/
COPY server/package.json ./server/
COPY core/package.json ./core/
RUN bun install --frozen-lockfile
# Stage 2: Build
FROM oven/bun:1 AS build
WORKDIR /app
COPY --from=install /app/node_modules ./node_modules
COPY . .
RUN cd server && bunx prisma generate
RUN cd client && bunx vite build
# Stage 3: Production
FROM oven/bun:1 AS production
WORKDIR /app
COPY --from=install /app/node_modules ./node_modules
COPY --from=build /app/client/dist ./client/dist
COPY server ./server
COPY core ./core
COPY package.json ./
# Overlay generated Prisma client from build stage
COPY --from=build /app/server/src/generated ./server/src/generated
ENV NODE_ENV=production
EXPOSE 3000
CMD ["sh", "-c", "cd server && bunx prisma migrate deploy && cd .. && bun run server/src/index.ts"]

8
railway.toml Normal file
View file

@ -0,0 +1,8 @@
[build]
dockerfilePath = "Dockerfile"
[deploy]
healthcheckPath = "/api/health"
healthcheckTimeout = 30
restartPolicyType = "ON_FAILURE"
restartPolicyMaxRetries = 5

View file

@ -1,3 +1,4 @@
import path from "path";
import Sentry from "./lib/sentry";
import express from "express";
import cors from "cors";
@ -66,6 +67,17 @@ app.use("/api/webhooks", webhooksRouter);
Sentry.setupExpressErrorHandler(app);
// In production, serve the built React client as static files
if (isProduction) {
const clientDist = path.resolve(import.meta.dirname, "../../client/dist");
app.use(express.static(clientDist));
// SPA fallback: serve index.html for any non-API route
app.get("/{*path}", (_req, res) => {
res.sendFile(path.join(clientDist, "index.html"));
});
}
if (!process.env.WEBHOOK_SECRET) {
console.warn("Warning: WEBHOOK_SECRET is not set. Webhook endpoints will return 500.");
}