161 lines
5.9 KiB
Markdown
161 lines
5.9 KiB
Markdown
# SaaS template
|
||
|
||
This is not gonna make You rich, but it sure as hell will save you a lot of time!
|
||
|
||
This is production ready setup for Convex and Next SaaS.
|
||
|
||
## Features
|
||
|
||
- Auth
|
||
- Stripe
|
||
- shadcn/create UI templte
|
||
- next intl
|
||
- next themes
|
||
- Backend/Frontend Tests
|
||
- Tmuxinator
|
||
- CICD
|
||
- accurate instructions
|
||
|
||
## Development process
|
||
|
||
### Environments
|
||
|
||
- Dev cloud environment - based on `develop` branch
|
||
- Prod cloud environment - based on `main` branch
|
||
|
||
## Getting Started
|
||
|
||
First, run the development server:
|
||
|
||
```bash
|
||
pnpm dev --webpack
|
||
```
|
||
|
||
> [!NOTE]
|
||
> As of Next.js@16.2.1 turbopack is broken ant it spikes CPU usage by 900% and 8-9GiB of RAM usage, thus why we use webpack. Wait for 16.3.0 to migrate to turbopack
|
||
|
||
### Convex setup
|
||
|
||
[Source of truth](https://github.com/get-convex/convex-backend/blob/main/self-hosted/README.md)
|
||
|
||
1. Go on Coolify, search for Convex and set it up.
|
||
|
||
> [!IMPORTANT]
|
||
> Best case: [copy config from here](https://github.com/get-convex/convex-backend/blob/main/self-hosted/docker/docker-compose.yml), paste it instead of Coolify's docker-compose file, then go into environment variables, copy them, paste them and the new docker-compose into an AI agent and tell him to properly map the envs to docker-compose so it's ready to deploy on coolify.
|
||
|
||
This works for Convex 1.34.0 (CLI+backend/dashboard)
|
||
|
||
```
|
||
services:
|
||
backend:
|
||
image: 'ghcr.io/get-convex/convex-backend:latest'
|
||
stop_grace_period: 10s
|
||
stop_signal: SIGINT
|
||
ports:
|
||
- '${PORT:-3210}:3210'
|
||
- '${SITE_PROXY_PORT:-3211}:3211'
|
||
volumes:
|
||
- 'data:/convex/data'
|
||
environment:
|
||
APPLICATION_MAX_CONCURRENT_MUTATIONS: '${APPLICATION_MAX_CONCURRENT_MUTATIONS:-16}'
|
||
APPLICATION_MAX_CONCURRENT_NODE_ACTIONS: '${APPLICATION_MAX_CONCURRENT_NODE_ACTIONS:-16}'
|
||
APPLICATION_MAX_CONCURRENT_QUERIES: '${APPLICATION_MAX_CONCURRENT_QUERIES:-16}'
|
||
APPLICATION_MAX_CONCURRENT_V8_ACTIONS: '${APPLICATION_MAX_CONCURRENT_V8_ACTIONS:-16}'
|
||
INSTANCE_NAME: '${INSTANCE_NAME}'
|
||
INSTANCE_SECRET: '${INSTANCE_SECRET}'
|
||
CONVEX_CLOUD_ORIGIN: '${SERVICE_URL_BACKEND}'
|
||
CONVEX_SITE_ORIGIN: '${SERVICE_URL_BACKEND_SITE}'
|
||
DISABLE_METRICS_ENDPOINT: '${DISABLE_METRICS_ENDPOINT:-true}'
|
||
DOCUMENT_RETENTION_DELAY: '${DOCUMENT_RETENTION_DELAY:-172800}'
|
||
DO_NOT_REQUIRE_SSL: '${DO_NOT_REQUIRE_SSL:-true}'
|
||
DISABLE_BEACON: '${DISABLE_BEACON:-false}'
|
||
REDACT_LOGS_TO_CLIENT: '${REDACT_LOGS_TO_CLIENT:-false}'
|
||
RUST_LOG: '${RUST_LOG:-info}'
|
||
RUST_BACKTRACE: '${RUST_BACKTRACE:-0}'
|
||
ACTIONS_USER_TIMEOUT_SECS: '${ACTIONS_USER_TIMEOUT_SECS:-600}'
|
||
HTTP_SERVER_TIMEOUT_SECONDS: '${HTTP_SERVER_TIMEOUT_SECONDS:-300}'
|
||
CONVEX_RELEASE_VERSION_DEV: '${CONVEX_RELEASE_VERSION_DEV:-}'
|
||
DATABASE_URL: '${DATABASE_URL:-}'
|
||
POSTGRES_URL: '${POSTGRES_URL:-}'
|
||
MYSQL_URL: '${MYSQL_URL:-}'
|
||
AWS_REGION: '${AWS_REGION:-}'
|
||
AWS_ACCESS_KEY_ID: '${AWS_ACCESS_KEY_ID:-}'
|
||
AWS_SECRET_ACCESS_KEY: '${AWS_SECRET_ACCESS_KEY:-}'
|
||
AWS_SESSION_TOKEN: '${AWS_SESSION_TOKEN:-}'
|
||
AWS_S3_FORCE_PATH_STYLE: '${AWS_S3_FORCE_PATH_STYLE:-}'
|
||
AWS_S3_DISABLE_SSE: '${AWS_S3_DISABLE_SSE:-}'
|
||
AWS_S3_DISABLE_CHECKSUMS: '${AWS_S3_DISABLE_CHECKSUMS:-}'
|
||
S3_ENDPOINT_URL: '${S3_ENDPOINT_URL:-}'
|
||
S3_STORAGE_EXPORTS_BUCKET: '${S3_STORAGE_EXPORTS_BUCKET:-}'
|
||
S3_STORAGE_SNAPSHOT_IMPORTS_BUCKET: '${S3_STORAGE_SNAPSHOT_IMPORTS_BUCKET:-}'
|
||
S3_STORAGE_MODULES_BUCKET: '${S3_STORAGE_MODULES_BUCKET:-}'
|
||
S3_STORAGE_FILES_BUCKET: '${S3_STORAGE_FILES_BUCKET:-}'
|
||
S3_STORAGE_SEARCH_BUCKET: '${S3_STORAGE_SEARCH_BUCKET:-}'
|
||
healthcheck:
|
||
test:
|
||
- CMD-SHELL
|
||
- 'curl -f http://localhost:3210/version'
|
||
interval: 5s
|
||
start_period: 10s
|
||
timeout: 5s
|
||
retries: 10
|
||
dashboard:
|
||
image: 'ghcr.io/get-convex/convex-dashboard:latest'
|
||
stop_grace_period: 10s
|
||
stop_signal: SIGINT
|
||
ports:
|
||
- '${DASHBOARD_PORT:-6791}:6791'
|
||
environment:
|
||
PORT: '6791'
|
||
NEXT_PUBLIC_DEPLOYMENT_URL: '${SERVICE_URL_BACKEND}'
|
||
NEXT_PUBLIC_LOAD_MONACO_INTERNALLY: '${NEXT_PUBLIC_LOAD_MONACO_INTERNALLY:-true}'
|
||
depends_on:
|
||
backend:
|
||
condition: service_healthy
|
||
volumes:
|
||
data: null
|
||
```
|
||
|
||
Then make sure to update domains and env vars accordingly
|
||
|
||
2. Deploy the service(s - dashboard and the db). It has built-in persistent storage
|
||
3. Connect to server with ssh, jump into a **backend** container with `docker exec -it <name> ./generate_admin_key.sh`
|
||
You'll receive Your admin key and You'll be able to log into dashboard
|
||
|
||
```
|
||
Admin key:
|
||
self-hosted-convex|010...
|
||
```
|
||
|
||
4. Now Your base is ready. Go to .env.local and finish setting up the connection.
|
||
5. Run `pnpm install` (only if Your hosted Convex image is latest, else use a proper version)
|
||
6. After that You can run `npx convex dev` and You should be ready to go!
|
||
|
||
### Frontend setup
|
||
|
||
1. Time to pick a theme! Go to [shadcn/create](https://ui.shadcn.com/create), create a theme, and simply use the received command to init this theme in Your project!
|
||
|
||
2. Replace `aliases` section in `components.json`.
|
||
|
||
```
|
||
"aliases": {
|
||
"components": "@/src/components",
|
||
"utils": "@/src/lib/utils",
|
||
"ui": "@/src/components/shadcn",
|
||
"lib": "@/src/lib",
|
||
"hooks": "@/src/hooks"
|
||
},
|
||
```
|
||
|
||
Move the folders accordingly. Make sure to also update front-end imports, since those changed too.
|
||
|
||
#### Troubleshooting
|
||
|
||
```
|
||
dev/templates/convex-next-saas main !? ❯ npx convex dev
|
||
✖ Error: Unable to start push to https://backend-i8e44nvzhj8sxw4qm9tbu1f7.mentat.ovh
|
||
✖ Error fetching POST https://backend-i8e44nvzhj8sxw4qm9tbu1f7.mentat.ovh/api/deploy2/start_push 400 Bad Request: BadJsonBody: Failed to deserialize the JSON body into th
|
||
e target type: appDefinition: missing field `functions` at line 1 column 272745
|
||
```
|
||
|
||
**Solution** - ensure both CLI and convex self-hosted cloud images versions are the same. If not - I suggest upgrading whatever version is lower to be higher.
|