create-apollo-monorepo 0.9.786 → 0.9.787

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +1 -1
  2. package/index.mjs +30 -137
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -45,7 +45,7 @@ collide:
45
45
  | ------------------------------------ | -------------------- |
46
46
  | `/`, your custom routes | `apps/frontend` |
47
47
  | `/admin/*` | `apps/backend` (admin pages **and** their JS chunks) |
48
- | `/api/auth/*`, `/api/v1/*`, `/api/admin/*`, `/api/email/*`, `/api/cron`, `/api/health`, `/api/mcp`, `/api/editing-presence/*` | `apps/backend` |
48
+ | `/api/auth/*`, `/api/v1/*`, `/api/admin/*`, `/api/email/*`, `/api/health`, `/api/mcp`, `/api/editing-presence/*` | `apps/backend` |
49
49
  | `/uploads/*` | `apps/backend` (media) |
50
50
 
51
51
  Apollo CMS reads `APOLLO_ASSET_PREFIX` (default `/admin`) and serves its built
package/index.mjs CHANGED
@@ -227,14 +227,14 @@ function preflight(flags) {
227
227
  success(`Node.js ${process.versions.node}`);
228
228
 
229
229
  // bun is required at runtime by apps/backend (apollo-cms): db:push, db:seed,
230
- // dev:cron, plugins:build, the upgrade pipeline, and pre-commit hooks all
230
+ // plugins:build, the upgrade pipeline, and pre-commit hooks all
231
231
  // shell out to `bun`. The scaffold itself works without bun, but `pnpm dev`,
232
232
  // `pnpm backend:setup`, and `pnpm backend:upgrade` will fail without it.
233
233
  const TOOLS = [
234
234
  { cmd: "git", required: true, missing: "git is required but not found.\n Install: https://git-scm.com/" },
235
235
  { cmd: "pnpm", required: false, missing: "pnpm not found — install with: npm i -g pnpm (required for workspaces)" },
236
236
  { cmd: "bun", required: false, missing:
237
- "bun not found — required by apps/backend for db:push, db:seed, dev:cron,\n" +
237
+ "bun not found — required by apps/backend for db:push, db:seed,\n" +
238
238
  " plugins:build, and the upgrade pipeline.\n" +
239
239
  " Install: curl -fsSL https://bun.sh/install | bash (or: brew install bun)" },
240
240
  ];
@@ -318,12 +318,11 @@ function writeRootPackageJson(targetDir, dirName) {
318
318
  description: `${dirName} monorepo (frontend + apollo-cms backend submodule)`,
319
319
  scripts: {
320
320
  // We bypass apollo-cms's own `dev` script ("bun install && bun run
321
- // plugins:build && next dev & bun run scripts/dev-cron.ts") because the
322
- // bash-`&`-then-foreground pattern exits with SIGHUP (129) under pnpm's
323
- // parallel runner. Instead we explicitly run plugins:build (both ours
324
- // and apollo-cms's) and `next dev` directly. Cron is optional in dev
325
- // run `pnpm dev:cron` in a separate terminal if you need scheduled jobs
326
- // (production uses Vercel Cron via apps/backend/vercel.json).
321
+ // plugins:build && next dev") because the bash-`&`-then-foreground
322
+ // pattern exits with SIGHUP (129) under pnpm's parallel runner. Instead
323
+ // we explicitly run plugins:build (both ours and apollo-cms's) and
324
+ // `next dev` directly. Nothing extra to start for scheduled jobs the
325
+ // backend drives its scheduler queue in-process (dev and production).
327
326
  "predev:setup":
328
327
  "pnpm cms-plugins:build && pnpm --filter ./apps/backend exec bun run plugins:build",
329
328
  // `pnpm dev` runs FE + BE Next.js dev servers (which watch their own
@@ -343,7 +342,6 @@ function writeRootPackageJson(targetDir, dirName) {
343
342
  "node scripts/with-env.mjs --port=FRONTEND_PORT pnpm --filter ./apps/frontend exec next dev",
344
343
  "dev:backend":
345
344
  "pnpm predev:setup && node scripts/with-env.mjs --port=BACKEND_PORT pnpm --filter ./apps/backend exec next dev",
346
- "dev:cron": "pnpm --filter ./apps/backend exec bun scripts/dev-cron.ts",
347
345
  // Build pipeline: cms-plugins → apollo-cms's own plugins → backend → frontend.
348
346
  // `prebuild` runs first (npm/pnpm convention) and fails fast if the
349
347
  // backend's required env vars are missing.
@@ -366,12 +364,6 @@ function writeRootPackageJson(targetDir, dirName) {
366
364
  "node scripts/with-env.mjs --port=FRONTEND_PORT pnpm --filter ./apps/frontend exec next start",
367
365
  "start:backend":
368
366
  "node scripts/with-env.mjs --port=BACKEND_PORT pnpm --filter ./apps/backend exec next start",
369
- // Self-hosted scheduler fallback. Vercel deploys use Vercel Cron via
370
- // apps/backend/vercel.json — skip this on Vercel. For Docker / VPS
371
- // you can either run \`pnpm start:cron\` alongside \`pnpm start\` (PM2
372
- // handles this via ecosystem.config.cjs), or use system cron / k8s
373
- // CronJob to hit /api/cron with CRON_SECRET.
374
- "start:cron": "pnpm --filter ./apps/backend exec bun scripts/dev-cron.ts",
375
367
  "cms-plugins:build":
376
368
  "pnpm --filter './apps/cms-plugins/*' --parallel --if-present build",
377
369
  "cms-plugins:dev":
@@ -522,7 +514,7 @@ server {
522
514
  # Backend APIs (mirror the list in apps/frontend/next.config.ts).
523
515
  # \`editing-presence\` is included so the bare path also routes to backend;
524
516
  # streaming sub-paths still match the \`^~\` block above first.
525
- location ~ ^/api/(auth|v1|cron|email|health|mcp|admin|editing-presence)(/|$) {
517
+ location ~ ^/api/(auth|v1|email|health|mcp|admin|editing-presence)(/|$) {
526
518
  proxy_pass http://apollo_backend;
527
519
  }
528
520
 
@@ -546,7 +538,7 @@ function writeProxyApp(targetDir, dirName, adminPrefix) {
546
538
  // Routes (in order):
547
539
  // ${prefix}, ${prefix}/*, /uploads/* → backend
548
540
  // /api/editing-presence/* → backend (SSE)
549
- // /api/{auth,v1,cron,email,health,mcp,admin,...}/* → backend
541
+ // /api/{auth,v1,email,health,mcp,admin,...}/* → backend
550
542
  // /__proxy/health → 200 OK (proxy itself)
551
543
  // everything else → frontend
552
544
  //
@@ -597,7 +589,7 @@ const ADMIN_PREFIX = process.env.ADMIN_PREFIX ?? "${prefix}";
597
589
  // Pipe-separated list of /api/<segment> paths that route to the backend.
598
590
  const BACKEND_API_SEGMENTS = (
599
591
  process.env.BACKEND_API_PATHS ??
600
- "auth|v1|cron|email|health|mcp|admin|editing-presence"
592
+ "auth|v1|email|health|mcp|admin|editing-presence"
601
593
  ).trim();
602
594
  const BACKEND_API = new RegExp(\`^/api/(\${BACKEND_API_SEGMENTS})(/|$)\`);
603
595
 
@@ -840,7 +832,7 @@ single-origin URL.
840
832
  | \`BACKEND\` | \`http://127.0.0.1:3000\` | apps/backend dev server |
841
833
  | \`FRONTEND\` | \`http://127.0.0.1:3001\` | apps/frontend dev server |
842
834
  | \`ADMIN_PREFIX\` | \`${prefix}\` | Backend admin path prefix |
843
- | \`BACKEND_API_PATHS\` | \`auth\\|v1\\|cron\\|email\\|health\\|mcp\\|admin\\|editing-presence\` | Pipe-separated /api/* segments routed to backend |
835
+ | \`BACKEND_API_PATHS\` | \`auth\\|v1\\|email\\|health\\|mcp\\|admin\\|editing-presence\` | Pipe-separated /api/* segments routed to backend |
844
836
  | \`MAX_BODY_BYTES\` | \`52428800\` (50MB) | Reject larger bodies. \`0\` = unlimited |
845
837
  | \`UPSTREAM_TIMEOUT_MS\` | \`60000\` | Request timeout to upstream |
846
838
  | \`TRUST_PROXY\` | \`1\` | Honors inbound X-Forwarded-* from upstream TLS terminator (nginx/Caddy/CF/LB). Set \`0\` if proxy is directly internet-facing |
@@ -1065,10 +1057,9 @@ const config: NextConfig = {
1065
1057
  return [
1066
1058
  // Apollo CMS admin UI (and its chunks when APOLLO_ASSET_PREFIX is /admin)
1067
1059
  { source: "/admin/:path*", destination: \`\${BACKEND}/admin/:path*\` },
1068
- // Apollo CMS APIs (REST + auth + cron + email + health + mcp + …)
1060
+ // Apollo CMS APIs (REST + auth + email + health + mcp + …)
1069
1061
  { source: "/api/auth/:path*", destination: \`\${BACKEND}/api/auth/:path*\` },
1070
1062
  { source: "/api/v1/:path*", destination: \`\${BACKEND}/api/v1/:path*\` },
1071
- { source: "/api/cron", destination: \`\${BACKEND}/api/cron\` },
1072
1063
  { source: "/api/email/:path*", destination: \`\${BACKEND}/api/email/:path*\` },
1073
1064
  { source: "/api/health", destination: \`\${BACKEND}/api/health\` },
1074
1065
  { source: "/api/mcp", destination: \`\${BACKEND}/api/mcp\` },
@@ -1123,20 +1114,6 @@ export default config;
1123
1114
  // .env.local is intentionally committed — it only contains dev port hints.
1124
1115
  ["node_modules", ".next", "dist", ""].join("\n"),
1125
1116
  );
1126
-
1127
- // Vercel project config for the frontend. Skip cron + region pinning is
1128
- // optional; configure Root Directory + "Include all submodules" in the
1129
- // Vercel UI when linking the project.
1130
- const vercelJson = {
1131
- $schema: "https://openapi.vercel.sh/vercel.json",
1132
- regions: ["sin1"],
1133
- };
1134
- writeFileSync(resolve(dir, "vercel.json"), JSON.stringify(vercelJson, null, 2) + "\n");
1135
-
1136
- writeFileSync(
1137
- resolve(dir, ".vercelignore"),
1138
- ["node_modules", ".next", ".env.local", ""].join("\n"),
1139
- );
1140
1117
  }
1141
1118
 
1142
1119
  // ─── Custom plugins scaffold ─────────────────────────────────────────────────
@@ -1233,7 +1210,7 @@ if (watch) {
1233
1210
  // → dist/server.mjs (built by \`pnpm cms-plugins:build\`).
1234
1211
  //
1235
1212
  // In dev under Bun the loader can also import index.ts directly (with a
1236
- // warning); in production (Vercel / next start) the dist file is required.
1213
+ // warning); in production (next start) the dist file is required.
1237
1214
 
1238
1215
  import type { PluginDefinition } from "@/lib/plugins/types";
1239
1216
 
@@ -1441,7 +1418,7 @@ function writeCheckEnvScript(targetDir) {
1441
1418
  // Pre-build sanity check. Reads apps/backend/.env.local and verifies that
1442
1419
  // required vars are present and non-empty. Skipped when SKIP_ENV_CHECK=1.
1443
1420
  //
1444
- // In CI/Vercel where envs come from the platform (not files), set
1421
+ // In CI where envs come from the platform (not files), set
1445
1422
  // SKIP_ENV_CHECK=1 and rely on the platform's own validation.
1446
1423
 
1447
1424
  import { existsSync, readFileSync } from "node:fs";
@@ -1486,7 +1463,7 @@ console.log("✓ env check passed");
1486
1463
  }
1487
1464
 
1488
1465
  // PM2 ecosystem config — production process supervision for self-hosted deploys.
1489
- // Includes FE, BE, optional proxy, and optional cron in fork mode (no clustering
1466
+ // Includes FE, BE, and optional proxy in fork mode (no clustering
1490
1467
  // since Next.js handles that internally and the proxy is single-threaded by design).
1491
1468
  function writePm2Config(targetDir, dirName, adminPrefix) {
1492
1469
  const singleOrigin = !!adminPrefix;
@@ -1510,9 +1487,8 @@ function writePm2Config(targetDir, dirName, adminPrefix) {
1510
1487
  // pnpm install
1511
1488
  // pnpm backend:upgrade
1512
1489
  // pnpm build
1513
- // pm2 start ecosystem.config.cjs # FE + BE + proxy + cron
1490
+ // pm2 start ecosystem.config.cjs # FE + BE + proxy
1514
1491
  // pm2 start ecosystem.config.cjs --only proxy # only the reverse proxy
1515
- // pm2 start ecosystem.config.cjs --only cron # self-hosted cron fallback
1516
1492
  // pm2 stop \${PM2_NAMESPACE} # stop everything in this project
1517
1493
  // pm2 save && pm2 startup # persist across reboots
1518
1494
 
@@ -1538,9 +1514,9 @@ const FRONTEND_PORT = Number(process.env.FRONTEND_PORT) || 3001;
1538
1514
  const BACKEND_PORT = Number(process.env.BACKEND_PORT) || 3002;
1539
1515
  const PROXY_PORT = Number(process.env.PROXY_PORT) || 3030;
1540
1516
 
1541
- // Backend's internal URL (loopback). Cron MUST target this, never the proxy or
1542
- // frontend — going through the FE just adds a failure mode (HTML error → JSON
1543
- // parse blowup in dev-cron.ts).
1517
+ // Backend's internal URL (loopback). Server-to-server callers MUST target
1518
+ // this, never the proxy or frontend — going through the FE just adds a failure
1519
+ // mode (an HTML error page where JSON was expected).
1544
1520
  const BACKEND_INTERNAL_URL = process.env.BACKEND_INTERNAL_URL || \`http://127.0.0.1:\${BACKEND_PORT}\`;
1545
1521
 
1546
1522
  module.exports = {
@@ -1582,21 +1558,6 @@ ${proxyEnv}
1582
1558
  max_memory_restart: '256M',
1583
1559
  autorestart: true,
1584
1560
  },
1585
- {
1586
- name: 'cron',
1587
- namespace: NAMESPACE,
1588
- cwd: './apps/backend',
1589
- script: 'scripts/dev-cron.ts',
1590
- interpreter: 'bun',
1591
- env: {
1592
- NODE_ENV: 'production',
1593
- // dev-cron.ts derives its target from NEXT_PUBLIC_SITE_URL. Override
1594
- // it to the backend loopback so cron skips the FE/proxy entirely.
1595
- NEXT_PUBLIC_SITE_URL: BACKEND_INTERNAL_URL,
1596
- CRON_SECRET: process.env.CRON_SECRET,
1597
- },
1598
- autorestart: true,
1599
- },
1600
1561
  ],
1601
1562
  };
1602
1563
  `;
@@ -1612,7 +1573,7 @@ function writeClaudeMd(targetDir, adminPrefix) {
1612
1573
  Frontend is the public entry point. It rewrites these paths to the backend (do **not** create matching routes in the frontend):
1613
1574
 
1614
1575
  - \`/admin/*\`, \`/uploads/*\`
1615
- - \`/api/auth/*\`, \`/api/v1/*\`, \`/api/email/*\`, \`/api/cron\`, \`/api/health\`, \`/api/mcp\`, \`/api/admin/*\`, \`/api/editing-presence/*\`
1576
+ - \`/api/auth/*\`, \`/api/v1/*\`, \`/api/email/*\`, \`/api/health\`, \`/api/mcp\`, \`/api/admin/*\`, \`/api/editing-presence/*\`
1616
1577
  - \`/_next/static\` under \`APOLLO_ASSET_PREFIX=${prefix}\` (backend chunks)
1617
1578
 
1618
1579
  Custom frontend APIs must be namespaced (e.g. \`/api/internal/*\`).
@@ -1687,7 +1648,6 @@ Proxy reads \`PORT\`, \`BACKEND\`, \`FRONTEND\`, \`ADMIN_PREFIX\` from env. When
1687
1648
  ## Deploy
1688
1649
 
1689
1650
  - Self-hosted: build on a runner, rsync to the server, then \`pm2 startOrReload ecosystem.config.cjs --update-env\`. If the backend submodule is private, the deploy runner needs a token with read access.
1690
- - Vercel: two projects per repo (\`apps/backend\` and \`apps/frontend\` root dirs). Backend's Build Command must copy \`apps/cms-plugins/*/dist\` into \`apps/backend/plugins/\` before \`next build\` because Turbopack rejects \`outputFileTracingIncludes\` globs above the project root. "Include all submodules" must be ON in both projects.
1691
1651
 
1692
1652
  ## Submodule discipline
1693
1653
 
@@ -1710,7 +1670,7 @@ paths to the backend so /_next/* doesn't collide:
1710
1670
  | --------------------------- | ------------------ |
1711
1671
  | \`/\` and other frontend routes | \`apps/frontend\` |
1712
1672
  | \`/admin/*\` | \`apps/backend\` |
1713
- | \`/api/auth/*\`, \`/api/v1/*\`, \`/api/email/*\`, \`/api/cron\`, \`/api/health\`, \`/api/mcp\`, \`/api/admin/*\`, \`/api/editing-presence/*\` | \`apps/backend\` |
1673
+ | \`/api/auth/*\`, \`/api/v1/*\`, \`/api/email/*\`, \`/api/health\`, \`/api/mcp\`, \`/api/admin/*\`, \`/api/editing-presence/*\` | \`apps/backend\` |
1714
1674
  | \`/uploads/*\` | \`apps/backend\` (media) |
1715
1675
  | \`${adminPrefix}/*\` | \`apps/backend\` (chunks via \`APOLLO_ASSET_PREFIX\`) |
1716
1676
 
@@ -1727,7 +1687,7 @@ Two options ship out of the box:
1727
1687
  deploys. Configure via \`PORT\`, \`BACKEND\`, \`FRONTEND\`, \`ADMIN_PREFIX\`.
1728
1688
  - **\`nginx.conf.sample\`** (production) — same routing baked in (frontend on
1729
1689
  :3001, backend on :3000). Use it when fronting both apps behind a single
1730
- TLS-terminating proxy outside Vercel — drop in your domain and SSL certs.
1690
+ TLS-terminating proxy — drop in your domain and SSL certs.
1731
1691
 
1732
1692
  To **disable** single-origin and run the backend on its own subdomain,
1733
1693
  delete \`APOLLO_ASSET_PREFIX\` from \`apps/backend/.env.local\` and remove the
@@ -1865,14 +1825,13 @@ processes without re-running \`drizzle-kit push\` every time. Always run
1865
1825
  | \`pnpm start\` | FE + BE (parallel \`next start\`) |
1866
1826
  | \`pnpm start:rp\` | FE + BE + reverse proxy on :3030 |
1867
1827
  | \`pnpm start:proxy\` | Reverse proxy alone (already running FE/BE separately) |
1868
- | \`pnpm start:cron\` | Self-hosted cron fallback — only if not using Vercel Cron / k8s |
1869
1828
 
1870
1829
  ### PM2 (recommended for VPS)
1871
1830
 
1872
1831
  The installer scaffolds \`ecosystem.config.cjs\`. To supervise everything:
1873
1832
 
1874
1833
  \`\`\`bash
1875
- pm2 start ecosystem.config.cjs # FE + BE + proxy + cron (all four)
1834
+ pm2 start ecosystem.config.cjs # FE + BE + proxy (all three)
1876
1835
  pm2 start ecosystem.config.cjs --only proxy # only the reverse proxy
1877
1836
  pm2 save && pm2 startup # persist across reboots
1878
1837
  pm2 logs \${PM2_NAMESPACE:-${dirName}} # tail just this project's logs
@@ -1880,13 +1839,14 @@ pm2 reload \${PM2_NAMESPACE:-${dirName}} # zero-downtime restart (nam
1880
1839
  pm2 stop \${PM2_NAMESPACE:-${dirName}} # stop only this project
1881
1840
  \`\`\`
1882
1841
 
1883
- All four processes are grouped under the \`PM2_NAMESPACE\` set in \`.env.local\`
1842
+ All three processes are grouped under the \`PM2_NAMESPACE\` set in \`.env.local\`
1884
1843
  (defaults to \`${dirName}\`), so namespace commands target only this project
1885
1844
  even when other PM2 apps share the host. Process names embed the bound port
1886
1845
  (\`frontend:3001\`, \`backend:3002\`, \`proxy:3030\`) for quick \`pm2 ls\` triage.
1887
1846
 
1888
- The proxy and cron processes can be omitted with \`--only\` if you front the
1889
- apps with nginx/Caddy or use platform cron (system cron, k8s CronJob).
1847
+ The proxy process can be omitted with \`--only\` if you front the apps with
1848
+ nginx/Caddy. Scheduled jobs need no extra process the backend drives its
1849
+ scheduler queue in-process.
1890
1850
 
1891
1851
  ### Docker / k8s
1892
1852
 
@@ -1894,74 +1854,7 @@ For containerized deploys:
1894
1854
  - Bake the build into the image (\`pnpm install && pnpm build\`)
1895
1855
  - Set entrypoint to \`pnpm start\` or \`pnpm start:rp\`
1896
1856
  - Run \`pnpm backend:upgrade\` as a separate init container / Job before app pods start
1897
- - Use platform-native cron (k8s CronJob hitting \`/api/cron\` with \`CRON_SECRET\`) instead of \`pnpm start:cron\`
1898
-
1899
- ## Deploy on Vercel
1900
-
1901
- Two Vercel projects, one repo. Each project picks up its own Root Directory.
1902
-
1903
- ### 1) Backend project
1904
-
1905
- - **Import** this repo into Vercel as a new project.
1906
- - **Root Directory**: \`apps/backend\`
1907
- - **Build Command**: \`cd ../.. && pnpm install --frozen-lockfile && pnpm cms-plugins:build && cp -r ../cms-plugins/* apps/backend/plugins/ 2>/dev/null || true && pnpm --filter ./apps/backend build\`
1908
- - **Install Command**: leave empty (handled in build)
1909
- - **Settings → Git → Include all submodules: ON** (Vercel checks out an empty \`apps/backend\` otherwise)
1910
- - **Environment variables**:
1911
- \`\`\`
1912
- DATABASE_URL=postgresql://…
1913
- APOLLO_SECRET=<openssl rand -hex 32>
1914
- NEXT_PUBLIC_SITE_URL=https://yourdomain.com # the PUBLIC origin
1915
- NEXT_PUBLIC_DEFAULT_LOCALE=en
1916
- ${singleOrigin ? `APOLLO_ASSET_PREFIX=${adminPrefix}` : "# APOLLO_ASSET_PREFIX=/admin # only when single-origin"}
1917
- CRON_SECRET=<random> # protects /api/cron
1918
- APOLLO_EXTRA_PLUGINS_DIR=./plugins # picks up copied cms-plugins (see Build Command)
1919
- # Storage on Vercel cannot use local FS — pick one:
1920
- # Vercel Blob: BLOB_READ_WRITE_TOKEN=…
1921
- # S3 / R2 / Spaces: S3_ACCESS_KEY_ID, S3_SECRET_ACCESS_KEY, S3_BUCKET, S3_REGION, S3_ENDPOINT
1922
- APOLLO_DISABLE_LOCAL_STORAGE=1
1923
- \`\`\`
1924
- - **Cron**: \`apps/backend/vercel.json\` declares \`/api/cron\` on a 5-minute schedule (from apollo-cms upstream).
1925
- - **About the \`cp\` step**: Turbopack rejects \`outputFileTracingIncludes\` globs that walk above the project root, so the Build Command copies built \`apps/cms-plugins/*/dist\` into \`apps/backend/plugins/\` before \`next build\`. NFT then traces them normally as if they were built-in plugins. Locally this isn't needed because \`APOLLO_EXTRA_PLUGINS_DIR=../cms-plugins\` reads them directly.
1926
-
1927
- ### 2) Frontend project
1928
-
1929
- - **Import the same repo** as a separate Vercel project.
1930
- - **Root Directory**: \`apps/frontend\`
1931
- - **Build Command**: \`cd ../.. && pnpm install --frozen-lockfile && pnpm --filter ./apps/frontend build\`
1932
- - **Install Command**: leave empty
1933
- - **Settings → Git → Include all submodules: ON**
1934
- - **Environment variables**:
1935
- \`\`\`
1936
- NEXT_PUBLIC_SITE_URL=https://yourdomain.com
1937
- ${singleOrigin
1938
- ? ` BACKEND_INTERNAL_URL=https://<your-backend>.vercel.app`
1939
- : ` NEXT_PUBLIC_BACKEND_URL=https://<your-backend>.vercel.app`
1940
- }
1941
- \`\`\`
1942
-
1943
- ### 3) Custom domain
1944
-
1945
- Attach \`yourdomain.com\` to the **frontend** project${singleOrigin ? " (in single-origin mode it's the public entry point)" : ""}. The backend stays on its \`*.vercel.app\` URL${singleOrigin ? " — that's what the rewrite proxies to" : ""}.
1946
-
1947
- ### 4) Skip duplicate builds (optional)
1948
-
1949
- Each push triggers both projects to rebuild. Add an **Ignored Build Step** in
1950
- each project's Settings → Git:
1951
-
1952
- - **Backend**: \`git diff HEAD^ HEAD --quiet -- apps/backend\` (exits 0 → skip build)
1953
- - **Frontend**: \`git diff HEAD^ HEAD --quiet -- apps/frontend\`
1954
-
1955
- ### Gotchas
1956
-
1957
- - **Submodule must be initialized** on Vercel — the "Include all submodules"
1958
- toggle is the most common reason builds fail with a missing \`apps/backend\`.
1959
- - **OAuth callbacks** for email providers must use the public domain:
1960
- \`https://yourdomain.com/api/email/oauth/callback\`.${singleOrigin ? " The frontend rewrite forwards it to the backend." : ""}
1961
- - **Cron** runs on the backend project only. Vercel sends \`Authorization:
1962
- Bearer $CRON_SECRET\` automatically when \`CRON_SECRET\` is set.${singleOrigin ? `
1963
- - **Better Auth** uses \`trustedProxyHeaders: true\` so the rewrite proxy's
1964
- \`x-forwarded-host\` lands cookies at the public origin without extra config.` : ""}
1857
+ - No cron sidecar needed the backend drives its scheduler queue in-process
1965
1858
  `;
1966
1859
  writeFileSync(resolve(targetDir, "README.md"), readme);
1967
1860
  }
@@ -1993,8 +1886,8 @@ async function main() {
1993
1886
  const adminPrefix =normalizeAdminPrefix(flags.adminPrefix);
1994
1887
  const { dbUrl, siteUrl, locale } = await gatherEnv(flags);
1995
1888
  const authSecret = randomBytes(48).toString("base64");
1996
- // Required by apollo-cms's /api/cron route and scripts/dev-cron.ts in dev.
1997
- // Without it the dev cron loop hits 403 "CRON_SECRET not configured".
1889
+ // Authenticates trusted callers of apollo-cms's /api/health?check=ready.
1890
+ // Without it that readiness check answers 403 "CRON_SECRET not configured".
1998
1891
  const cronSecret = randomBytes(24).toString("hex");
1999
1892
  const backendInternalUrl = `http://localhost:${DEFAULT_BACKEND_PORT}`;
2000
1893
  success(`Frontend pkg name: ${frontendName}`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-apollo-monorepo",
3
- "version": "0.9.786",
3
+ "version": "0.9.787",
4
4
  "description": "Scaffold a monorepo with a frontend app and Apollo CMS as a git submodule backend (single-origin via Next.js rewrites + assetPrefix)",
5
5
  "bin": {
6
6
  "create-apollo-monorepo": "index.mjs"