@zaaxch/tailframe 4.0.6 → 4.0.7

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 (2) hide show
  1. package/package.json +1 -1
  2. package/src/new.mjs +49 -5
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zaaxch/tailframe",
3
- "version": "4.0.6",
3
+ "version": "4.0.7",
4
4
  "description": "Tailframe architecture toolkit: validates the Tailframe structure, import-boundary, and file-convention contracts. The package version is the contract version.",
5
5
  "type": "module",
6
6
  "bin": {
package/src/new.mjs CHANGED
@@ -269,6 +269,10 @@ add(`${svc}/.env.example`, `NODE_ENV=development\nPORT=3000\nCORS_ORIGIN=https:/
269
269
  add(`${svc}/.env.infrastructure.example`, `ECR_IMAGE=<account>.dkr.ecr.<region>.amazonaws.com/${options.name}
270
270
  IMAGE_TAG=<product-sha>
271
271
  APP_ENV_FILE=/opt/${options.name}/shared/.env.production
272
+ CADDY_ORIGIN_CERTIFICATE=/opt/${options.name}/shared/caddy/origin.pem
273
+ CADDY_ORIGIN_KEY=/opt/${options.name}/shared/caddy/origin-key.pem
274
+ CADDY_DATA_DIR=/opt/${options.name}/shared/caddy/data
275
+ CADDY_CONFIG_DIR=/opt/${options.name}/shared/caddy/config
272
276
  ${postgres ? `POSTGRES_DATA_DIR=/opt/${options.name}/shared/postgres/data
273
277
  POSTGRES_ROOT_PASSWORD=<uri-safe-random-value>
274
278
  POSTGRES_APP_PASSWORD=<different-uri-safe-random-value>
@@ -1190,6 +1194,9 @@ configured. No push or merge deploys production automatically.
1190
1194
  Configure the ECR repository with immutable image tags. The release-only role may publish; the distinct deployment
1191
1195
  role is pull-only. Record the full commit SHA and ECR digest; deployment and product migrations use that release image.
1192
1196
 
1197
+ Production ingress is a required Caddy reverse proxy in every generated service deployment. The application container remains
1198
+ internal; Caddy is the only edge surface and must own 80/443 exposure.
1199
+
1193
1200
  The host separates replaceable artifacts from persistent state:
1194
1201
 
1195
1202
  \`\`\`text
@@ -1201,6 +1208,12 @@ The host separates replaceable artifacts from persistent state:
1201
1208
  └── shared/
1202
1209
  ├── .env.production
1203
1210
  ├── .env.infrastructure
1211
+ ├── caddy/
1212
+ │ ├── certs/
1213
+ │ │ ├── origin.pem
1214
+ │ │ └── origin-key.pem
1215
+ │ ├── config/
1216
+ │ └── data/
1204
1217
  ${options.auth === "firebase" ? ` ├── secrets/firebase-service-account.json
1205
1218
  ` : ""}${postgres ? ` ├── postgres/data/
1206
1219
  ` : ` ├── mongo/config/keyfile
@@ -1215,6 +1228,8 @@ Actions may replace \`current/\` and must never replace \`shared/\`. The server
1215
1228
  - \`.env.production\` contains Node application behavior and provider credentials.
1216
1229
  - \`.env.infrastructure\` contains Compose paths, image identity, and infrastructure passwords. Start from
1217
1230
  \`.env.infrastructure.example\` and replace every placeholder.
1231
+ - \`.env.infrastructure\` is also the host-owned control plane for Caddy certificate paths and runtime directories; keep TLS
1232
+ key material under shared storage and rotate it independently from application images.
1218
1233
  - Compose \`environment:\` owns fixed production wiring: \`NODE_ENV\`, internal database/cache URLs, and mounted
1219
1234
  credential paths.
1220
1235
  ${options.ui && options.auth === "firebase" ? `- The UI application's build-time \`.env.production\` comes from the GitHub \`UI_ENV_PRODUCTION\` secret and is unrelated to the service runtime file above.
@@ -1225,9 +1240,11 @@ Do not inject \`.env.infrastructure\` into Node. Make both host environment file
1225
1240
 
1226
1241
  1. Install Docker Engine and Docker Compose.
1227
1242
  ${postgres
1228
- ? `2. Create \`/opt/${options.name}/current/deploy/postgres\` and \`/opt/${options.name}/shared/postgres/data\`${options.redis ? `, plus \`/opt/${options.name}/shared/redis/data\`` : ""}.`
1243
+ ? `2. Create \`/opt/${options.name}/current/deploy/postgres\`, \`/opt/${options.name}/shared/postgres/data\`,
1244
+ \`/opt/${options.name}/shared/caddy/certs\`, \`/opt/${options.name}/shared/caddy/data\`, \`/opt/${options.name}/shared/caddy/config\`${options.redis ? `, plus \`/opt/${options.name}/shared/redis/data\`` : ""}.`
1229
1245
  : `2. Create \`/opt/${options.name}/current/deploy/mongo\`, \`/opt/${options.name}/shared/mongo/config\`, and
1230
- \`/opt/${options.name}/shared/mongo/data\`${options.redis ? `, plus \`/opt/${options.name}/shared/redis/data\`` : ""}.`}
1246
+ \`/opt/${options.name}/shared/mongo/data\`, \`/opt/${options.name}/shared/caddy/certs\`,
1247
+ \`/opt/${options.name}/shared/caddy/data\`, \`/opt/${options.name}/shared/caddy/config\`${options.redis ? `, plus \`/opt/${options.name}/shared/redis/data\`` : ""}.`}
1231
1248
  3. Install \`.env.production\` and a completed \`.env.infrastructure\` under \`shared/\`.
1232
1249
  ${postgres ? "" : `4. Generate the MongoDB replica key with \`openssl rand -base64 756\`, make it owned by UID/GID \`999:999\`, and
1233
1250
  mode \`0400\`.
@@ -1331,6 +1348,34 @@ const developmentEnvironment = [
1331
1348
  ];
1332
1349
  const developmentEnvironmentBlock = `\n environment:\n${developmentEnvironment.join("\n")}`;
1333
1350
  const volumeBlock = serviceVolumes.length ? `\n volumes:\n${serviceVolumes.join("\n")}` : "";
1351
+ const caddyService = `
1352
+ caddy:
1353
+ image: caddy:2-alpine
1354
+ ports:
1355
+ - "80:80"
1356
+ - "443:443"
1357
+ volumes:
1358
+ - ./Caddyfile:/etc/caddy/Caddyfile:ro
1359
+ - \${CADDY_ORIGIN_CERTIFICATE:?Set CADDY_ORIGIN_CERTIFICATE}:/etc/caddy/certs/origin.pem:ro
1360
+ - \${CADDY_ORIGIN_KEY:?Set CADDY_ORIGIN_KEY}:/etc/caddy/certs/origin-key.pem:ro
1361
+ - \${CADDY_DATA_DIR:?Set CADDY_DATA_DIR}:/data
1362
+ - \${CADDY_CONFIG_DIR:?Set CADDY_CONFIG_DIR}:/config
1363
+ depends_on:
1364
+ ${options.name}:
1365
+ condition: service_healthy
1366
+ networks:
1367
+ - backend
1368
+ restart: unless-stopped`;
1369
+ add(`${svc}/Caddyfile`, `{
1370
+ auto_https off
1371
+ }
1372
+ :80 {
1373
+ redir https://{host}{uri} 308
1374
+ }
1375
+ :443 {
1376
+ tls /etc/caddy/certs/origin.pem /etc/caddy/certs/origin-key.pem
1377
+ reverse_proxy ${options.name}:3000
1378
+ }`);
1334
1379
  const workerService = options.worker ? `\n worker:
1335
1380
  image: \${ECR_IMAGE:?Set ECR_IMAGE}:\${IMAGE_TAG:?Set IMAGE_TAG}
1336
1381
  env_file:
@@ -1473,8 +1518,7 @@ services:
1473
1518
  image: \${ECR_IMAGE:?Set ECR_IMAGE}:\${IMAGE_TAG:?Set IMAGE_TAG}
1474
1519
  env_file:
1475
1520
  - \${APP_ENV_FILE:-.env.production}
1476
- ports:
1477
- - "3000:3000"${productionEnvironmentBlock}${volumeBlock}${dependsBlock}
1521
+ ${productionEnvironmentBlock}${volumeBlock}${dependsBlock}
1478
1522
  healthcheck:
1479
1523
  test:
1480
1524
  - CMD-SHELL
@@ -1490,7 +1534,7 @@ services:
1490
1534
  stop_grace_period: 2m
1491
1535
  networks:
1492
1536
  - backend
1493
- restart: unless-stopped${workerService}${schemaInitService}${databaseService}${redisService}
1537
+ restart: unless-stopped${workerService}${schemaInitService}${databaseService}${redisService}${caddyService}
1494
1538
  networks:
1495
1539
  backend:
1496
1540
  driver: bridge