Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -60,3 +60,11 @@ GOOGLE_SHEETS_CLIENT_SECRET=""
GOOGLE_DRIVE_CLIENT_ID=""
GOOGLE_DRIVE_CLIENT_SECRET=""

# DigitalOcean Spaces (S3-compatible Object Storage)
DO_SPACES_KEY=""
DO_SPACES_SECRET=""
DO_SPACES_ENDPOINT="https://blr1.digitaloceanspaces.com"
DO_SPACES_BUCKET="nodebase-media"
DO_SPACES_REGION="blr1"
DO_SPACES_CDN_URL=""
DO_SPACES_SAS_EXPIRY_HOURS="48"
124 changes: 124 additions & 0 deletions .github/workflows/deploy-digitalocean.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
name: Build and Deploy to DigitalOcean

on:
push:
branches: [main]
pull_request:
branches: [main]

env:
REGISTRY: registry.digitalocean.com/nodebase
IMAGE_NAME: nodebase

jobs:
# ─── Build & Push Docker image to DigitalOcean Container Registry ───
build-and-push:
name: Build & Push to DOCR
runs-on: ubuntu-latest
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
permissions:
contents: read

steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: Install doctl
uses: digitalocean/action-doctl@v2
with:
token: ${{ secrets.DIGITALOCEAN_ACCESS_TOKEN }}

- name: Log in to DigitalOcean Container Registry
run: doctl registry login --expiry-seconds 1200

- name: Build Docker image
run: |
docker build \
-t ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:sha-${{ github.sha }} \
-t ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest \
.

- name: Push Docker image
run: |
docker push ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:sha-${{ github.sha }}
docker push ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest

# ─── Deploy to DigitalOcean App Platform ────────────────────────────
deploy:
name: Deploy to App Platform
runs-on: ubuntu-latest
needs: build-and-push
if: github.event_name == 'push' && github.ref == 'refs/heads/main'

steps:
- name: Install doctl
uses: digitalocean/action-doctl@v2
with:
token: ${{ secrets.DIGITALOCEAN_ACCESS_TOKEN }}

- name: Deploy to App Platform
run: |
APP_ID=$(doctl apps list --format ID --no-header | head -1)
if [ -z "$APP_ID" ]; then
echo "❌ No App Platform app found. Create one first in DigitalOcean console."
exit 1
fi
echo "🚀 Triggering deployment for App: $APP_ID"
doctl apps create-deployment "$APP_ID" --wait
echo "✅ Deployment complete!"
Comment thread
coderabbitai[bot] marked this conversation as resolved.

# ─── PR Build Validation ────────────────────────────────────────────
build-check:
name: Validate build (PR only)
runs-on: ubuntu-latest
if: github.event_name == 'pull_request'
permissions:
contents: read

steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'

- name: Install dependencies
run: npm ci

- name: Generate Prisma client
run: npx prisma generate

- name: Type check
run: npx tsc --noEmit

- name: Build
run: npm run build
env:
NODE_OPTIONS: "--max-old-space-size=4096"
DATABASE_URL: "postgresql://dummy:dummy@dummy:5432/dummy"
DIRECT_DATABASE_URL: "postgresql://dummy:dummy@dummy:5432/dummy"
BETTER_AUTH_SECRET: "dummy-secret-for-build-only"
BETTER_AUTH_URL: "https://nodebase.tech"
NEXT_PUBLIC_BETTER_AUTH_URL: "https://nodebase.tech"
NEXT_PUBLIC_APP_URL: "https://nodebase.tech"
INNGEST_SIGNING_KEY: "signkey-prod-dummy"
INNGEST_EVENT_KEY: "dummy-event-key"
ENCRYPTION_KEY: "dummy-encryption-key-32-characters"
GOOGLE_CLIENT_ID: "dummy"
GOOGLE_CLIENT_SECRET: "dummy"
GOOGLE_GMAIL_CLIENT_ID: "dummy"
GOOGLE_GMAIL_CLIENT_SECRET: "dummy"
GOOGLE_SHEETS_CLIENT_ID: "dummy"
GOOGLE_SHEETS_CLIENT_SECRET: "dummy"
GOOGLE_DRIVE_CLIENT_ID: "dummy"
GOOGLE_DRIVE_CLIENT_SECRET: "dummy"
GITHUB_CLIENT_ID: "dummy"
GITHUB_CLIENT_SECRET: "dummy"
GROQ_API_KEY: "dummy"
GOOGLE_GENERATIVE_AI_API_KEY: "dummy"
POLAR_ACCESS_TOKEN: "dummy"
POLAR_WEBHOOK_SECRET: "dummy"
SENTRY_AUTH_TOKEN: "dummy"
108 changes: 0 additions & 108 deletions .github/workflows/deploy.yml

This file was deleted.

This file was deleted.

2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ COPY . .
RUN npx prisma generate

# Dummy env vars so Next.js can build without real credentials
# Real values are injected at runtime by Azure Container Apps
# Real values are injected at runtime by DigitalOcean App Platform
ENV NEXT_TELEMETRY_DISABLED=1
ENV DATABASE_URL="postgresql://dummy:dummy@dummy:5432/dummy"
ENV DIRECT_DATABASE_URL="postgresql://dummy:dummy@dummy:5432/dummy"
Expand Down
43 changes: 43 additions & 0 deletions next-sitemap.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/** @type {import('next-sitemap').IConfig} */
module.exports = {
siteUrl: "https://nodebase.tech",
generateRobotsTxt: true,
generateIndexSitemap: false,
changefreq: "weekly",
priority: 0.7,
sitemapSize: 5000,
exclude: [
"/workflows/*",
"/editor/*",
"/settings/*",
"/api/*",
"/verify-email",
"/check-email",
"/resend-verification",
],
additionalPaths: async (config) => [
await config.transform(config, "/"),
await config.transform(config, "/pricing"),
await config.transform(config, "/blog"),
await config.transform(config, "/integrations"),
await config.transform(config, "/login"),
await config.transform(config, "/signup"),
],
robotsTxtOptions: {
policies: [
{
userAgent: "*",
allow: "/",
disallow: ["/workflows/", "/editor/", "/settings/", "/api/"],
},
{
userAgent: "Googlebot",
allow: "/",
disallow: ["/workflows/", "/editor/", "/settings/"],
},
],
additionalSitemaps: [
"https://nodebase.tech/sitemap.xml",
],
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Outdated
},
}
9 changes: 9 additions & 0 deletions next.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,15 @@ import type { NextConfig } from "next";
const nextConfig: NextConfig = {
output: "standalone",
devIndicators: false,
// AWS SDK v3 uses deep subpath exports that Turbopack can't resolve —
// mark them as external so Node.js handles module resolution natively
serverExternalPackages: [
"@aws-sdk/client-s3",
"@aws-sdk/s3-request-presigner",
"@aws-sdk/core",
"@aws-sdk/signature-v4-multi-region",
"@smithy/core",
],
async redirects() {

return [];
Expand Down
Loading
Loading