diff --git a/.env.example b/.env.example index 02a3142..7a7625c 100644 --- a/.env.example +++ b/.env.example @@ -1,6 +1,11 @@ # Client-side Base URL (optional - defaults to current origin in production) VITE_BASE_URL="http://localhost:3000" +# Deployment Configuration +# Choose one of: netlify, vercel, cloudflare-pages, node-server, bun +# Leave empty for default (no specific target) +VITE_DEPLOYMENT_TARGET= + # Database URL # ------------------------------------------------- DATABASE_URL="postgresql://user:password@localhost:5432/ex0" @@ -36,4 +41,6 @@ GOOGLE_CLIENT_ID="your-google-client-id" GOOGLE_CLIENT_SECRET="your-google-client-secret" -TEST_BASE_URL="http://localhost:3000" \ No newline at end of file +TEST_BASE_URL="http://localhost:3000" + +# Add other environment variables here \ No newline at end of file diff --git a/DEPLOYMENT.md b/DEPLOYMENT.md new file mode 100644 index 0000000..1ada83c --- /dev/null +++ b/DEPLOYMENT.md @@ -0,0 +1,169 @@ +# Deployment Guide + +This project supports multiple deployment targets through environment variables. You can configure your deployment target by setting the `VITE_DEPLOYMENT_TARGET` environment variable. + +## Configuration + +1. Copy `.env.example` to `.env`: + + ```bash + cp .env.example .env + ``` + +2. Set the `VITE_DEPLOYMENT_TARGET` variable to one of the following values: + - `netlify` - Deploy to Netlify + - `vercel` - Deploy to Vercel + - `cloudflare-pages` - Deploy to Cloudflare Pages + - `node-server` - Deploy to a Node.js server + - `bun` - Deploy to a Bun server + - Leave empty for default (no specific target) + +## Deployment Instructions + +### Netlify + +1. Set in your `.env` file: + + ``` + VITE_DEPLOYMENT_TARGET=netlify + ``` + +2. Deploy using Netlify's one-click deployment or CLI: + ```bash + pnpm build + # Deploy with Netlify CLI + netlify deploy --prod + ``` + +### Vercel + +1. Set in your `.env` file: + + ``` + VITE_DEPLOYMENT_TARGET=vercel + ``` + +2. Deploy using Vercel's CLI: + ```bash + pnpm build + vercel --prod + ``` + +### Cloudflare Pages + +1. Install the required dependency: + + ```bash + pnpm add unenv@latest + ``` + +2. Set in your `.env` file: + + ``` + VITE_DEPLOYMENT_TARGET=cloudflare-pages + ``` + +3. Create an `app.config.ts` file in your project root: + + ```typescript + import { defineConfig } from '@tanstack/react-start/config'; + import { cloudflare } from 'unenv'; + + export default defineConfig({ + server: { + preset: 'cloudflare-pages', + unenv: cloudflare, + }, + }); + ``` + +4. Create a `wrangler.toml` file: + + ```toml + name = "your-cloudflare-project-name" + pages_build_output_dir = "./dist" + compatibility_flags = ["nodejs_compat"] + compatibility_date = "2024-11-13" + ``` + +5. Build and deploy: + ```bash + pnpm build + wrangler pages deploy dist + ``` + +### Node.js Server + +1. Set in your `.env` file: + + ``` + VITE_DEPLOYMENT_TARGET=node-server + ``` + +2. Create an `app.config.ts` file in your project root: + + ```typescript + import { defineConfig } from '@tanstack/react-start/config'; + + export default defineConfig({ + server: { + preset: 'node-server', + }, + }); + ``` + +3. Build and run: + ```bash + pnpm build + node .output/server/index.mjs + ``` + +### Bun Server + +**Note:** Bun deployment requires React 19 or higher. + +1. Ensure you're using React 19: + + ```bash + pnpm add react@rc react-dom@rc + ``` + +2. Set in your `.env` file: + + ``` + VITE_DEPLOYMENT_TARGET=bun + ``` + +3. Create an `app.config.ts` file in your project root: + + ```typescript + import { defineConfig } from '@tanstack/react-start/config'; + + export default defineConfig({ + server: { + preset: 'bun', + }, + }); + ``` + +4. Build and run: + ```bash + bun run build + bun run .output/server/index.mjs + ``` + +## Environment Variables in Production + +Make sure to set all necessary environment variables in your deployment platform: + +- Database URL +- Authentication secrets +- API keys +- And any other variables from `.env.example` + +Each deployment platform has its own way of setting environment variables: + +- **Netlify**: Use the Netlify UI or `netlify.toml` +- **Vercel**: Use the Vercel dashboard or `vercel.json` +- **Cloudflare Pages**: Use the Cloudflare dashboard +- **Node.js/Bun**: Use a `.env` file or system environment variables diff --git a/README.md b/README.md index a4d015f..40f9696 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,6 @@ > ⚠️ **Work in Progress** - This starter kit is currently under active development. Features and documentation may change frequently. - ## ✨ Features - **[TanStack Start](https://tanstack.com/start)** - Modern full-stack React framework @@ -28,7 +27,8 @@ ## 🚀 Quick Start ### Prerequisites -- **Node.js** 18+ + +- **Node.js** 18+ - **pnpm** (recommended package manager) ### Installation @@ -99,47 +99,47 @@ drizzle/ # Database migrations tests/ # Test files ``` -| Command | Description | Args | -| :--------- | :------------------------------------------------------------------------- | :------------------- | -| `init` | Initialize the project (dependencies, DB setup, Docker) | | -| `stop` | Stop running Docker containers | | -| `reload` | Reload Docker containers with updated configuration | | -| `recreate` | Recreate Docker containers and volume (WARNING: deletes all data!) | | -| `recreate` | Recreate Docker containers (use --wipeVolume to also delete the data volume) | `--wipeVolume` | -| `testdata` | Create or delete seed test data in the database | `--create`, `--delete` | -| `deploy` | [TODO] Deploy the application | | +| Command | Description | Args | +| :--------- | :---------------------------------------------------------------------------------------- | :--------------------- | +| `init` | Initialize the project (dependencies, DB setup, Docker) | | +| `stop` | Stop running Docker containers | | +| `reload` | Reload Docker containers with updated configuration | | +| `recreate` | Recreate Docker containers and volume (WARNING: deletes all data!) | | +| `recreate` | Recreate Docker containers (use --wipeVolume to also delete the data volume) | `--wipeVolume` | +| `testdata` | Create or delete seed test data in the database | `--create`, `--delete` | +| `deploy` | [TODO] Deploy the application | | ### npm/pnpm Scripts Standard project scripts are available via `pnpm `. -| Script | Description | Underlying Command | -| :----------------- | :----------------------------------------------- | :--------------------------------------------------------------------------------------- | -| `dev` | Start development server | `vite` | -| `build` | Build the project | `vite build` | -| `start` | Start production server | `vite preview` | -| `test` | Run tests | `vitest` | -| `db:pull` | Pull database schema using Drizzle Kit | `npx drizzle-kit pull` | -| `db:generate` | Generate Drizzle migrations/schema changes | `npx drizzle-kit generate` | -| `db:migrate` | Apply Drizzle migrations | `npx drizzle-kit migrate` | -| `auth:init` | Generate Better Auth schema | `npx -y @better-auth/cli@latest generate --config src/server/auth.ts --output src/server/db/auth.schema.ts` | -| `ex0` | Run the custom project CLI | `tsx cli/index.ts` | +| Script | Description | Underlying Command | +| :------------ | :----------------------------------------- | :---------------------------------------------------------------------------------------------------------- | +| `dev` | Start development server | `vite` | +| `build` | Build the project | `vite build` | +| `start` | Start production server | `vite preview` | +| `test` | Run tests | `vitest` | +| `db:pull` | Pull database schema using Drizzle Kit | `npx drizzle-kit pull` | +| `db:generate` | Generate Drizzle migrations/schema changes | `npx drizzle-kit generate` | +| `db:migrate` | Apply Drizzle migrations | `npx drizzle-kit migrate` | +| `auth:init` | Generate Better Auth schema | `npx -y @better-auth/cli@latest generate --config src/server/auth.ts --output src/server/db/auth.schema.ts` | +| `ex0` | Run the custom project CLI | `tsx cli/index.ts` | ### Tech Stack Reference -| Technology | Purpose | Documentation | -|------------|---------|---------------| -| **TanStack Start** | Full-stack React framework | [Docs](https://tanstack.com/start) | -| **TanStack Router** | Type-safe file-based routing | [Docs](https://tanstack.com/router) | -| **Better Auth** | Authentication & user management | [Docs](https://better-auth.com/) | -| **Drizzle ORM** | Type-safe database ORM | [Docs](https://orm.drizzle.team/) | -| **PostgreSQL** | Database | [Docs](https://postgresql.org/) | -| **shadcn/ui** | Component library | [Docs](https://ui.shadcn.com/) | -| **Tailwind CSS** | Utility-first CSS framework | [Docs](https://tailwindcss.com/) | -| **TypeScript** | Type safety | [Docs](https://typescriptlang.org/) | -| **Oxlint** | Fast JavaScript/TypeScript linter | [Docs](https://oxc.rs/) | -| **Vitest** | Unit testing framework | [Docs](https://vitest.dev/) | -| **Resend** | Email delivery service | [Docs](https://resend.com/) | +| Technology | Purpose | Documentation | +| ------------------- | --------------------------------- | ----------------------------------- | +| **TanStack Start** | Full-stack React framework | [Docs](https://tanstack.com/start) | +| **TanStack Router** | Type-safe file-based routing | [Docs](https://tanstack.com/router) | +| **Better Auth** | Authentication & user management | [Docs](https://better-auth.com/) | +| **Drizzle ORM** | Type-safe database ORM | [Docs](https://orm.drizzle.team/) | +| **PostgreSQL** | Database | [Docs](https://postgresql.org/) | +| **shadcn/ui** | Component library | [Docs](https://ui.shadcn.com/) | +| **Tailwind CSS** | Utility-first CSS framework | [Docs](https://tailwindcss.com/) | +| **TypeScript** | Type safety | [Docs](https://typescriptlang.org/) | +| **Oxlint** | Fast JavaScript/TypeScript linter | [Docs](https://oxc.rs/) | +| **Vitest** | Unit testing framework | [Docs](https://vitest.dev/) | +| **Resend** | Email delivery service | [Docs](https://resend.com/) | ## 🔧 Configuration @@ -190,6 +190,7 @@ The application supports **multiple email providers** for maximum flexibility. Y #### Email Provider Options 1. **Console Provider** (Default for development) + - Logs emails to the console - No external dependencies - Perfect for initial development @@ -199,6 +200,7 @@ The application supports **multiple email providers** for maximum flexibility. Y ``` 2. **Mailhog** (Recommended for local development) + - Catches all emails locally - Web UI to view emails at http://localhost:8025 - Already included in Docker Compose @@ -209,11 +211,13 @@ The application supports **multiple email providers** for maximum flexibility. Y ``` Start Mailhog with Docker: + ```bash docker-compose up -d mailhog ``` 3. **SMTP Provider** (For production or custom email servers) + ```bash EMAIL_PROVIDER="smtp" SMTP_HOST="smtp.gmail.com" @@ -224,6 +228,7 @@ The application supports **multiple email providers** for maximum flexibility. Y ``` 4. **Resend** (Modern email API) + ```bash EMAIL_PROVIDER="resend" RESEND_API_KEY="re_xxxxxxxxxxxx" @@ -249,6 +254,7 @@ VITE_ENABLE_EMAIL_VERIFICATION="true" The email system is designed to be extensible. To add a new provider: 1. **Create a new provider class** in `src/server/email/providers.ts`: + ```typescript export class MyCustomProvider implements EmailProvider { async sendEmail({ from, to, subject, html }) { @@ -258,6 +264,7 @@ The email system is designed to be extensible. To add a new provider: ``` 2. **Add the provider to the factory** in `src/server/email/index.ts`: + ```typescript case "custom": emailProvider = new MyCustomProvider(); @@ -273,11 +280,13 @@ The email system is designed to be extensible. To add a new provider: #### Email Verification Behavior **When disabled** (default): + - Users are automatically signed in after registration - No verification email is sent - Users are redirected directly to the dashboard **When enabled**: + - Users must verify their email before signing in - A verification email is sent upon registration - Users are redirected to a "check your email" page @@ -290,6 +299,7 @@ The application supports OAuth authentication with GitHub and Google. Here's how #### GitHub OAuth Setup 1. **Create a GitHub OAuth App:** + - Go to [GitHub Developer Settings](https://github.com/settings/developers) - Click "New OAuth App" - Fill in the application details: @@ -298,15 +308,17 @@ The application supports OAuth authentication with GitHub and Google. Here's how - **Authorization callback URL**: `http://localhost:3000/api/auth/callback/github` 2. **Get your credentials:** + - After creating the app, copy the **Client ID** - Generate a new **Client Secret** 3. **Add to environment variables:** + ```bash # Server-side configuration GITHUB_CLIENT_ID="your-github-client-id" GITHUB_CLIENT_SECRET="your-github-client-secret" - + # Client-side configuration (for UI buttons) VITE_GITHUB_CLIENT_ID="your-github-client-id" ``` @@ -318,29 +330,34 @@ The application supports OAuth authentication with GitHub and Google. Here's how #### Google OAuth Setup 1. **Create a Google OAuth App:** + - Go to [Google Cloud Console](https://console.cloud.google.com/) - Create a new project or select an existing one - Enable the Google+ API - Go to "Credentials" → "Create Credentials" → "OAuth 2.0 Client IDs" 2. **Configure OAuth consent screen:** + - Fill in the required application information - Add your domain to authorized domains 3. **Create OAuth 2.0 Client ID:** + - Application type: **Web application** - **Authorized JavaScript origins**: `http://localhost:3000` (for development) - **Authorized redirect URIs**: `http://localhost:3000/api/auth/callback/google` 4. **Get your credentials:** + - Copy the **Client ID** and **Client Secret** 5. **Add to environment variables:** + ```bash # Server-side configuration GOOGLE_CLIENT_ID="your-google-client-id" GOOGLE_CLIENT_SECRET="your-google-client-secret" - + # Client-side configuration (for UI buttons) VITE_GOOGLE_CLIENT_ID="your-google-client-id" ``` @@ -354,6 +371,7 @@ The application supports OAuth authentication with GitHub and Google. Here's how Once configured, users will see GitHub and Google sign-in options on the authentication pages. The OAuth providers are conditionally enabled based on the presence of their respective environment variables. ### Adding shadcn/ui Components + ```bash # Add new components npx shadcn@latest add button @@ -362,23 +380,27 @@ npx shadcn@latest add input ``` ### Database + - **PostgreSQL** with Drizzle ORM for type-safe database operations - **Docker Compose** setup included for local development - **Drizzle Studio** for database visualization and management ### Authentication + - **Better Auth** provides secure authentication with email/password and OAuth - **Protected routes** with automatic redirects - **Email verification** and password reset functionality - **GitHub & Google OAuth** support ### Styling & Components + - **Tailwind CSS** for utility-first styling - **shadcn/ui** for beautiful, accessible components - **CSS custom properties** for theming support - **Dark/light mode** toggle included ### Development Tools + - **Oxlint** for fast linting - **TypeScript** for type safety - **Vitest** for testing @@ -386,12 +408,20 @@ npx shadcn@latest add input ## 🚀 Deployment +### Deployment Targets + +This project supports multiple deployment targets including Netlify, Vercel, Cloudflare Pages, Node.js, and Bun. The deployment target can be configured via environment variables. + +See [DEPLOYMENT.md](DEPLOYMENT.md) for detailed deployment instructions for each platform. + ### Build for Production + ```bash pnpm build ``` ### Start Production Server + ```bash pnpm start ``` @@ -405,5 +435,3 @@ This project is licensed under the MIT License - see the [LICENSE](LICENSE) file

