mirror of
https://github.com/AmruthPillai/Reactive-Resume.git
synced 2026-09-29 08:14:25 +10:00
* feat(deploy): support Vercel Hobby alongside Docker * fix(deploy): include PDFKit runtime font assets * docs(deploy): document Vercel and Docker setup * docs(deploy): record storage persistence checks * refactor(deploy): drop scheduled staging cleanup Staging uploads are deleted after finalization and expired ones are swept on each new upload, so the Vercel cron job, its route, and CRON_SECRET are no longer needed. The Deploy with Vercel wizard now asks for two secrets. * docs(deploy): restructure Vercel guides Split the Vercel page into a how-to with its environment reference, move the large RPC staging protocol to an API reference page, and move CI deployment checks to the contributing section. Point Deploy with Vercel buttons at main. * chore: remove agent planning records and fix web app description Delete superpowers plans/specs, ADRs, issue plans, execution briefs, domain context maps, and Europass research. Describe apps/web as a TanStack Router SPA served by apps/server. * refactor(deploy): simplify Vercel support code - Share one Redis client and key namespace through @reactive-resume/db/redis for API and auth instead of a second auth-only client. - Drop the auth seeding retry; the provider already treats concurrent inserts as no-ops and deployment preparation seeds before runtime. - Detect staging support from POST /api/storage/stage (404 on Docker) instead of a separate GET probe. - Read staged bodies directly; the signed upload already caps their size. - Close per-subscription Redis connections with disconnect() alone. - Check Blob health with one list call instead of write/read/delete. - Remove redundant tsdown onlyBundle list, dead namespace fallbacks, and the conditional spread in the health status. * fix(deploy): heal stopped runs with dead owners and keep auth up without Redis - Run owners refresh a Redis heartbeat until they release their claim. Stop requests reap the run immediately when the owner has stopped heartbeating, instead of leaving the thread blocked until the 15-minute TTL reaper. - Auth and oRPC rate limiters fall back to per-instance memory limits when Redis errors, instead of rejecting every login or failing requests. * ci: allow esbuild build for Vercel CLI and register deployment deps with knip pnpm 12 fails dlx installs with ignored build scripts, so allow esbuild explicitly. The server bundle keeps @vercel/blob, ioredis, and jose external, and api/index.mjs is the Vercel Function entry. * fix(web): send buffered RPC bodies instead of teed streams Reading a request clone turned the original body into a stream, which browsers send without inspectable request data and which needs duplex mode. Send the already buffered Blob for direct requests. * fix(web): send direct RPC bodies as bytes Blob request bodies are sent as data pipes, so browser tooling cannot inspect them. Buffer the original request as an ArrayBuffer and send those bytes; this restores the e2e save assertions that match on request data.
160 lines
9.2 KiB
Plaintext
160 lines
9.2 KiB
Plaintext
---
|
|
title: "Self-hosting on Vercel"
|
|
description: "Deploy Reactive Resume on Vercel Hobby with Neon PostgreSQL, private Vercel Blob, and Upstash Redis."
|
|
---
|
|
|
|
This guide deploys Reactive Resume to a Vercel project with the Deploy with Vercel wizard. The wizard provisions a database, file storage, and Redis for you. You supply two secrets.
|
|
|
|
Vercel serves the static web assets from its CDN and runs the shared Hono server in one Node.js 24 Function. Docker is also supported and uses the same API, authentication, templates, and data format. See [Self-hosting with Docker](/self-hosting/docker) for that option.
|
|
|
|
## Before you start
|
|
|
|
You need:
|
|
|
|
- A Vercel account and a GitHub account.
|
|
- Two independent random secrets, `AUTH_SECRET` and `ENCRYPTION_SECRET`. Generate each one separately:
|
|
|
|
```bash
|
|
openssl rand -hex 32
|
|
```
|
|
|
|
Save both values in a password manager. You must keep the same values for the life of the installation. Losing `ENCRYPTION_SECRET` makes saved AI-provider API keys unreadable.
|
|
|
|
The wizard connects three services through Vercel Marketplace:
|
|
|
|
| Service | Used for |
|
|
| --- | --- |
|
|
| Neon PostgreSQL | Application data |
|
|
| Vercel Blob (**private**) | Uploaded pictures, files, and agent attachments |
|
|
| Upstash Redis | Agent streaming and cancellation, shared rate limits, live resume updates |
|
|
|
|
Quotas and permitted use depend on your Vercel, Neon, and Upstash plans. Review [Vercel limits](https://vercel.com/docs/functions/limitations), [Neon](https://vercel.com/marketplace/neon), and [Upstash](https://vercel.com/marketplace/upstash/upstash-kv) before you choose a plan. Turn off automatic paid upgrades if you want to stay inside a free allowance.
|
|
|
|
<Note>
|
|
Each AI agent run stops active work after four minutes. This keeps the run, plus saving and cleanup, inside Vercel Hobby's five-minute Function limit. The limit applies to each question, not to the whole conversation. Docker uses the same limit.
|
|
</Note>
|
|
|
|
## Deploy
|
|
|
|
<Steps>
|
|
<Step title="Start the wizard">
|
|
Click the button:
|
|
|
|
[](https://vercel.com/new/clone?repository-url=https%3A%2F%2Fgithub.com%2Freactive-resume%2Freactive-resume&project-name=reactive-resume&repository-name=reactive-resume&env=AUTH_SECRET%2CENCRYPTION_SECRET&envDescription=Generate+two+independent+secrets+with+openssl+rand+-hex+32.+Keep+these+values+across+deployments.&envLink=https%3A%2F%2Fdocs.rxresu.me%2Fself-hosting%2Fvercel&stores=%5B%7B%22type%22%3A%22integration%22%2C%22protocol%22%3A%22storage%22%2C%22integrationSlug%22%3A%22neon%22%2C%22productSlug%22%3A%22neon%22%7D%2C%7B%22type%22%3A%22integration%22%2C%22protocol%22%3A%22storage%22%2C%22integrationSlug%22%3A%22upstash%22%2C%22productSlug%22%3A%22upstash-kv%22%7D%2C%7B%22type%22%3A%22blob%22%2C%22access%22%3A%22private%22%7D%5D)
|
|
</Step>
|
|
|
|
<Step title="Choose the Git scope">
|
|
On Hobby, select your **personal GitHub account**. Private repositories owned by a GitHub organization require Vercel Pro.
|
|
</Step>
|
|
|
|
<Step title="Connect the services">
|
|
Approve Neon, Upstash, and Blob. Set Blob access to **private**. Pick nearby regions for all three, ideally close to the Function region (`iad1` by default).
|
|
</Step>
|
|
|
|
<Step title="Enter the secrets">
|
|
Paste `AUTH_SECRET` and `ENCRYPTION_SECRET`.
|
|
</Step>
|
|
|
|
<Step title="Deploy">
|
|
Keep the project root at the repository root and keep the committed `vercel.json`. Do not select the `apps/web` subdirectory and do not add an SPA fallback rewrite.
|
|
|
|
The build compiles both apps and applies database migrations before the deployment goes live. You do not run migrations yourself.
|
|
</Step>
|
|
</Steps>
|
|
|
|
<Warning>
|
|
Do not paste Docker's `.env.example` into Vercel. Its local URLs and S3 settings select the wrong services.
|
|
</Warning>
|
|
|
|
## Check the deployment
|
|
|
|
1. Open `https://<your-project>.vercel.app/api/health`. `database`, `storage`, and `redis` should all report `healthy`. A sleeping Neon database can fail the first check; retry once.
|
|
2. Open the production domain and create an account.
|
|
3. Optional: add an AI provider under **Settings** to enable AI features.
|
|
4. Optional: configure SMTP for verification and password-reset emails. Without SMTP, emails are written to the Function logs.
|
|
5. Optional: add social or custom OAuth sign-in with the callback URLs in the [SSO guide](/self-hosting/sso).
|
|
|
|
## Use a custom domain
|
|
|
|
1. Add the domain to the Vercel project.
|
|
2. Set `APP_URL` to the full origin, for example `https://resume.example.com`.
|
|
3. Update the callback URLs of every OAuth provider you configured.
|
|
4. Redeploy.
|
|
|
|
Changing the domain does not move stored files. Files stay under the same `DEPLOYMENT_NAMESPACE`.
|
|
|
|
## Update the deployment
|
|
|
|
Redeploy the same project. Keep its connected services and secrets unchanged.
|
|
|
|
- Migrations run in the build step, never in runtime Functions. A database advisory lock serializes concurrent deployments.
|
|
- Rolling back to an older deployment does not roll back the database schema. Keep migrations backward-compatible, or restore a database backup.
|
|
|
|
## Preview deployments
|
|
|
|
Preview builds refuse to run migrations by default, so untrusted preview code cannot change your production database.
|
|
|
|
To enable previews:
|
|
|
|
1. Connect separate Neon, Upstash, and Blob resources to the **Preview** environment.
|
|
2. Set `ALLOW_PREVIEW_MIGRATIONS=true` for **Preview** only.
|
|
|
|
A storage namespace does not isolate SQL rows. Never connect the production database to the Preview environment.
|
|
|
|
## Back up your data
|
|
|
|
Back up the Neon database and the Blob store. Store `AUTH_SECRET` and `ENCRYPTION_SECRET` separately from those backups.
|
|
|
|
Moving between Docker and Vercel does not copy the database or files. Migrate them yourself.
|
|
|
|
## Build locally
|
|
|
|
A local Vercel build applies migrations, so run it only against an isolated database.
|
|
|
|
```bash
|
|
vercel pull --environment production
|
|
APP_URL=https://your-project.vercel.app vercel build --prod
|
|
```
|
|
|
|
Replace sensitive pulled values with local-only ones first. The CLI has no deployment hostname before publishing, so `APP_URL` is required here. Cloud builds set it automatically.
|
|
|
|
## Environment variables
|
|
|
|
Explicit variables take precedence over the Marketplace aliases listed here.
|
|
|
|
| Variable | Required | Behavior |
|
|
| --- | --- | --- |
|
|
| `AUTH_SECRET` | Yes | Signs sessions and tokens. Keep it constant. |
|
|
| `ENCRYPTION_SECRET` | Yes | At least 32 characters. Encrypts saved AI-provider API keys. Keep it constant. |
|
|
| `APP_URL` | No | Public origin. Defaults to the production domain in Production and to the deployment domain in Preview. Set it for a custom domain. |
|
|
| `DATABASE_URL` | Injected | Pooled runtime connection. Falls back to `POSTGRES_URL`. |
|
|
| `DATABASE_MIGRATION_URL` | No | Direct connection for migrations. Falls back to `DATABASE_URL_UNPOOLED`, then `POSTGRES_URL_NON_POOLING`, then `DATABASE_URL`. |
|
|
| `DATABASE_POOL_MAX` | No | Maximum database connections per Function instance. Default `10`. |
|
|
| `REDIS_URL` | Injected | Redis TCP/TLS URL. Falls back to Upstash's `KV_URL`. REST credentials alone do not work. |
|
|
| `STORAGE_BACKEND` | No | Must resolve to `blob` on Vercel, which is the default. The build fails with any other value. |
|
|
| `BLOB_READ_WRITE_TOKEN` | Injected | Provided by the connected Blob store. `BLOB_STORE_ID` with Vercel OIDC also works. |
|
|
| `DEPLOYMENT_NAMESPACE` | No | Prefix for Blob objects and Redis keys. Defaults to `production`, or to a per-branch value in Preview. Keep it constant after you store files. Set different values if two installations share one Blob store or Redis database. |
|
|
| `ALLOW_PREVIEW_MIGRATIONS` | No | Set to `true` in Preview only after you connect isolated preview resources. |
|
|
|
|
For SMTP, OAuth providers, and feature flags, use the same variables as Docker. See [Self-hosting with Docker](/self-hosting/docker).
|
|
|
|
## Upload limits
|
|
|
|
Vercel limits Function request bodies to 4.5 MB. The web app sends larger requests through private Blob staging, so these application limits still apply:
|
|
|
|
- General uploads: 10 MB per file.
|
|
- Agent attachments: 25 MiB per file and 100 MiB per thread.
|
|
|
|
Blob objects are never public. The application serves public pictures and authorizes private files itself. API clients that send large RPC requests must follow the [large RPC requests](/guides/large-rpc-requests) protocol. REST (`/api/openapi`) and MCP request bodies stay subject to the 4.5 MB limit.
|
|
|
|
## Troubleshooting
|
|
|
|
| Symptom | Fix |
|
|
| --- | --- |
|
|
| First build fails on configuration | Check that all three services are connected to Production and both secrets are set. Remove any `S3_*` variables and any `STORAGE_BACKEND` value other than `blob`. |
|
|
| Preview build refuses to migrate | Connect isolated preview resources, then set `ALLOW_PREVIEW_MIGRATIONS=true` for Preview. |
|
|
| Large upload returns `413` | Use the web app or the [large RPC requests](/guides/large-rpc-requests) protocol. Vercel Pro does not raise the request body limit. |
|
|
| Agent reconnect or stop fails | Check the Upstash TLS URL, the remaining Upstash quota, and that every environment uses the expected `DEPLOYMENT_NAMESPACE`. |
|
|
| Sign-in redirects to another hostname | Set `APP_URL` to the domain you use and redeploy. Do not add wildcard trusted origins. |
|
|
| Files are missing after a configuration change | Restore the original `DEPLOYMENT_NAMESPACE` and Blob connection. |
|