@auth-craft/aws-cf-stack 1.7.1 → 1.9.0

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.
package/.env.example CHANGED
@@ -11,12 +11,20 @@
11
11
  # Required vs optional is marked per line.
12
12
 
13
13
  # ─── Stage / project / naming ────────────────────────────────────────────────
14
+ # Resources are named {app}-{env}-{layer}-{component}, e.g. snapshot-commerce-prod-auth-data.
15
+ # app = AUTH_CRAFT_APP_NAME, else auth-craft[-<project>]
16
+ # env = STAGE
17
+ # layer = LAYER (default "auth")
18
+ # component = per-resource: data (table), api (Lambda), system/tenant/customer (workers)
19
+ # The {app}-{env}-{layer} base (no component) is also AUTH_SYSTEM_NAME / the JWT issuer.
14
20
  STAGE=dev # optional (flag --stage), default dev | staging | prod
15
21
  # also accepts production -> prod, development -> dev
16
- PROJECT=default # optional (flag --project), default "default" (multi-tenant naming)
17
- AUTH_CRAFT_APP_NAME= # optional (flag --app-name) — override the app/resource name
18
- # (e.g. snapshot-auth). Unset = auth-craft[-<project>]. Drives
19
- # stack names, table, Lambda fn, worker names.
22
+ PROJECT=default # optional (flag --project), default "default". app = auth-craft-<project>
23
+ AUTH_CRAFT_APP_NAME= # optional (flag --app-name) — full rebrand of the app name
24
+ # (e.g. snapshot-commerce, drops the auth-craft prefix).
25
+ # Unset = auth-craft[-<project>].
26
+ LAYER=auth # optional (flag --layer), default "auth" — layer namespace within
27
+ # the app; use a larger app's other layers (e.g. billing) per deploy.
20
28
 
21
29
  # ─── Tool command overrides (optional — pin your own binaries) ───────────────
22
30
  AUTH_CRAFT_WRANGLER_CMD= # optional — e.g. "pnpm wrangler"; default "npx --yes wrangler"
@@ -147,6 +155,18 @@ LAMBDA_REFRESH_COOKIE_TENANT=refresh_token_tenant
147
155
  LAMBDA_REFRESH_COOKIE_SYSTEM=refresh_token_system
148
156
  LAMBDA_AUDIT_ENABLED=false
149
157
  LAMBDA_DEVICE_TRACKING=true
158
+
159
+ # ─── Observability cost controls (optional) ──────────────────────────────────
160
+ # CloudWatch Logs are billed for ingestion AND stored volume; retention only affects
161
+ # storage. Short retention in dev is the cheap default.
162
+ # Unset → 3 days in dev, 30 days in staging/prod.
163
+ # Valid → 1,3,5,7,14,30,60,90,120,150,180,365,400,545,731,1096,1827,2192,2557,
164
+ # 2922,3288,3653 (CloudWatch's fixed set — anything else fails at synth),
165
+ # or 'infinite' to never expire.
166
+ LAMBDA_LOG_RETENTION_DAYS=
167
+ # X-Ray tracing is billed per recorded trace. Unset → disabled in dev, active otherwise.
168
+ # active | disabled | pass_through
169
+ LAMBDA_TRACING=
150
170
  LAMBDA_APP_URL=
151
171
  LAMBDA_SUPPORT_EMAIL=
152
172
  LAMBDA_CORS_ORIGINS=
package/README.md CHANGED
@@ -28,17 +28,30 @@ process env.
28
28
 
29
29
  ### Naming convention
30
30
 
31
- Everything is named from `--stage` (`dev|staging|prod`) and `--project` (default
32
- `default`). With the default project, `app = auth-craft`; otherwise `app = auth-craft-<project>`.
31
+ Pattern: **`{app}-{env}-{layer}-{component}`**.
32
+
33
+ - **`app`** — `auth-craft` by default; `auth-craft-<project>` with `--project`; or a full
34
+ rebrand with `--app-name` / `AUTH_CRAFT_APP_NAME` (e.g. `snapshot-commerce`).
35
+ - **`env`** — `--stage` (`dev|staging|prod`).
36
+ - **`layer`** — `--layer` / `LAYER`, default `auth`. Namespaces this deploy within a larger
37
+ app that has other layers (e.g. `--layer billing`), so the CLI is reused per layer.
38
+ - **`component`** — per-resource: `data` (table), `api` (Lambda), `system`/`tenant`/`customer`
39
+ (gateway workers).
33
40
 
34
41
  | Resource | Name |
35
42
  |----------|------|
