πŸ“„ SKILL.md

← Vault

name: documents-vps-deploy

description: Deploy Documents app (TanStack Start) to VPS β€” post-build sync and systemd env vars

category: devops


Documents VPS Deploy β€” Critical Post-Build Sync

Context

Documents app (TanStack Start + Vite) on VPS at documentos.rochasalesseguros.com.br, port 3010. Service: systemctl documentos.

The Problem (HTTP 500 on all routes after build)

After a Lovable/TanStack Start build, the build output is in dist/ but the running app serves from .output/. TWO syncs are needed after every build β€” missing the server assets sync causes 500 on ALL routes because TanStack Start's SSR manifest references new hash-named files that don't exist in .output/.

Build + Deploy Steps (TanStack Start v1.167.65 target: "node-server")

`bash

cd /var/www/documentos/deploy-nodejs/deploy-vps-nodejs/app

1. Build (nvm Node 20 required)

source ~/.nvm/nvm.sh && nvm use 20 && npm run build

Build outputs to:

dist/client/ β†’ static assets (JS, CSS, etc.)

dist/server/server.js β†’ SSR handler (NOT a standalone HTTP server)

.output/server/index.mjs β†’ thin wrapper: re-exports from dist/server/server.js

2. NO need to sync to .output/ anymore β€” server.js points directly to dist/

(see server.js patch below β€” this replaced the old .output/ sync approach)

3. Restart

sudo systemctl restart documentos

`

CRITICAL: server.js must be updated after every rebuild

The server.js in the app root is the custom HTTP server wrapper β€” it creates the HTTP server, serves static files from dist/client, and forwards SSR requests to the handler. It does NOT auto-update after npm run build. After every rebuild you MUST verify (and patch if needed):

`bash

Check what server.js currently imports

grep -n "output\|dist/server" /var/www/documentos/deploy-nodejs/deploy-vps-nodejs/app/server.js

`

Current working config (after 2025-05-12 fix):

Use Gmail App Password via SMTP instead β€” simpler, more reliable, no popups.

Setup Steps

1. Install nodemailer:

`bash

cd /var/www/documentos/deploy-vps-nodejs/app

source ~/.nvm/nvm.sh && nvm use 20 && npm install nodemailer

`

2. Generate App Password:

- Go to https://myaccount.google.com/apppasswords

- Login with the sender email

- Create app with name "DocCorretor" (or similar)

- Copy the 16-character password (format xxxx xxxx xxxx xxxx)

3. Add to .env (generate 32-byte hex key for encryption):

`bash

# Generate encryption key

openssl rand -hex 32

`

`

GMAIL_APP_PASSWORD_KEY=<32-byte-hex-key>

`

4. Add to systemd service (/etc/systemd/system/documentos.service):

`

EnvironmentFile=/var/www/documentos/deploy-vps-nodejs/app/.env

`

Then: systemctl daemon-reload && systemctl restart documentos

5. Routes to create (under src/routes/api/gmail/):

- app-password.ts β€” GET/POST/DELETE for SMTP config, stores encrypted password in public.app_settings

- send.ts β€” reads encrypted password, creates nodemailer SMTP transporter, sends email with attachments

- smtp-config.ts β€” GET/POST/DELETE for SMTP settings check

6. Storage in DB (public.app_settings):

- smtp.app_password β€” AES-encrypted (via GMAIL_APP_PASSWORD_KEY)

- smtp.sender_email β€” set to Supabase session user email at save time

Key pattern: sender email = login email

The sender email is automatically the Supabase authenticated user's email. No separate sender selection needed.


Verify after deploy

`bash

Test public URL

curl -s -o /dev/null -w "%{http_code}" https://documentos.rochasalesseguros.com.br/

Test assets are served

curl -s -o /dev/null -w "%{http_code}" https://documentos.rochasalesseguros.com.br/assets/index-BDfKYpOe.js

`

Build command

`bash

source ~/.nvm/nvm.sh && nvm use 20

npm run build

`