Built with ❤️ using modern React tools

- - diff --git a/src/types/deployment.ts b/src/types/deployment.ts new file mode 100644 index 0000000..354f3b5 --- /dev/null +++ b/src/types/deployment.ts @@ -0,0 +1,25 @@ +/** + * Valid deployment targets for the application + */ +export type DeploymentTarget = 'netlify' | 'vercel' | 'cloudflare-pages' | 'node-server' | 'bun'; + +/** + * Configuration options for TanStack Start plugin + */ +export interface TanStackStartOptions { + target?: DeploymentTarget; +} + +/** + * Validates if a string is a valid deployment target + */ +export function isValidDeploymentTarget(target: string): target is DeploymentTarget { + const validTargets: DeploymentTarget[] = [ + 'netlify', + 'vercel', + 'cloudflare-pages', + 'node-server', + 'bun', + ]; + return validTargets.includes(target as DeploymentTarget); +} diff --git a/vite.config.ts b/vite.config.ts index 6616d39..3930307 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -1,17 +1,32 @@ -import tailwindcss from "@tailwindcss/vite" -import { tanstackStart } from "@tanstack/react-start/plugin/vite" -import { defineConfig } from "vite" -import tsConfigPaths from "vite-tsconfig-paths" +import tailwindcss from '@tailwindcss/vite'; +import { tanstackStart } from '@tanstack/react-start/plugin/vite'; +import { defineConfig, loadEnv } from 'vite'; +import tsConfigPaths from 'vite-tsconfig-paths'; +import type { DeploymentTarget, TanStackStartOptions } from '~/types/deployment'; -export default defineConfig({ +export default defineConfig(({ mode }) => { + // Load environment variables + const env = loadEnv(mode, process.cwd(), ''); + + // Get deployment target from environment variable + const deploymentTarget = env.VITE_DEPLOYMENT_TARGET as DeploymentTarget | undefined; + + // Prepare tanstackStart options + const tanstackStartOptions: TanStackStartOptions = {}; + if (deploymentTarget) { + tanstackStartOptions.target = deploymentTarget; + } + + return { server: { - port: 3000 + port: 3000, }, plugins: [ - tsConfigPaths({ - projects: ["./tsconfig.json"] - }), - tanstackStart(), - tailwindcss() - ] -}) + tsConfigPaths({ + projects: ['./tsconfig.json'], + }), + tanstackStart(tanstackStartOptions), + tailwindcss(), + ], + }; +});