36
- | CDK stacks | `<app>-<stage>-data`, `<app>-<stage>-api` |
37
- | Lambda fn + DynamoDB table | `<app>-<stage>` |
38
- | Gateway workers (`multi`) | `<app>-<stage>-system` / `-tenant` / `-customer` |
39
- | Gateway worker (`shared`) | `<app>-<stage>` |
40
-
41
- So `outputs`/`gateway` look up the api stack `<app>-<stage>-api`. The CDK output keys are
43
+ | CDK stacks | `<app>-<env>-<layer>-data`, `<app>-<env>-<layer>-api` |
44
+ | DynamoDB table | `<app>-<env>-<layer>-data` |
45
+ | Lambda fn (+ log group) | `<app>-<env>-<layer>-api` |
46
+ | Gateway workers (`multi`) | `<app>-<env>-<layer>-system` / `-tenant` / `-customer` |
47
+ | Gateway worker (`shared`) | `<app>-<env>-<layer>` |
48
+ | `AUTH_SYSTEM_NAME` / JWT issuer | `<app>-<env>-<layer>` (no component — keeps the `iss` claim stable) |
49
+
50
+ Example (`--app-name snapshot-commerce --stage prod`, default layer):
51
+ `snapshot-commerce-prod-auth-data` (table), `snapshot-commerce-prod-auth-api` (Lambda),
52
+ `snapshot-commerce-prod-auth-system` (worker), issuer `snapshot-commerce-prod-auth`.
53
+
54
+ So `outputs`/`gateway` look up the api stack `<app>-<env>-<layer>-api`. The CDK output keys are
42
55
  `LambdaFunctionUrl`, `ApiBasePath`, `AuthSystemName`, `DynamoDBTableName`.
43
56
 
44
57
  ### Deploy model (multi vs shared)
@@ -150,6 +163,43 @@ CF_EDGE_GATE_SECRET="$SNAP_EDGE" CLOUDFLARE_ACCOUNT_ID="$SNAP_CF_ACCT" \
150
163
  npx auth-craft-stack all --stage "$STAGE"
151
164
  ```
152
165
 
166
+ ## Observability cost controls (log retention, tracing)
167
+
168
+ CloudWatch Logs and X-Ray are usually the two line items that make a low-traffic **dev**
169
+ stage cost more than the Lambda itself. Both are configurable, with stage-aware defaults
170
+ that keep dev cheap without touching staging/prod behaviour:
171
+
172
+ | Setting | Env var / flag | Default (dev) | Default (staging/prod) |
173
+ |---------|----------------|---------------|------------------------|
174
+ | Log retention | `LAMBDA_LOG_RETENTION_DAYS` / `--log-retention-days` | `3` days | `30` days |
175
+ | X-Ray tracing | `LAMBDA_TRACING` / `--tracing` | `disabled` | `active` |
176
+
177
+ ```bash
178
+ # Cheapest dev: keep 1 day of logs, no tracing (tracing is already off by default in dev)
179
+ npx auth-craft-stack lambda --stage dev --log-retention-days 1
180
+
181
+ # Turn tracing back on in dev while debugging
182
+ npx auth-craft-stack lambda --stage dev --tracing active
183
+
184
+ # Long retention for an audited prod
185
+ npx auth-craft-stack lambda --stage prod --log-retention-days 365
186
+ ```
187
+
188
+ Notes:
189
+ - Retention accepts only **CloudWatch's fixed set** — `1, 3, 5, 7, 14, 30, 60, 90, 120, 150,
190
+ 180, 365, 400, 545, 731, 1096, 1827, 2192, 2557, 2922, 3288, 3653` — or `infinite` to never
191
+ expire. Any other value fails at **synth** time with the valid list, so a typo can't
192
+ silently deploy the wrong retention.
193
+ - Retention caps **storage** cost only; you are still billed for log **ingestion**. To cut
194
+ ingestion, reduce what the app logs.
195
+ - Changing retention applies to the existing log group too (it's the same CloudFormation
196
+ resource), so old logs beyond the new window age out — it is not just for new logs.
197
+ - In `prod` the log group has `RemovalPolicy.RETAIN`, so destroying the stack keeps the logs
198
+ (and the group must be deleted manually before a same-name redeploy). In dev/staging it is
199
+ destroyed with the stack.
200
+ - `LogRetentionDays` and `TracingMode` are emitted as CDK outputs, so
201
+ `npx auth-craft-stack outputs` shows what is actually deployed.
202
+
153
203
  ## CORS (per scope + dynamic allowlist)
154
204
 
155
205
  CORS is resolved **per scope** (system / tenant / customer) — the 3 workers no longer
@@ -214,8 +264,8 @@ worker names + a ready-to-paste snippet are in `auth-craft-stack outputs`:
214
264
  ```jsonc
215
265
  // auth-craft-stack outputs →
216
266
  {
217
- "workerNames": { "system": "auth-craft-prod-system", "tenant": "...", "customer": "auth-craft-prod-customer" },
218
- "pagesProxy": { "serviceBindingExample": "[[services]]\nbinding = \"AUTH_GATEWAY\"\nservice = \"auth-craft-prod-customer\"\n" }
267
+ "workerNames": { "system": "auth-craft-prod-auth-system", "tenant": "...", "customer": "auth-craft-prod-auth-customer" },
268
+ "pagesProxy": { "serviceBindingExample": "[[services]]\nbinding = \"AUTH_GATEWAY\"\nservice = \"auth-craft-prod-auth-customer\"\n" }
219
269
  }
220
270
  ```
221
271
 
@@ -225,7 +275,7 @@ In the Pages app:
225
275
  # wrangler.toml (your Pages project) — bind the gateway worker for the scope this app serves
226
276
  [[services]]
227
277
  binding = "AUTH_GATEWAY"
228
- service = "auth-craft-prod-customer" # from outputs.workerNames.<scope>
278
+ service = "auth-craft-prod-auth-customer" # from outputs.workerNames.<scope>
229
279
  ```
230
280
 
231
281
  ```ts