From 4ae60473b69ee608498323cd71945397916c6b8f Mon Sep 17 00:00:00 2001 From: nxtkofi Date: Tue, 21 Apr 2026 21:37:24 +0200 Subject: [PATCH] docs: rewrite README and update DEVELOPMENT guide Rewrite README.md as a clean template landing page. Update DEVELOPMENT.md with Resend setup instructions and expanded checklist. Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus --- DEVELOPMENT.md | 16 +++++ README.md | 187 +++++++++++++------------------------------------ 2 files changed, 64 insertions(+), 139 deletions(-) diff --git a/DEVELOPMENT.md b/DEVELOPMENT.md index 5d8cd80..6cd3ce7 100644 --- a/DEVELOPMENT.md +++ b/DEVELOPMENT.md @@ -119,6 +119,21 @@ pnpm dlx convex env set SITE_URL=http://localhost:3000 For production, `SITE_URL` should be your deployed frontend URL. +### 5. Resend Email Setup + +Email is handled by Resend. The API key is **server-side only** and lives on Convex, not in `.env.local`. + +1. Get your API key from [resend.com](https://resend.com) +2. Verify your domain in Resend and create a sender email (e.g. `noreply@yourdomain.com`) +3. Set Convex environment variables: + +```bash +pnpm dlx convex env set RESEND_API_KEY=re_xxxxxxxxxxxxx +pnpm dlx convex env set RESEND_FROM_EMAIL=noreply@yourdomain.com +``` + +> These are read by `convex/lib/resend.ts` at runtime. Never commit them. + ## Adding a New Project from Template ### Option A: Manual Clone (Private Forgejo) @@ -193,6 +208,7 @@ When starting a new project: - [ ] Fill `.env.local` - [ ] Deploy Convex backend on Coolify - [ ] Set `BETTER_AUTH_SECRET` and `SITE_URL` on Convex +- [ ] Set `RESEND_API_KEY` and `RESEND_FROM_EMAIL` on Convex - [ ] Update `src/app/layout.tsx` metadata - [ ] Remove/replace placeholder content in `src/app/[locale]/page.tsx` - [ ] Add project-specific routes to `src/lib/routes.ts` diff --git a/README.md b/README.md index 5cd6050..b02edf3 100644 --- a/README.md +++ b/README.md @@ -1,160 +1,69 @@ -# SaaS template +# convex-next-saas -This is not gonna make You rich, but it sure as hell will save you a lot of time! +A personal, opinionated SaaS template built for speed. Next.js 16 + Convex self-hosted + Better Auth + Resend. -This is production ready setup for Convex and Next SaaS. +> This template is tailored for self-hosted Convex on Coolify with a private Forgejo workflow. It's not trying to be a generic marketplace template — it's the setup I actually use to ship projects fast. -## Features +## Stack -- Auth -- Stripe -- shadcn/create UI templte -- next intl -- next themes -- Backend/Frontend Tests -- Tmuxinator -- CICD -- accurate instructions +- **Frontend**: Next.js 16 (App Router), React 19, TypeScript 5, Tailwind CSS 4 +- **Backend**: Convex self-hosted (Docker on Coolify) +- **Auth**: Better Auth (email/password, email verification, password reset) +- **Email**: Resend (free tier: 3,000 emails/month) +- **UI**: shadcn/ui (radix-nova), @hugeicons/react +- **i18n**: next-intl v4 with locale routing (`/en`, `/pl`) +- **State**: RSC + Client Components hybrid +- **Validation**: Zod v4 +- **Linting**: ESLint + oxlint -## Development process +## What's Included -### Environments +- [x] Email/password auth with HIBP password checking +- [x] Email verification flow +- [x] Forgot / reset password flow +- [x] Change password (authenticated) +- [x] Locale-based routing (EN / PL) +- [x] Theme switching (dark/light/system) +- [x] Protected routes with redirect + callbackURL +- [x] Runtime env validation (Zod) +- [x] GitHub Actions CI (lint + build) +- [x] Project init script (`bin/init-template.mjs`) -- Dev cloud environment - based on `develop` branch -- Prod cloud environment - based on `main` branch - -## Getting Started - -First, run the development server: +## Quick Start ```bash +git clone my-project +cd my-project +pnpm install + +# Copy and fill env vars +cp .env.example .env.local + +# Set up Convex backend (see DEVELOPMENT.md) +# Then: 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 +> ⚠️ **Always use `--webpack`** — Turbopack is broken in Next.js 16.2.1 (900% CPU spike). -### Convex setup +## Project Bootstrap -[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 +```bash +node bin/init-template.mjs my-project +cd my-project +# Fill .env.local, deploy Convex, done. ``` -Then make sure to update domains and env vars accordingly +## Docs -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 ./generate_admin_key.sh` -You'll receive Your admin key and You'll be able to log into dashboard +- [`AGENTS.md`](./AGENTS.md) — Architecture, conventions, and anti-patterns for AI agents +- [`DEVELOPMENT.md`](./DEVELOPMENT.md) — Local setup, Coolify deployment, troubleshooting -``` -Admin key: -self-hosted-convex|010... -``` +## Environments -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! +- **Dev**: `develop` branch +- **Prod**: `main` branch ->[!TIP] -> Remember to add 2 domains with ports in Your backend Coolify config: -> -> 1. Actual backend domain e.g `https://convex-backend.mentat.ovh:3210` -> 2. Backend actions domain e.g `https://backend-site-olnjg91x5ervt6j6owwgnlha.mentat.ovh:3211` +## License -### Frontend setup - -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! - -### Better Auth - -This project utilizes `BetterAuth`. To set it up: - -1. `pnpm dlx convex env set BETTER_AUTH_SECRET=$(openssl rand -base64 32)` -2. `pnpm dlx convex env set SITE_URL=http://localhost:3000` - -#### 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. +MIT — do whatever you want.