{
  "asOf": "2026-10-28",
  "currency": "USD",
  "periodDays": 30,
  "classification": "Published vendor rates with illustrative, unmeasured steady-state workloads. Not an invoice or capacity result.",
  "scope": "Identity-only comparison plus an explicit Workers/D1 CRUD app comparison. The CRUD app is identical in both alternatives; app and Nathan meters share one Cloudflare account and one set of inclusions. Optional gateway requests in the identity-only model are separate from the CRUD model's already-counted API requests.",
  "prices": {
    "workers": {"base": 5, "includedRequests": 10000000, "requestPerMillion": 0.30, "includedCpuMs": 30000000, "cpuMsPerMillion": 0.02, "source": "workers-pricing"},
    "d1": {"includedReadRows": 25000000000, "readPerMillion": 0.001, "includedWrittenRows": 50000000, "writePerMillion": 1, "includedGb": 5, "gbMonth": 0.75, "maximumGbPerDatabase": 10, "source": "d1-pricing", "limitSource": "d1-limits"},
    "logsCurrent": {"includedEvents": 20000000, "eventsPerMillion": 0.60, "retentionDays": 7, "source": "workers-pricing", "validThrough": "2026-11-30"},
    "logsDecember": {"includedIngestedGb": 50, "ingestionPerGb": 0.25, "includedStoredGbMonth": 10, "storagePerGbMonth": 0.10, "retentionDays": 7, "source": "observability-pricing", "effectiveFrom": "2026-12-01"},
    "clerk": {"monthlyBase": 25, "annualBasePerMonth": 20, "includedMruPerApp": 50000, "mruTiers": [{"through": 100000, "rate": 0.02}, {"through": 1000000, "rate": 0.018}, {"through": 10000000, "rate": 0.015}, {"through": null, "rate": 0.012}], "source": "clerk-pricing"},
    "resend": {"selectedPlan": "Pro 50k, deliberately conservative; volume-plan optimization not assumed", "base": 20, "includedEmails": 50000, "overagePer1000Bucket": 0.90, "freeMonthly": 3000, "freeDaily": 100, "source": "resend-pricing"},
    "r2": {"includedGb": 10, "gbMonth": 0.015, "source": "r2-pricing"}
  },
  "assumptions": {
    "registeredUsers": 1000000,
    "retainedFraction": 1,
    "signinsPerRetainedUser": 4,
    "requestsPerSignin": 10,
    "cpuMsPerSignin": 100,
    "readRowsPerSignin": 80,
    "writtenRowsPerSignin": 30,
    "refreshesPerRetainedUser": 20,
    "requestsPerRefresh": 1,
    "cpuMsPerRefresh": 5,
    "readRowsPerRefresh": 20,
    "writtenRowsPerRefresh": 10,
    "d1BytesPerRegisteredUser": 12000,
    "emailsPerRetainedUser": 0.2,
    "protectedRequestsPerRetainedUser": 0,
    "cpuMsPerProtectedRequest": 2,
    "readRowsPerProtectedRequest": 10,
    "writtenRowsPerProtectedRequest": 0,
    "authLogFraction": 1,
    "protectedLogFraction": 1,
    "eventsPerAuthRequest": 1,
    "eventsPerProtectedRequest": 2,
    "bytesPerLogEvent": 1000,
    "writeMultiplier": 1,
    "incrementalOperatorHours": 0,
    "operatorHourlyRate": 100,
    "otherMonthlyCosts": 0
  },
  "assumptionNotes": {
    "billingPopulation": "Charts set retained users equal to registered users. Fractional-retention scenarios keep the registered population/storage fixed. MRU means a user who returns at least 24 hours after signup; it is not an account count or conventional MAU.",
    "cpu": "CPU is total active CPU across the workflow and same-account service calls, excluding provider/network wait. No Nathan measurement backs these input values.",
    "database": "Rows are billed rows after table/index writes, updates, deletes, cleanup and rate-limiter effects, not SQL-statement counts. Aggregate budgets are assumptions and must be replaced by D1 rows_read/rows_written metrics.",
    "storage": "12 decimal kB per registered user includes modeled user/account/factor/group/session/index overhead and bounded retention. It is not measured schema size. Multiple databases/architecture changes are needed if a database would exceed 10 GB. Allowances are shared across the account.",
    "logs": "One invocation/event per auth request and two Nathan events per protected request are assumptions, not a measured event count. Current configs enable observability with no sampling setting; default head sampling is 100%. Additional console events/traces raise usage. Security audit records must remain complete when diagnostic logs are sampled.",
    "email": "0.2 emails per retained user is a lifecycle-mail example for social/passkey/password/TOTP use, not email OTP for each login. Use 4 emails per user for four email-OTP logins. Paid Resend is selected whenever modeled mail is nonzero to avoid assuming the 100/day free cap accommodates bursts.",
    "steadyState": "No new-user acquisition/import burst, SMS, directory sync, extra upstream-IdP fees, WAF premium, independent backup, external SIEM, taxes, support contract or one-time development cost is included in the base. These are separate variables, not claimed to be zero in a real deployment.",
    "refresh": "20 refreshes/user/month is moderate-session behavior. Five-minute tokens for one hour/day over 20 days imply 240 refreshes; eight hours/day imply 1920. Changing lifetimes to save money requires an explicit security decision.",
    "gateway": "Optional full request-path cost. Default 0 reflects OIDC external apps calling Nathan for identity, not every app request. Service bindings add CPU/log/database work but no additional Standard request fee. Upstream application CPU/hosting remains excluded.",
    "labor": "Use incremental Nathan operation/security time relative to Clerk integration/operation time. Both products require app integration; initial implementation/migration/independent review are separate amortized costs."
  },
  "crud": {
    "classification": "Illustrative read-heavy task/notes app, not a measured typical-workload benchmark. Registered, app-active and Clerk-retained populations are equal only in the main table.",
    "assumptions": {
      "activeFraction": 1,
      "requestsPerActiveUser": 1000,
      "readFraction": 0.9,
      "cpuMsPerRead": 3,
      "cpuMsPerMutation": 5,
      "readRowsPerRead": 20,
      "readRowsPerMutation": 2,
      "writtenRowsPerMutation": 3,
      "bytesPerRegisteredUser": 100000,
      "staticRequestsPerActiveUser": 2000,
      "logFraction": 0.01,
      "eventsPerRequest": 1,
      "bytesPerLogEvent": 1000,
      "policyChecksPerApiRequest": 1,
      "cpuMsPerPolicyCheck": 2,
      "readRowsPerPolicyCheck": 10,
      "writtenRowsPerPolicyCheck": 0,
      "eventsPerPolicyCheck": 1,
      "policyLogFraction": 0.01,
      "commonMonthlyCosts": 0
    },
    "notes": {
      "traffic": "1000 API requests = 50/day on 20 active days. 90% indexed reads/lists, 10% create/update/delete mutations. No claim that all CRUD apps behave this way; lighter and busier profiles are provided.",
      "cpu": "3 CPU-ms/read and 5/mutation are whole app-handler budgets including local token verification on both sides. Nathan additionally budgets 2 CPU-ms and 10 read rows for one live app-policy service-binding check per API request. These are not measured latencies or promises of correct revocation.",
      "rows": "Each indexed read scans 20 rows, including list results; each mutation reads 2 ownership/record rows and bills 3 writes including table/index effects. Cleanup and retention must fit this budget or be added. Reads and mutations are business requests, not extra public requests for each SQL call.",
      "storage": "100 decimal kB per registered account = an illustrative 50 bounded records at 1 kB plus 2x total table/index/metadata overhead. This is an at-rest footprint, not 100 kB of new growth per month. App and identity data need separately viable D1 layouts beyond 10 GB per database.",
      "static": "2000 public SPA-shell/JS/CSS/image requests per active user use direct Workers Static Assets serving with no Worker invocation or Workers Caching enabled. Private API data still goes through the protected Worker. Static requests are shown but not added to dynamic invocation fees.",
      "logs": "One diagnostic event/API request and one per Nathan service-bound policy check, each sampled at 1%, with 1 kB/event. Auth requests retain the original 100% logging budget. Required security audits are not dropped; additional business audit storage must be budgeted separately.",
      "allocation": "App-only Cloudflare bill is the common baseline. Nathan auth increment = combined app+identity+policy Cloudflare bill minus app-only bill plus auth email. Clerk auth = Pro fee. Account base/inclusions apply once; app-first allocation is a convention, not a separate Nathan invoice.",
      "parity": "Both options validate tokens locally inside the app CPU budget. Nathan's additional live policy check is a conservative projection for protected Worker authorization. Clerk's local-token path does not by itself prove equivalent 60-second deprovisioning/group enforcement. Additional equivalent policy controls are unpriced.",
      "scope": "No uploads/object storage, background jobs, real-time features, app notification mail, external monitoring/support, domain purchase, independent backups, taxes or development/operator time in baseline recurring cash totals. Manual common costs can be added equally to both. Identity-only gateway traffic overrides are excluded to avoid counting the same CRUD requests twice."
    },
    "scales": [50000, 51000, 100000, 250000, 1000000, 2000000, 5000000],
    "scenarios": [
      {"id": "light", "label": "Light CRUD: 100 API requests/user/month", "overrides": {"requestsPerActiveUser": 100}},
      {"id": "baseline", "label": "Read-heavy CRUD: 1000 API requests/user/month", "overrides": {}},
      {"id": "busy", "label": "Busy CRUD: 10000 API requests/user/month", "overrides": {"requestsPerActiveUser": 10000}},
      {"id": "write-heavy", "label": "Write-heavy: 50% mutations, 5 billed writes/mutation", "overrides": {"readFraction": 0.5, "writtenRowsPerMutation": 5}},
      {"id": "full-logs", "label": "Read-heavy CRUD with 100% app/policy diagnostic logs", "overrides": {"logFraction": 1, "policyLogFraction": 1}}
    ]
  },
  "scales": [1000, 10000, 50000, 51000, 100000, 250000, 1000000, 2000000, 5000000],
  "sensitivityScales": [51000, 100000, 1000000, 2000000],
  "scenarios": [
    {"id": "efficient", "label": "Fewer sign-ins and refreshes", "overrides": {"signinsPerRetainedUser": 2, "requestsPerSignin": 8, "cpuMsPerSignin": 75, "readRowsPerSignin": 40, "writtenRowsPerSignin": 20, "refreshesPerRetainedUser": 8, "cpuMsPerRefresh": 3, "readRowsPerRefresh": 10, "writtenRowsPerRefresh": 6, "emailsPerRetainedUser": 0.05}},
    {"id": "baseline", "label": "Moderate identity traffic", "overrides": {}},
    {"id": "refresh-240", "label": "Five-minute refresh, 1 hour/day, 20 days", "overrides": {"refreshesPerRetainedUser": 240}},
    {"id": "refresh-1920", "label": "Five-minute refresh, 8 hours/day, 20 days", "overrides": {"refreshesPerRetainedUser": 1920}},
    {"id": "busy", "label": "More sign-ins, writes, refreshes and mail", "overrides": {"signinsPerRetainedUser": 10, "requestsPerSignin": 12, "cpuMsPerSignin": 250, "readRowsPerSignin": 200, "writtenRowsPerSignin": 80, "refreshesPerRetainedUser": 100, "cpuMsPerRefresh": 10, "readRowsPerRefresh": 40, "writtenRowsPerRefresh": 20, "emailsPerRetainedUser": 1}},
    {"id": "gateway-full", "label": "Add 1,000 protected requests/user, current full diagnostic logs", "overrides": {"protectedRequestsPerRetainedUser": 1000}},
    {"id": "gateway-sampled", "label": "Same gateway traffic, 1% diagnostic logs; security audits retained", "overrides": {"protectedRequestsPerRetainedUser": 1000, "protectedLogFraction": 0.01}},
    {"id": "email-otp", "label": "Four auth emails/user/month", "overrides": {"emailsPerRetainedUser": 4}},
    {"id": "writes-3x", "label": "Three times the billed database writes", "overrides": {"writeMultiplier": 3}}
  ]
}
