diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index f50768f..f332962 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -22,6 +22,7 @@ on: type: choice options: - vercel + - render - firebase jobs: @@ -39,6 +40,19 @@ jobs: VERCEL_TOKEN: ${{ secrets.VERCEL_TOKEN }} VERCEL_ENV: ${{ github.event.inputs.environment || 'production' }} + deploy-render: + if: ${{ github.event_name == 'workflow_dispatch' && inputs.provider == 'render' }} + runs-on: ubuntu-latest + environment: + name: ${{ github.event.inputs.environment }} + steps: + - uses: actions/checkout@v7 + - uses: jdx/mise-action@v4 + - name: Deploy to Render + run: mise run deploy:render + env: + RENDER_DEPLOY_HOOK: ${{ secrets.RENDER_DEPLOY_HOOK }} + deploy-firebase: if: ${{ github.event_name == 'workflow_dispatch' && inputs.provider == 'firebase' }} runs-on: ubuntu-latest diff --git a/.mise.toml b/.mise.toml index 38c140a..b3de21f 100644 --- a/.mise.toml +++ b/.mise.toml @@ -109,6 +109,16 @@ else fi """ +[tasks."deploy:render"] +description = "Deploy the site to Render" +run = """ +if [ -z "$RENDER_DEPLOY_HOOK" ]; then + echo "Error: RENDER_DEPLOY_HOOK is not set." >&2 + exit 1 +fi +curl -f -X POST "$RENDER_DEPLOY_HOOK" +""" + [tasks."deploy:vercel"] description = "Deploy the site to Vercel" run = """ diff --git a/AGENTS.md b/AGENTS.md index 6b8eddf..f51bd07 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -57,6 +57,7 @@ Validated via Zod in `app/lib/env.ts`. ## 13. Deployment - Vercel: Primary target for SSR site (`mise run deploy:vercel` / `deploy.yml`). +- Render: Web service target for SSR site (`mise run deploy:render` / `render.yaml` / `deploy.yml`). - Firebase Hosting: Alternative target for site and docs (`mise run deploy:firebase`). - GitHub Pages: Static documentation hosting (`docs.yml`). diff --git a/README.md b/README.md index c18a295..b36570b 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ cur8d is an opinionated, production-ready Next.js starter template optimized for - **Comprehensive Testing Rigor**: Robust test coverage enforcement (80%+ target) with Vitest for unit/component tests and Playwright for E2E, visual, and accessibility (Axe) audits. - **Static Documentation Project**: An integrated documentation workspace powered by Nextra, generating a static site ready for GitHub Pages or Firebase hosting. - **Zero-Friction Dev Environment**: Fully managed local development tasks and toolchains via `mise`, including custom alias shortcuts for common git and npm tasks. -- **Flexible Deployment Targets**: Configured for Serverless deployments on Vercel (ideal for Next.js App Router and Server Components) and static site deployment on Firebase Hosting. +- **Flexible Deployment Targets**: Configured for Serverless deployments on Vercel, Node.js web service on Render, and static site deployment on Firebase Hosting. ## Project Structure @@ -33,6 +33,7 @@ This project is organized as a monorepo workspace managed by `pnpm`: │ ├── unit/ # Component and utility tests (Vitest) │ └── e2e/ # E2E and accessibility audits (Playwright) ├── .mise.toml # Toolchain, task definitions, and run shortcuts +├── render.yaml # Render Blueprint specification └── pnpm-workspace.yaml # Monorepo workspaces definition ``` @@ -49,7 +50,7 @@ The core framework and library stack includes (without version locks): - **Unit Testing**: Vitest with React Testing Library & jsdom - **E2E & A11y Testing**: Playwright & `@axe-core/playwright` - **Documentation**: Nextra & Markdown (MDX) -- **Deployments**: Vercel CLI & Firebase CLI +- **Deployments**: Vercel CLI, Render Blueprint & Deploy Hook, and Firebase CLI ## Quick Start diff --git a/docs/content/adr/adr-008-vercel.mdx b/docs/content/adr/adr-008-vercel.mdx index c4ecb38..50085c7 100644 --- a/docs/content/adr/adr-008-vercel.mdx +++ b/docs/content/adr/adr-008-vercel.mdx @@ -5,11 +5,11 @@ Status: Accepted We need a scalable, automated hosting architecture supporting both Server-Side Rendered (SSR) web applications and static documentation. ## Decision -We chose Vercel as the primary SSR deployment platform, Firebase Hosting as an alternative multi-target host, and GitHub Pages for static documentation. +We chose Vercel as the primary SSR deployment platform, Render as a managed Node.js web service platform, Firebase Hosting as an alternative multi-target host, and GitHub Pages for static documentation. ## Rationale -Vercel delivers native zero-configuration optimization for Next.js App Router, React Server Components, and Edge Middleware. GitHub Pages provides free, high-availability hosting for Nextra static docs, and Firebase Hosting serves as a battle-tested static and preview environment. +Vercel delivers native zero-configuration optimization for Next.js App Router, React Server Components, and Edge Middleware. Render provides fully managed Node.js runtime hosting with Blueprints and Deploy Hooks. GitHub Pages provides free, high-availability hosting for Nextra static docs, and Firebase Hosting serves as a battle-tested static and preview environment. ## Consequences -Workflows in `.github/workflows/` are partitioned into `deploy.yml` (application deployment to Vercel/Firebase) and `docs.yml` (documentation deployment to GitHub Pages). +Workflows in `.github/workflows/` are partitioned into `deploy.yml` (application deployment to Vercel/Render/Firebase) and `docs.yml` (documentation deployment to GitHub Pages). diff --git a/docs/content/deployment/_meta.js b/docs/content/deployment/_meta.js index c8b0cd9..5b4019c 100644 --- a/docs/content/deployment/_meta.js +++ b/docs/content/deployment/_meta.js @@ -1,6 +1,7 @@ export default { "index": "Overview", "vercel": "Vercel", + "render": "Render", "firebase": "Firebase Hosting", "github-pages": "GitHub Pages" } \ No newline at end of file diff --git a/docs/content/deployment/index.mdx b/docs/content/deployment/index.mdx index 2292ea8..da62701 100644 --- a/docs/content/deployment/index.mdx +++ b/docs/content/deployment/index.mdx @@ -3,6 +3,7 @@ Instructions for deploying your cur8d application and documentation. - [Vercel](/deployment/vercel) +- [Render](/deployment/render) - [Firebase Hosting](/deployment/firebase) - [GitHub Pages](/deployment/github-pages) diff --git a/docs/content/deployment/render.mdx b/docs/content/deployment/render.mdx new file mode 100644 index 0000000..082823b --- /dev/null +++ b/docs/content/deployment/render.mdx @@ -0,0 +1,36 @@ +# Render Deployment + +Render provides cloud hosting for Next.js App Router applications as a managed Node.js web service, fully supporting Server Components, API routes, and SSR. + +## Configuration + +Render services can be defined as Infrastructure-as-Code using Render Blueprints: + +- [`render.yaml`](file:///Users/amrabed/Library/CloudStorage/OneDrive-Personal/code/cur8d.tsx/render.yaml): Configures the web service name, Node.js runtime, build command (`pnpm install && pnpm run build`), start command (`pnpm run start`), and environment variables. + +## Automated CI/CD Deployment + +Render deployment can be automated via Render Deploy Hooks and GitHub Actions: + +- **Deploy Hooks**: Trigger zero-downtime deployments instantly by sending a POST request to your Render Deploy Hook URL. +- **GitHub Actions Workflow**: Configured in `.github/workflows/deploy.yml`. Can be triggered on-demand via `workflow_dispatch` selecting the `render` provider. + +### Setting up Secrets in GitHub + +To enable automated deployments via GitHub Actions: +1. Navigate to your Web Service in the [Render Dashboard](https://dashboard.render.com). +2. Go to **Settings** > **Deploy Hook** and copy your hook URL. +3. Add `RENDER_DEPLOY_HOOK` to your repository secrets (`Settings > Secrets and variables > Actions`). + +## Local Deployment via mise + +You can trigger a deployment directly from your terminal using `mise` or `pnpm`: + +```bash +# Trigger Render deployment via deploy hook +export RENDER_DEPLOY_HOOK="https://api.render.com/deploy/srv-xxxx?key=yyyy" +mise run deploy:render + +# Or using package.json script directly +pnpm run deploy:render +``` diff --git a/docs/content/getting-started/environment-variables.mdx b/docs/content/getting-started/environment-variables.mdx index 3ecbd10..669d749 100644 --- a/docs/content/getting-started/environment-variables.mdx +++ b/docs/content/getting-started/environment-variables.mdx @@ -21,6 +21,7 @@ Environment variables are validated against the `envSchema` defined in `app/lib/ These tokens are used by deployment workflows in `.github/workflows/deploy.yml` and local deployment tasks defined in `.mise.toml`: - `VERCEL_TOKEN`: Authentication token for automated deployments using Vercel CLI. +- `RENDER_DEPLOY_HOOK`: Webhook URL for triggering automated deployments to Render. - `FIREBASE_TOKEN`: Authentication token for deploying to Firebase Hosting via Firebase CLI. ## Schema Definition diff --git a/docs/content/getting-started/project-structure.mdx b/docs/content/getting-started/project-structure.mdx index c65f295..1c2eae3 100644 --- a/docs/content/getting-started/project-structure.mdx +++ b/docs/content/getting-started/project-structure.mdx @@ -13,6 +13,7 @@ The project follows a modern Next.js App Router workspace structure optimized fo - `.mise.toml`: Toolchain management and task definitions. - `pnpm-workspace.yaml`: Monorepo workspaces definition. - `firebase.json` & `.firebaserc`: Firebase Hosting configuration for app and docs. +- `render.yaml`: Render Blueprint deployment configuration. - `vercel.json`: Vercel deployment configuration. ## Application Directory (`app/`) diff --git a/docs/content/reference/workflows.mdx b/docs/content/reference/workflows.mdx index 01f2a75..0730ad6 100644 --- a/docs/content/reference/workflows.mdx +++ b/docs/content/reference/workflows.mdx @@ -22,9 +22,10 @@ Cur8d includes pre-configured GitHub Actions workflows in `.github/workflows/` w - **Triggers**: Push to `main` (excluding changes strictly in `docs/**`) and manual trigger (`workflow_dispatch`). - **Inputs**: - `environment`: `'production'` (default) or `'preview'`. - - `provider`: `'vercel'` (default) or `'firebase'`. + - `provider`: `'vercel'` (default), `'render'`, or `'firebase'`. - **Jobs**: - `deploy-vercel`: Runs `mise run deploy:vercel` using `VERCEL_TOKEN`. + - `deploy-render`: Runs `mise run deploy:render` using `RENDER_DEPLOY_HOOK`. - `deploy-firebase`: Runs `mise run deploy:firebase` using `FIREBASE_TOKEN`. ### 3. Documentation Deployment (`docs.yml`) diff --git a/package.json b/package.json index cfebf8b..d36f3cf 100644 --- a/package.json +++ b/package.json @@ -17,7 +17,8 @@ "test:e2e:report": "playwright show-report", "analyze": "ANALYZE=true next build", "deploy:firebase": "firebase deploy --only hosting:site", - "deploy:firebase:docs": "firebase deploy --only hosting:docs" + "deploy:firebase:docs": "firebase deploy --only hosting:docs", + "deploy:render": "curl -f -X POST $RENDER_DEPLOY_HOOK" }, "dependencies": { "@heroui/react": "3.2.4", diff --git a/render.yaml b/render.yaml new file mode 100644 index 0000000..573b7bf --- /dev/null +++ b/render.yaml @@ -0,0 +1,10 @@ +services: + - type: web + name: cur8d + runtime: node + plan: starter + buildCommand: pnpm install && pnpm run build + startCommand: pnpm run start + envVars: + - key: NODE_ENV + value: production diff --git a/scripts/init.ts b/scripts/init.ts index eb47c6a..6a8289f 100644 --- a/scripts/init.ts +++ b/scripts/init.ts @@ -92,6 +92,7 @@ async function main() { 'app/components/Navbar/index.tsx', 'app/page.tsx', '.firebaserc', + 'render.yaml', 'docs/app/[[...mdxPath]]/layout.tsx', 'docs/theme.config.jsx', 'docs/next.config.mjs', @@ -151,12 +152,15 @@ async function main() { content = content.replace(/"name": "docs"/, `"name": "${slug}-docs"`); } - // 4. Firebase project IDs + // 4. Firebase & Render project configs if (file === '.firebaserc') { content = content.replace(/cur8d-vibe/g, `${slug}`); content = content.replace(/cur8d-site/g, `${slug}-site`); content = content.replace(/cur8d-docs/g, `${slug}-docs`); } + if (file === 'render.yaml') { + content = content.replace(/name: cur8d/g, `name: ${slug}`); + } // 5. Descriptions (must happen before general cur8d replacement) if (description) {