Skip to content

Support production deployment on Linux/nginx via SSH tunnel#48

Merged
michaelzick merged 2 commits into
mainfrom
prod-server-deploy
Jun 12, 2026
Merged

Support production deployment on Linux/nginx via SSH tunnel#48
michaelzick merged 2 commits into
mainfrom
prod-server-deploy

Conversation

@michaelzick

Copy link
Copy Markdown
Owner

What changed

Running the built server (node dist/index.js) previously crashed: tsup externalized @timefraim/shared, whose package exports points at TypeScript source that Node can't load at runtime. There was also no start script, and the bundled code computed the repo root with a fixed ../../../../ from its own location — correct for src/config/env.ts, wrong for dist/index.js, so the root .env wasn't found unless the process happened to run from the repo root.

  • apps/server/tsup.config.ts — bundles @timefraim/shared into dist/index.js (config file replaces the inline CLI flags). Verified the output has zero runtime references to the workspace package.
  • apps/server/src/config/env.ts — locates the repo root by walking up to pnpm-workspace.yaml instead of a fixed parent-hop count, so .env discovery works from both src (tsx dev) and the bundled dist.
  • Scriptsstart in the server package, start:server at the root.
  • docs/deploy-linux-prod.md — production runbook written for a coding agent: nginx on loopback :6173 serves apps/web/dist and proxies /api, /health, /mcp to the API on :4000, reached through a single SSH tunnel port. Includes the prod .env template (linked Supabase values, IPv4 session-pooler DATABASE_URL), a systemd unit, SPA-fallback nginx config with unbuffered /mcp, verification steps, and a troubleshooting table.
  • apps/server/tsconfig.json — includes tsup.config.ts (mirrors web's vite.config.ts idiom) so the ESLint project service can type it; rootDir dropped since tsc is --noEmit here and tsup controls output layout. Server lint now covers the config file.
  • BriefsAGENTS.md updated and CLAUDE.md/GEMINI.md regenerated via pnpm agent-briefs:sync; .env.example points at the runbook.

Why

The app worked under pnpm dev on a server but had no viable production path: the dev server was the only way to run it. This makes pnpm build && pnpm start:server work and documents the full nginx/tunnel topology so the same origin (http://127.0.0.1:6173) keeps Supabase Google OAuth and APP_ORIGIN CORS working with NODE_ENV=production.

Reviewer notes

  • Smoke-tested the built server with NODE_ENV=production from a non-root cwd: /health returns {"ok":true}, the root .env is found, configured origins get CORS headers, and foreign origins are rejected.
  • Full gate passes: pnpm check components (agent-briefs check, lint, typecheck, 144 tests, build).
  • The single-port nginx design makes browser requests same-origin, so no Google Cloud or Supabase auth config changes are needed for existing tunnel users.

🤖 Generated with Claude Code

michaelzick and others added 2 commits June 12, 2026 05:07
- Bundle @timefraim/shared into the server dist via tsup.config.ts: the
  shared package's exports point at TypeScript source, so the previous
  externalized import crashed node dist/index.js.
- Locate the repo-root .env by walking up to pnpm-workspace.yaml instead
  of a fixed parent-hop count that broke once the code was bundled.
- Add `start` (server) and `start:server` (root) scripts.
- Add docs/deploy-linux-prod.md: production runbook for Linux/nginx
  served over an SSH tunnel (single loopback origin, API proxied).
- Point .env.example at the runbook; update agent briefs.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The ESLint project service had no project covering tsup.config.ts,
producing a parsing error in editors. Mirror the web package idiom
(vite.config.ts in include) and lint it explicitly; rootDir is dropped
since tsc is noEmit-only here and tsup controls output layout.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@michaelzick michaelzick merged commit 80fd895 into main Jun 12, 2026
10 checks passed
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