{"id":"bumpgrade-product-access-source-data","updatedAt":"2026-05-24","status":"owner-product-delivery-gate-ready","issue":409,"parentIssue":16,"generatedFrom":"src/lib/product-access.ts","routes":["/products/source-data","/products/entitlements","/api/products/entitlements","/api/products/download-tokens","/api/products/downloads?token={token}","/api/products/protected-content","/products/test-checkout/:linkId","/api/products/test-checkout","/api/admin/products/assets","/api/admin/products/catalog","/api/admin/products/delivery-gates","/api/admin/products/offer-access-grants","/api/admin/products/test-checkout-links","/api/admin/products/revocation-intents","/products/indie-launch-library"],"stableIds":["productId","assetId","accessRuleId","entitlementTemplateId","customerProductEntitlementLookupId","productDownloadTokenId","productAssetUploadIntentId","productCreationIntentId","productDeliveryGateLinkId","productOfferAccessGrantIntentId","productTestCheckoutLinkId","productTestCheckoutPurchaseId","productEntitlementRevocationIntentId","productProtectedContentId","productPaymentPlanId","subscriptionPlanId","fulfillmentId","agentActionId"],"entitlementWrites":{"id":"product-entitlement-webhook-grant-contract","status":"sandbox-webhook-grants-ready","issue":101,"parentIssue":16,"sourceEvents":["checkout.session.completed"],"tables":["product_entitlements","product_fulfillment_tasks"],"sourceDataRoute":"/products/source-data","grantMappings":[{"id":"grant-map-sandbox-launch-pass-to-bundle","sourcePriceId":"price-bumpgrade-sandbox-launch-pass-usd","sourceCommerceProductId":"product-bumpgrade-sandbox-launch-pass","productId":"product-launch-bundle","productTitle":"Launch bundle","entitlementTemplateId":"entitlement-template-launch-bundle","entitlementTemplateTitle":"Launch bundle entitlement","accessRuleId":"access-rule-download-after-paid-webhook","fulfillmentKind":"bundle","grants":["Download access","Course enrollment","Membership access"],"grantSummary":"Grant the sandbox launch bundle entitlement after trusted paid checkout evidence."},{"id":"grant-map-launch-checklist-bump-to-download","sourcePriceId":"price-launch-checklist-bump-usd","sourceCommerceProductId":"product-launch-checklist-bump","productId":"product-launch-checklist-download","productTitle":"Launch checklist download","entitlementTemplateId":"entitlement-template-launch-download","entitlementTemplateTitle":"Launch download entitlement","accessRuleId":"access-rule-download-after-paid-webhook","fulfillmentKind":"digital_download","grants":["Download asset access","Receipt-visible fulfillment status"],"grantSummary":"Grant the launch checklist download entitlement after trusted paid checkout evidence."}],"publicSafeFields":["id","checkout_intent_id","product_id","entitlement_template_id","access_rule_id","status","grant_kind","source_price_id","granted_at"],"serverPrivateFields":["buyer_user_id","buyer_email_hash","source_stripe_event_id","metadata_json","private R2 object keys","signed URLs","raw Stripe customer/session/payment IDs"],"writeBoundary":"Issue #101 can grant idempotent sandbox entitlement rows from trusted paid checkout webhook evidence. Signed downloads, protected content, revocation, live fulfillment, customer portals, refunds, and direct agent writes remain locked behind future confirmed-write APIs."},"grantMappings":[{"id":"grant-map-sandbox-launch-pass-to-bundle","sourcePriceId":"price-bumpgrade-sandbox-launch-pass-usd","sourceCommerceProductId":"product-bumpgrade-sandbox-launch-pass","productId":"product-launch-bundle","productTitle":"Launch bundle","entitlementTemplateId":"entitlement-template-launch-bundle","entitlementTemplateTitle":"Launch bundle entitlement","accessRuleId":"access-rule-download-after-paid-webhook","fulfillmentKind":"bundle","grants":["Download access","Course enrollment","Membership access"],"grantSummary":"Grant the sandbox launch bundle entitlement after trusted paid checkout evidence."},{"id":"grant-map-launch-checklist-bump-to-download","sourcePriceId":"price-launch-checklist-bump-usd","sourceCommerceProductId":"product-launch-checklist-bump","productId":"product-launch-checklist-download","productTitle":"Launch checklist download","entitlementTemplateId":"entitlement-template-launch-download","entitlementTemplateTitle":"Launch download entitlement","accessRuleId":"access-rule-download-after-paid-webhook","fulfillmentKind":"digital_download","grants":["Download asset access","Receipt-visible fulfillment status"],"grantSummary":"Grant the launch checklist download entitlement after trusted paid checkout evidence."}],"subscriptionMembershipAccess":{"id":"subscription-membership-access-contract","status":"subscription-membership-entitlement-ready","issue":187,"parentIssue":16,"sourceEvents":["customer.subscription.created","customer.subscription.updated","customer.subscription.deleted"],"sourceDataRoute":"/products/source-data","customerLookupRoute":"/api/products/entitlements","sourcePriceId":"price-launch-membership-monthly-usd","sourceCommerceProductId":"product-bumpgrade-launch-membership","productId":"product-launch-membership","entitlementTemplateId":"entitlement-template-launch-membership","accessRuleId":"access-rule-membership-active-subscription","activeStatuses":["active","trialing"],"inactiveStatuses":["canceled","unpaid","incomplete_expired"],"redaction":{"buyerEmailIncluded":false,"buyerEmailHashIncluded":false,"rawStripeSubscriptionIdsIncluded":false,"rawStripeCustomerIdsIncluded":false,"sourceStripeEventIdsIncluded":false,"metadataJsonIncluded":false,"memberPostsIncluded":false,"rawR2KeysIncluded":false,"signedUrlsIncluded":false,"progressDataIncluded":false,"customerPortalUrlIncluded":false},"writeBoundary":"Issue #187 mirrors trusted Stripe Billing subscription state and updates a checkout-linked membership entitlement only when subscription state is active or trialing. It marks access inactive when subscription state is canceled, unpaid, incomplete_expired, or deleted. It does not create manual renewal loops, Customer Portal sessions, raw Stripe ID exposure, member posts, progress rows, private R2 keys, signed URLs, destructive revocation, or direct unauthenticated agent writes.","source":"d1","loadError":null,"counts":{"billingSubscriptions":0,"activeOrTrialingBillingSubscriptions":0,"membershipEntitlements":0,"activeMembershipEntitlements":0,"inactiveMembershipEntitlements":0}},"subscriptionMembershipGrantMapping":{"id":"grant-map-launch-membership-subscription","sourcePriceId":"price-launch-membership-monthly-usd","sourceCommerceProductId":"product-bumpgrade-launch-membership","productId":"product-launch-membership","productTitle":"Launch membership","entitlementTemplateId":"entitlement-template-launch-membership","entitlementTemplateTitle":"Launch membership entitlement","accessRuleId":"access-rule-membership-active-subscription","fulfillmentKind":"membership","grants":["Member area access while subscription is active or trialing"],"grantSummary":"Grant launch membership access while trusted Stripe Billing subscription state is active or trialing."},"productPaymentPlans":{"id":"product-payment-plan-readiness","status":"product-payment-plan-readiness-ready","issue":16,"parentIssue":16,"sourceDataRoute":"/products/source-data","previewRoute":"/products/indie-launch-library","recordsIncluded":true,"counts":{"paymentPlans":3,"installmentPlans":1,"subscriptionPlans":1,"payInFullPlans":1},"supportedBillingModels":["pay_in_full","installments","subscription"],"plans":[{"id":"product-payment-plan-launch-course-installments","title":"Launch course installment plan","status":"draft","billingModel":"installments","productIds":["product-launch-course-lite"],"entitlementTemplateIds":["entitlement-template-launch-course"],"accessRuleIds":["access-rule-course-after-paid-webhook"],"sourcePriceId":null,"installments":3,"interval":"month","amountCents":null,"currency":"usd","customerLabel":"Three scheduled payments before course access is considered fully paid.","liveBillingEnabled":false,"stripePriceCreated":false,"checkoutSessionCreated":false,"writeBoundary":"This is a product payment-plan read contract only. It does not create Stripe Prices, Checkout Sessions, installment schedules, live charges, access grants, or customer records."},{"id":"product-payment-plan-launch-membership-recurring","title":"Launch membership recurring plan","status":"draft","billingModel":"subscription","productIds":["product-launch-membership"],"entitlementTemplateIds":["entitlement-template-launch-membership"],"accessRuleIds":["access-rule-membership-active-subscription"],"sourcePriceId":"price-launch-membership-monthly-usd","installments":null,"interval":"month","amountCents":null,"currency":"usd","customerLabel":"Monthly membership access depends on trusted active or trialing subscription state.","liveBillingEnabled":false,"stripePriceCreated":false,"checkoutSessionCreated":false,"writeBoundary":"This plan points to the existing seeded subscription membership price id for read semantics only. It does not create or mutate Stripe subscriptions, Customer Portal sessions, live charges, or member delivery."},{"id":"product-payment-plan-launch-bundle-pay-in-full","title":"Launch bundle pay-in-full plan","status":"draft","billingModel":"pay_in_full","productIds":["product-launch-bundle"],"entitlementTemplateIds":["entitlement-template-launch-bundle"],"accessRuleIds":["access-rule-download-after-paid-webhook","access-rule-course-after-paid-webhook"],"sourcePriceId":null,"installments":null,"interval":null,"amountCents":null,"currency":"usd","customerLabel":"Single checkout path that can grant bundled access after trusted paid evidence.","liveBillingEnabled":false,"stripePriceCreated":false,"checkoutSessionCreated":false,"writeBoundary":"This is a seeded plan option for read and preview surfaces only. Live checkout, Stripe Price creation, fulfillment delivery, and published offer selection remain future confirmed-write work."}],"redaction":{"buyerEmailIncluded":false,"buyerEmailHashIncluded":false,"rawStripePriceIdsIncluded":false,"rawStripeCustomerIdsIncluded":false,"rawStripeSubscriptionIdsIncluded":false,"liveAmountsIncluded":false,"checkoutSessionIdsIncluded":false,"customerPortalUrlIncluded":false,"idempotencyKeysIncluded":false},"writeBoundary":"Payment plans are public-safe seeded read records only. They do not create Stripe Prices, Checkout Sessions, live charges, installment schedules, Customer Portal sessions, fulfillment delivery, customer records, or direct agent billing writes."},"writeBoundary":"Issue #101 can grant idempotent sandbox product entitlement rows and fulfillment task evidence from trusted paid checkout webhooks, issue #141 can inspect customer-safe checkout-intent entitlement status, issue #143 can create one-use download tokens for active file entitlements, issue #146 can stream a seeded private R2-backed fixture through Bumpgrade, issue #147 revalidates current entitlement and trusted checkout state before redemption, issue #151 lets verified owners create small private asset upload records after exact confirmation, idempotency, and catalog revision checks, issue #179 exposes non-destructive revocation intent readiness, issue #181 exposes protected content readiness, issue #185 returns seeded protected fixture bodies only after checkout-intent, entitlement, product/template scope, and trusted checkout checks, issue #187 syncs checkout-linked membership entitlement state from trusted Stripe Billing subscription events, issue #251 lets verified owners record non-destructive revocation intents after exact confirmation, idempotency, and stale-state checks, issue #403 lets verified owners create draft product records after exact confirmation and idempotency without billing or fulfillment mutation, issue #405 lets verified owners link owner-created draft products to test offer/funnel IDs and create synthetic paid checkout/access grant evidence without Stripe Checkout Sessions, live charges, published offer copy, or public buyer exposure, issue #407 lets verified owners create buyer-facing test checkout links that public test buyers can complete after exact confirmation, idempotency, and link-revision checks to create synthetic paid checkout/access evidence, issue #409 lets verified owners link those test checkout links to seeded offer/funnel delivery gates, and issue #16 now exposes seeded pay-in-full, installment, and subscription payment-plan read semantics without live billing mutation. Customer delivery of arbitrary uploads, signed object URLs, Stripe product and price creation, live offer/funnel publishing, refunds, Customer Portal actions, destructive revocations, live fulfillment automation, and direct unconfirmed agent writes require future APIs.","catalogs":[{"id":"product-access-catalog-indie-launch","slug":"indie-launch-library","title":"Indie launch product and access library","status":"draft","issue":101,"parentIssue":16,"sourceDataRoute":"/products/source-data","previewRoute":"/products/indie-launch-library","checkoutOfferRoute":"/offers/indie-launch-stack","commerceContractRoute":"/commerce/source-data","revisionId":"product-access-revision-indie-launch-2026-05-19","summary":"A product and access library for downloads, courses, memberships, services, events, bundles, payment-backed access, and protected delivery.","assets":[{"id":"asset-launch-checklist-pdf","kind":"file","title":"Launch checklist PDF","publicDescription":"A downloadable checklist asset delivered only after customer access is confirmed.","storageBoundary":"Issue #146 stores and reads the safe fixture through the PRODUCT_ASSETS R2 binding server-side; private object keys and signed URLs stay out of public source-data and token responses."},{"id":"asset-launch-course-lessons","kind":"lesson","title":"Launch course lessons","publicDescription":"Course lesson metadata for a future protected learning area.","storageBoundary":"Lesson bodies, videos, transcripts, and progress data remain private until auth and entitlements ship."},{"id":"asset-launch-member-area","kind":"member_area","title":"Launch member area","publicDescription":"Membership container for recurring access state.","storageBoundary":"Member-only posts, files, community data, and billing identifiers are not exposed in this source-data slice."},{"id":"asset-launch-coaching-booking","kind":"booking","title":"Launch coaching booking","publicDescription":"Manual scheduling path for service delivery.","storageBoundary":"Calendar links, private notes, buyer details, and meeting URLs stay server-private."},{"id":"asset-launch-webinar-seat","kind":"event","title":"Launch webinar seat","publicDescription":"Event access path for webinar or live workshop delivery.","storageBoundary":"Private join URLs, attendee lists, and replay URLs require confirmed entitlement state."}],"accessRules":[{"id":"access-rule-download-after-paid-webhook","title":"Grant download after paid checkout","grants":"Digital download access after trusted checkout completion.","timing":"after_webhook_paid","revocable":true,"sourceEvent":"checkout.session.completed","writeBoundary":"Issue #146 can issue a short-lived one-use token for active file entitlements and stream the seeded private R2 fixture through Bumpgrade."},{"id":"access-rule-course-after-paid-webhook","title":"Grant course after paid checkout","grants":"Course enrollment after paid checkout evidence.","timing":"after_webhook_paid","revocable":true,"sourceEvent":"checkout.session.completed","writeBoundary":"No protected lesson access or progress record is written in this slice."},{"id":"access-rule-membership-active-subscription","title":"Grant membership while subscription is active","grants":"Membership access while Stripe subscription state is active or trialing.","timing":"active_subscription","revocable":true,"sourceEvent":"customer.subscription.updated","writeBoundary":"No subscription entitlement is granted until billing subscription state is mirrored and trusted."},{"id":"access-rule-service-manual-review","title":"Queue service fulfillment for manual review","grants":"Service or coaching delivery task after payment evidence.","timing":"manual_review","revocable":true,"sourceEvent":"payment_audit_events","writeBoundary":"No private booking link, customer note, or meeting URL is exposed through public source-data."},{"id":"access-rule-event-after-paid-webhook","title":"Grant event seat after paid checkout","grants":"Event or webinar seat after trusted payment evidence.","timing":"after_webhook_paid","revocable":true,"sourceEvent":"checkout.session.completed","writeBoundary":"No join URL, attendee roster, or replay access is exposed until entitlement writes exist."}],"products":[{"id":"product-launch-checklist-download","slug":"launch-checklist-download","kind":"digital_download","title":"Launch checklist download","status":"draft","summary":"A downloadable asset that can back an order bump or standalone checkout product.","linkedOfferIds":["offer-bump-launch-checklist"],"assetIds":["asset-launch-checklist-pdf"],"accessRuleIds":["access-rule-download-after-paid-webhook"],"entitlementTemplateId":"entitlement-template-launch-download"},{"id":"product-launch-course-lite","slug":"launch-course-lite","kind":"course","title":"Launch course lite","status":"draft","summary":"A small course product for lessons, modules, and protected progress state.","linkedOfferIds":["offer-upsell-launch-accelerator"],"assetIds":["asset-launch-course-lessons"],"accessRuleIds":["access-rule-course-after-paid-webhook"],"entitlementTemplateId":"entitlement-template-launch-course"},{"id":"product-launch-membership","slug":"launch-membership","kind":"membership","title":"Launch membership","status":"draft","summary":"Recurring membership access that depends on subscription state.","linkedOfferIds":["offer-upsell-launch-accelerator"],"assetIds":["asset-launch-member-area"],"accessRuleIds":["access-rule-membership-active-subscription"],"entitlementTemplateId":"entitlement-template-launch-membership"},{"id":"product-launch-coaching-session","slug":"launch-coaching-session","kind":"coaching_service","title":"Launch coaching session","status":"draft","summary":"Manual service fulfillment path for coaching or implementation support.","linkedOfferIds":["offer-downsell-launch-review"],"assetIds":["asset-launch-coaching-booking"],"accessRuleIds":["access-rule-service-manual-review"],"entitlementTemplateId":"entitlement-template-launch-service"},{"id":"product-launch-webinar-seat","slug":"launch-webinar-seat","kind":"event_webinar","title":"Launch webinar seat","status":"draft","summary":"Event or webinar access record with private join details kept out of public data.","linkedOfferIds":["offer-downsell-launch-review"],"assetIds":["asset-launch-webinar-seat"],"accessRuleIds":["access-rule-event-after-paid-webhook"],"entitlementTemplateId":"entitlement-template-launch-event"},{"id":"product-launch-bundle","slug":"launch-bundle","kind":"bundle","title":"Launch bundle","status":"draft","summary":"Bundle model that can grant multiple product entitlements after a trusted purchase.","linkedOfferIds":["offer-upsell-launch-accelerator"],"assetIds":["asset-launch-checklist-pdf","asset-launch-course-lessons","asset-launch-member-area"],"accessRuleIds":["access-rule-download-after-paid-webhook","access-rule-course-after-paid-webhook","access-rule-membership-active-subscription"],"entitlementTemplateId":"entitlement-template-launch-bundle"}],"productPaymentPlans":[{"id":"product-payment-plan-launch-course-installments","title":"Launch course installment plan","status":"draft","billingModel":"installments","productIds":["product-launch-course-lite"],"entitlementTemplateIds":["entitlement-template-launch-course"],"accessRuleIds":["access-rule-course-after-paid-webhook"],"sourcePriceId":null,"installments":3,"interval":"month","amountCents":null,"currency":"usd","customerLabel":"Three scheduled payments before course access is considered fully paid.","liveBillingEnabled":false,"stripePriceCreated":false,"checkoutSessionCreated":false,"writeBoundary":"This is a product payment-plan read contract only. It does not create Stripe Prices, Checkout Sessions, installment schedules, live charges, access grants, or customer records."},{"id":"product-payment-plan-launch-membership-recurring","title":"Launch membership recurring plan","status":"draft","billingModel":"subscription","productIds":["product-launch-membership"],"entitlementTemplateIds":["entitlement-template-launch-membership"],"accessRuleIds":["access-rule-membership-active-subscription"],"sourcePriceId":"price-launch-membership-monthly-usd","installments":null,"interval":"month","amountCents":null,"currency":"usd","customerLabel":"Monthly membership access depends on trusted active or trialing subscription state.","liveBillingEnabled":false,"stripePriceCreated":false,"checkoutSessionCreated":false,"writeBoundary":"This plan points to the existing seeded subscription membership price id for read semantics only. It does not create or mutate Stripe subscriptions, Customer Portal sessions, live charges, or member delivery."},{"id":"product-payment-plan-launch-bundle-pay-in-full","title":"Launch bundle pay-in-full plan","status":"draft","billingModel":"pay_in_full","productIds":["product-launch-bundle"],"entitlementTemplateIds":["entitlement-template-launch-bundle"],"accessRuleIds":["access-rule-download-after-paid-webhook","access-rule-course-after-paid-webhook"],"sourcePriceId":null,"installments":null,"interval":null,"amountCents":null,"currency":"usd","customerLabel":"Single checkout path that can grant bundled access after trusted paid evidence.","liveBillingEnabled":false,"stripePriceCreated":false,"checkoutSessionCreated":false,"writeBoundary":"This is a seeded plan option for read and preview surfaces only. Live checkout, Stripe Price creation, fulfillment delivery, and published offer selection remain future confirmed-write work."}],"entitlementTemplates":[{"id":"entitlement-template-launch-download","title":"Launch download entitlement","productIds":["product-launch-checklist-download"],"status":"draft","grants":["Download asset access","Receipt-visible fulfillment status"],"revocationRules":["Refunds or chargebacks should revoke download eligibility in a future fulfillment API."],"privateDataExcluded":["R2 object key","signed URL","buyer email","Stripe customer id"]},{"id":"entitlement-template-launch-course","title":"Launch course entitlement","productIds":["product-launch-course-lite"],"status":"draft","grants":["Course enrollment","Protected lesson access"],"revocationRules":["Refund, dispute, or manual admin revocation should remove future lesson access."],"privateDataExcluded":["Lesson body","video URL","progress state","buyer identity"]},{"id":"entitlement-template-launch-membership","title":"Launch membership entitlement","productIds":["product-launch-membership"],"status":"draft","grants":["Member area access while subscription is active"],"revocationRules":["Subscription cancellation, unpaid invoices, refunds, or disputes should revoke active access."],"privateDataExcluded":["Stripe subscription id","member posts","private files","buyer identity"]},{"id":"entitlement-template-launch-service","title":"Launch service entitlement","productIds":["product-launch-coaching-session"],"status":"draft","grants":["Manual service fulfillment task"],"revocationRules":["Service cancellation or refund should close or reverse the fulfillment task."],"privateDataExcluded":["Calendar link","meeting URL","private notes","buyer identity"]},{"id":"entitlement-template-launch-event","title":"Launch event entitlement","productIds":["product-launch-webinar-seat"],"status":"draft","grants":["Event seat","Replay eligibility after event"],"revocationRules":["Refund, cancellation, or no-show policy should determine event access changes."],"privateDataExcluded":["Join URL","attendee list","replay URL","buyer identity"]},{"id":"entitlement-template-launch-bundle","title":"Launch bundle entitlement","productIds":["product-launch-bundle"],"status":"draft","grants":["Download access","Course enrollment","Membership access"],"revocationRules":["Bundle revocation should cascade through each component entitlement with audit evidence."],"privateDataExcluded":["Component private asset keys","subscription ids","buyer identity"]}],"writeBoundary":"Issue #101 can grant idempotent sandbox product entitlement rows and fulfillment task evidence from trusted paid checkout webhooks, issue #141 can inspect customer-safe checkout-intent entitlement status, issue #143 can create one-use download tokens for active file entitlements, issue #146 can stream a seeded private R2-backed fixture through Bumpgrade, issue #147 revalidates current entitlement and trusted checkout state before redemption, issue #151 lets verified owners create small private asset upload records after exact confirmation, idempotency, and catalog revision checks, issue #179 exposes non-destructive revocation intent readiness, issue #181 exposes protected content readiness, issue #185 returns seeded protected fixture bodies only after checkout-intent, entitlement, product/template scope, and trusted checkout checks, issue #187 syncs checkout-linked membership entitlement state from trusted Stripe Billing subscription events, issue #251 lets verified owners record non-destructive revocation intents after exact confirmation, idempotency, and stale-state checks, issue #403 lets verified owners create draft product records after exact confirmation and idempotency without billing or fulfillment mutation, issue #405 lets verified owners link owner-created draft products to test offer/funnel IDs and create synthetic paid checkout/access grant evidence without Stripe Checkout Sessions, live charges, published offer copy, or public buyer exposure, issue #407 lets verified owners create buyer-facing test checkout links that public test buyers can complete after exact confirmation, idempotency, and link-revision checks to create synthetic paid checkout/access evidence, issue #409 lets verified owners link those test checkout links to seeded offer/funnel delivery gates, and issue #16 now exposes seeded pay-in-full, installment, and subscription payment-plan read semantics without live billing mutation. Customer delivery of arbitrary uploads, signed object URLs, Stripe product and price creation, live offer/funnel publishing, refunds, Customer Portal actions, destructive revocations, live fulfillment automation, and direct unconfirmed agent writes require future APIs.","validation":["/products/source-data returns seeded products, assets, access rules, entitlement templates, and payment-plan read records.","/products/indie-launch-library renders the product/access preview.","/products/entitlements renders checkout-intent-scoped customer entitlement lookup.","/api/products/download-tokens creates short-lived download tokens for active file entitlements.","/api/products/downloads?token={token} revalidates current entitlement and trusted checkout state, streams the seeded private R2 fixture once, and rejects token replay.","/api/admin/products/assets lets verified owners create small private R2-backed asset upload records without exposing private object keys, signed URLs, or upload bodies.","/api/admin/products/catalog lets verified owners create draft product records without Stripe product/price creation, fulfillment mutation, customer access grants, or raw owner identity exposure.","Owner-confirmed revocation intents are recordable without entitlement mutation, access removal, raw buyer exposure, billing changes, refunds, or customer notification.","Protected content readiness is inspectable without lesson bodies, member posts, progress rows, private R2 keys, signed URLs, or customer delivery.","Subscription-backed membership access is inspectable without raw Stripe subscription/customer IDs, buyer identity, member posts, private files, or Customer Portal URLs.","/api/stripe/webhook grants idempotent sandbox entitlements after trusted paid checkout evidence.","/agent-docs/source-data lists the product access read contract for future MCP resources."]}],"caveat":"This contract proves product/access read and preview semantics, seeded product payment-plan read semantics, sandbox webhook-backed entitlement row grants, subscription-backed membership entitlement state, owner inspection, customer-safe checkout-intent entitlement lookup, short-lived download tokens, seeded private R2-backed fixture delivery, owner-confirmed draft product creation, owner-created product test checkout links and buyer-facing test checkout completion, owner-created product delivery-gate links for the seeded offer/funnel path, owner-created product test offer/access grants, owner-confirmed small private asset upload records, owner-confirmed non-destructive revocation intent records, protected content readiness, and checkout-intent-scoped protected fixture delivery. It does not expose private R2 keys, signed object URLs, upload bodies, arbitrary uploaded content, private revocation notes, raw owner identity, raw buyer identity, raw checkout link IDs, raw checkout or entitlement IDs in public source-data, raw Stripe price/subscription/customer IDs, live amounts, destructive revocation APIs, Stripe product or price creation, live offer/funnel publishing, live fulfillment automation, customer portals, customer delivery of arbitrary uploads, or direct unconfirmed agent writes.","entitlementInspection":{"id":"product-entitlement-inspection-contract","status":"owner-product-entitlement-inspection-ready","issue":139,"parentIssue":16,"ownerRoute":"/admin/products","publicSourceDataRoute":"/products/source-data","source":"d1","loadError":null,"counts":{"entitlements":8,"activeEntitlements":8,"fulfillmentTasks":8,"queuedFulfillmentTasks":8,"checkoutIntentsWithEntitlements":4},"lastGrantedAt":"2026-05-19T12:23:59.000Z","lastFulfillmentAt":"2026-05-19T12:23:59.000Z","productCounts":[{"id":"product-launch-bundle","status":"active","total":4},{"id":"product-launch-checklist-download","status":"active","total":4}],"templateCounts":[{"id":"entitlement-template-launch-bundle","status":"active","total":4},{"id":"entitlement-template-launch-download","status":"active","total":4}],"fulfillmentCounts":[{"id":"bundle","status":"queued","total":4},{"id":"digital_download","status":"queued","total":4}],"redaction":{"privateBuyerDataIncluded":false,"rawBuyerEmailIncluded":false,"buyerEmailHashIncluded":false,"rawStripeIdsIncluded":false,"rawR2KeysIncluded":false,"signedUrlsIncluded":false,"metadataJsonIncluded":false},"privateFieldsExcluded":["buyerEmail","buyerEmailHash","sourceStripeEventId","stripeCheckoutSessionId","stripePaymentIntentId","stripeSubscriptionId","metadataJson","privateR2ObjectKeys","signedUrls"],"writeBoundary":"Issue #139 exposes owner-gated product entitlement and fulfillment inspection plus public aggregate source-data. Signed downloads, protected lessons, revocations, subscription access changes, refunds, customer portals, private asset delivery, and direct agent entitlement writes still require future confirmed-write APIs."},"customerEntitlementLookup":{"id":"customer-product-entitlement-lookup-contract","status":"customer-product-entitlement-lookup-ready","issue":141,"parentIssue":16,"route":"/products/entitlements","apiRoute":"/api/products/entitlements","sourceDataRoute":"/products/source-data","authBoundary":"checkout-intent-bearer-reference","lookupInput":"checkoutIntentId","redaction":{"buyerEmailIncluded":false,"buyerEmailHashIncluded":false,"rawStripeIdsIncluded":false,"sourceStripeEventIdsIncluded":false,"rawR2KeysIncluded":false,"signedUrlsIncluded":false,"metadataJsonIncluded":false,"downloadTokensIncluded":false},"privateFieldsExcluded":["buyerEmail","buyerEmailHash","buyerUserId","ownerUserId","sourceStripeEventId","stripeCheckoutSessionId","stripePaymentIntentId","stripeSubscriptionId","metadataJson","privateR2ObjectKeys","signedUrls"],"writeBoundary":"Issue #141 exposes a checkout-intent-scoped customer entitlement lookup with product, access-rule, and fulfillment status only. Issue #143 can create one-use download tokens for active file entitlements, issue #146 can stream a seeded private R2-backed fixture through Bumpgrade, issue #147 revalidates current entitlement and trusted checkout state at redemption, and issue #187 can show subscription-backed membership entitlement state after trusted Stripe Billing events. Private R2 keys, signed URLs, protected lessons, private buyer data, entitlement mutation, revocation, arbitrary asset uploads, Customer Portal actions, and live fulfillment automation remain future authenticated confirmed-write APIs."},"sandboxDownloadTokens":{"id":"sandbox-product-download-token-contract","status":"private-r2-download-delivery-ready","issue":146,"followsIssue":143,"redemptionRevalidationIssue":147,"parentIssue":16,"apiRoute":"/api/products/download-tokens","downloadRoutePrefix":"/api/products/downloads","sourceDataRoute":"/products/source-data","ttlSeconds":900,"tables":["product_download_tokens"],"privateAssetBucketBinding":"PRODUCT_ASSETS","authBoundary":"checkout-intent-and-entitlement-bearer-reference","eligibleAssetKind":"file","deliveryMode":"private-r2-fixture","privateAssetDelivery":{"r2Backed":true,"seededAssetId":"asset-launch-checklist-pdf","rawR2KeysIncluded":false,"signedUrlsIncluded":false},"redemptionRevalidation":{"entitlementStatus":"active","trustedCheckoutStatuses":["paid","completed"],"checkoutIntentLinkRequired":true,"assetScopeCheckedBeforeRead":true,"tokenConsumedAfterPrivateAssetRead":true},"redaction":{"buyerEmailIncluded":false,"buyerEmailHashIncluded":false,"rawStripeIdsIncluded":false,"rawR2KeysIncluded":false,"signedUrlsIncluded":false,"metadataJsonIncluded":false},"writeBoundary":"Issue #146 can create short-lived download tokens for active checkout-linked file entitlements and stream a seeded private R2-backed fixture through Bumpgrade. Issue #147 revalidates current entitlement status, checkout intent linkage, trusted checkout state, and asset scope before private R2 reads or token consumption. It does not expose private R2 keys, signed object URLs, protected lessons, buyer identity, revocation, subscription access, arbitrary uploads, or live fulfillment automation."},"ownerAssetUploadIntents":{"id":"owner-private-product-asset-upload-intents","status":"owner-private-asset-upload-intents-ready","issue":151,"parentIssue":16,"apiRoute":"/api/admin/products/assets","sourceDataRoute":"/products/source-data","ownerAuthBoundary":"Better Auth owner session","confirmation":{"required":true,"text":"Create private product asset upload intent"},"idempotencyRequired":true,"staleStateCheck":{"required":true,"field":"expectedCatalogRevisionId","currentRevisionId":"product-access-revision-indie-launch-2026-05-19"},"maxPayloadBytes":65536,"tables":["product_asset_uploads"],"privateAssetBucketBinding":"PRODUCT_ASSETS","redaction":{"rawR2KeysIncluded":false,"signedUrlsIncluded":false,"rawUploadBodyIncluded":false,"privateMetadataIncluded":false,"rawOwnerEmailIncluded":false,"buyerDataIncluded":false},"writeBoundary":"Verified owners can create small private product asset upload records after exact confirmation, idempotency, and product-catalog revision checks. The API stores the body in PRODUCT_ASSETS under a server-only object key and returns only public-safe metadata. It does not expose R2 object keys, signed URLs, upload bodies, private owner metadata, buyer data, customer delivery, protected content, revocation, or direct unauthenticated agent writes.","source":"d1","loadError":null,"counts":{"uploadRecords":1,"storedPrivateUploads":1},"latestCreatedAt":"2026-05-19T18:32:23.000Z","rawRowsIncluded":false},"productCreation":{"id":"owner-product-creation","status":"owner-product-creation-ready","issue":403,"parentIssue":16,"apiRoute":"/api/admin/products/catalog","sourceDataRoute":"/products/source-data","ownerRoute":"/admin/products","ownerAuthBoundary":"Better Auth owner session","confirmation":{"required":true,"text":"Create draft product"},"idempotencyRequired":true,"supportedKinds":["digital_download","course","membership","coaching_service","event_webinar","bundle"],"writeBoundary":"Owners can create draft Bumpgrade product records after exact confirmation and idempotency. This does not create Stripe products or prices, publish offer copy, grant fulfillment, create customer access, expose private owner identity, or enable direct unauthenticated agent writes.","redaction":{"actorEmailIncluded":false,"actorUserIdIncluded":false,"idempotencyKeysIncluded":false,"rawRowsIncluded":false,"rawStripeIdsIncluded":false,"billingMutationEnabled":false,"fulfillmentMutationEnabled":false},"source":"d1","loadError":null,"counts":{"creationIntents":0,"draftProducts":0},"kindCounts":[],"latestCreatedAt":null,"recordsIncluded":false},"productDeliveryGates":{"id":"owner-product-delivery-gates","status":"owner-product-delivery-gate-ready","issue":409,"parentIssue":16,"apiRoute":"/api/admin/products/delivery-gates","ownerRoute":"/admin/products","sourceDataRoute":"/products/source-data","offerSourceDataRoute":"/offers/source-data","funnelSourceDataRoute":"/funnels/source-data","offerStackId":"checkout-stack-indie-launch-sandbox","offerId":"offer-primary-sandbox-launch-pass","offerPreviewRoute":"/offers/indie-launch-stack","funnelId":"funnel-indie-launch-sandbox","funnelRoute":"/funnels/indie-launch-sandbox","auth":"Better Auth owner session","confirmation":{"required":true,"text":"Link owner product to offer and delivery gates"},"idempotencyRequired":true,"staleStateChecks":["expectedProductUpdatedAt","expectedLinkRevisionId"],"recordsIncluded":false,"writeBoundary":"Owners can link an owner-created product test checkout link to the seeded offer/funnel delivery gates after exact confirmation, idempotency, a current product updatedAt check, and a current checkout-link revision check. The link records offer/funnel/product delivery intent only; it does not create Stripe products, Stripe prices, Checkout Sessions, live charges, live offer/funnel publishing, arbitrary customer delivery, signed URLs, private R2 keys, or direct unconfirmed agent writes.","deliveryBoundary":"Customer delivery remains gated by the test checkout entitlement and fulfillment task. Seeded fixture delivery can be inspected through existing checkout-intent scoped product routes; arbitrary uploaded asset delivery, live protected course/member delivery, signed URLs, and live fulfillment automation remain blocked.","redaction":{"actorEmailIncluded":false,"actorUserIdIncluded":false,"buyerEmailIncluded":false,"buyerEmailHashIncluded":false,"idempotencyKeysIncluded":false,"checkoutLinkIdsIncluded":false,"publicCheckoutIntentIdsIncluded":false,"publicEntitlementIdsIncluded":false,"rawStripeIdsIncluded":false,"rawR2KeysIncluded":false,"signedUrlsIncluded":false,"liveBillingEnabled":false,"liveFulfillmentDeliveryEnabled":false},"source":"d1","loadError":null,"counts":{"deliveryGateLinks":0,"activeDeliveryGateLinks":0,"liveBillingEnabled":0,"liveFulfillmentDeliveryEnabled":0},"latestLinkedAt":null},"productOfferAccess":{"id":"owner-product-offer-access-grants","status":"owner-product-offer-access-ready","issue":405,"parentIssue":16,"apiRoute":"/api/admin/products/offer-access-grants","sourceDataRoute":"/products/source-data","ownerRoute":"/admin/products","ownerAuthBoundary":"Better Auth owner session","confirmation":{"required":true,"text":"Link product and create test access grant"},"idempotencyRequired":true,"defaultOfferIdPrefix":"offer-owner-product-test","defaultFunnelIdPrefix":"funnel-owner-product-test","writeBoundary":"Owners can link an owner-created draft product to test offer/funnel IDs and create a synthetic test checkout intent, product entitlement, fulfillment task evidence, and payment audit event after exact confirmation and idempotency. This does not create Stripe products, Stripe prices, Checkout Sessions, live charges, published offer copy, customer-facing fulfillment delivery, raw buyer exposure, or direct unauthenticated agent writes.","redaction":{"actorEmailIncluded":false,"actorUserIdIncluded":false,"buyerEmailIncluded":false,"buyerEmailHashIncluded":false,"idempotencyKeysIncluded":false,"publicCheckoutIntentIdsIncluded":false,"publicEntitlementIdsIncluded":false,"rawStripeIdsIncluded":false,"liveBillingEnabled":false,"stripeCheckoutSessionCreated":false,"fulfillmentDeliveryEnabled":false},"source":"d1","loadError":null,"counts":{"grantIntents":0,"linkedProducts":0,"testCheckoutIntents":0,"activeTestEntitlements":0},"latestCreatedAt":null,"recordsIncluded":false},"productTestCheckout":{"id":"owner-product-test-checkout-links","status":"owner-product-test-checkout-ready","issue":407,"parentIssue":16,"ownerApiRoute":"/api/admin/products/test-checkout-links","checkoutApiRoute":"/api/products/test-checkout","publicRoutePattern":"/products/test-checkout/:linkId","sourceDataRoute":"/products/source-data","ownerRoute":"/admin/products","ownerAuthBoundary":"Better Auth owner session","publicCheckoutBoundary":"public test checkout link plus exact confirmation, idempotency, and link revision check","ownerConfirmation":{"required":true,"text":"Create test checkout link for owner product"},"buyerConfirmation":{"required":true,"text":"Complete test checkout for owner product"},"idempotencyRequired":true,"staleStateChecks":["expectedProductUpdatedAt","expectedLinkRevisionId"],"writeBoundary":"Owners can create stable buyer-facing test checkout links for owner-created draft products after exact confirmation, idempotency, and a current product updatedAt check. Buyers can use those links to create synthetic paid test checkout, entitlement, fulfillment task, and audit evidence after exact confirmation, idempotency, and a current link revision check. This does not create Stripe products, Stripe prices, Stripe Checkout Sessions, live charges, live offer/funnel publishing, arbitrary fulfillment delivery, raw buyer exposure, or direct unconfirmed agent writes.","redaction":{"actorEmailIncluded":false,"actorUserIdIncluded":false,"buyerEmailIncluded":false,"buyerEmailHashIncluded":false,"idempotencyKeysIncluded":false,"publicCheckoutLinkIdsIncluded":false,"publicCheckoutIntentIdsIncluded":false,"publicEntitlementIdsIncluded":false,"rawStripeIdsIncluded":false,"liveBillingEnabled":false,"stripeCheckoutSessionCreated":false,"liveChargeCreated":false,"fulfillmentDeliveryEnabled":false},"source":"d1","loadError":null,"counts":{"checkoutLinks":0,"activeCheckoutLinks":0,"testPurchases":0,"activeTestEntitlements":0},"latestLinkCreatedAt":null,"latestPurchaseCreatedAt":null,"recordsIncluded":false},"revocationIntents":{"id":"product-entitlement-revocation-intent-contract","status":"owner-product-revocation-intents-ready","issue":179,"parentIssue":16,"ownerRoute":"/admin/products","publicSourceDataRoute":"/products/source-data","apiRoute":"/api/admin/products/revocation-intents","writeIssue":251,"source":"d1","loadError":null,"confirmation":{"required":true,"text":"Record product access removal intent"},"idempotencyRequired":true,"staleStateCheck":{"required":true,"field":"expectedEntitlementStatus"},"reasonCodes":["manual_review","refund_or_chargeback","customer_request","test_cleanup"],"counts":{"revocationIntents":1,"dryRunIntents":1,"ownerConfirmedIntents":0,"destructiveActionsEnabled":0,"entitlementMutationsEnabled":0},"records":[{"id":"revocation-intent-launch-download-dry-run","productId":"product-launch-checklist-download","productTitle":"Launch checklist download","entitlementTemplateId":"entitlement-template-launch-download","entitlementTemplateTitle":"Launch download entitlement","accessRuleId":"access-rule-download-after-paid-webhook","accessRuleTitle":"Grant download after paid checkout","status":"revocation_intent_ready","intentKind":"owner_confirmed_dry_run","reasonCode":null,"ownerConfirmed":false,"privateReasonRecorded":false,"revocationPolicy":"Future revocation must require owner identity, exact confirmation, current entitlement status, refund/dispute/manual reason, and customer-safe notification review before access removal.","staleStatePolicy":"Reject future destructive revocation if entitlement status, checkout state, buyer scope, or product mapping changed since the owner reviewed it.","auditCorrelationPolicy":"Future revocation rows must include owner action id, entitlement id, checkout intent id, product id, reason code, idempotency key, and redacted audit event id.","destructiveActionEnabled":false,"entitlementMutationEnabled":false,"targetEntitlementIncluded":false,"actorIdentityIncluded":false,"createdAt":"2026-05-20T01:05:56.000Z","updatedAt":"2026-05-20T01:05:56.000Z"}],"redaction":{"privateBuyerDataIncluded":false,"rawBuyerEmailIncluded":false,"actorEmailIncluded":false,"actorEmailHashIncluded":false,"rawStripeIdsIncluded":false,"targetEntitlementIdsIncluded":false,"privateReasonIncluded":false,"entitlementMutationEnabled":false,"destructiveActionEnabled":false},"privateFieldsExcluded":["buyerEmail","buyerEmailHash","actorEmail","actorEmailHash","targetEntitlementId","stripeCheckoutSessionId","stripePaymentIntentId","stripeSubscriptionId","metadataJson","privateReason","privateReasonNote"],"writeBoundary":"Issue #179 exposes non-destructive product entitlement revocation intent readiness. Issue #251 lets verified owners record non-destructive revocation intents after exact confirmation, idempotency, and a current entitlement status check. It does not revoke access, mutate entitlements, expose buyer data, change billing, issue refunds, notify customers, or authorize direct public agent revocation writes."},"protectedContent":{"id":"product-protected-content-readiness-contract","status":"protected-product-content-readiness-ready","issue":181,"parentIssue":16,"ownerRoute":"/admin/products","publicSourceDataRoute":"/products/source-data","source":"d1","loadError":null,"counts":{"protectedContentItems":2,"courseItems":1,"membershipItems":1,"deliveryEnabled":2,"protectedBodiesIncluded":0},"records":[{"id":"protected-content-launch-course-module-1","productId":"product-launch-course-lite","productTitle":"Launch course lite","assetId":"asset-launch-course-lessons","assetTitle":"Launch course lessons","entitlementTemplateId":"entitlement-template-launch-course","entitlementTemplateTitle":"Launch course entitlement","status":"protected_content_ready","contentKind":"course_module","title":"Launch course module readiness","publicSummary":"Public-safe metadata for the first protected course module.","accessPolicy":"Future delivery must require an active course entitlement, current trusted checkout state, and a fresh access check before any lesson body, video, transcript, or progress row is returned.","privateContentBoundary":"Lesson body, video URL, transcript body, progress state, buyer identity, private R2 object keys, and signed URLs are excluded from this readiness record.","deliveryEnabled":true,"protectedBodyIncluded":false,"updatedAt":"2026-05-20T02:21:17.000Z"},{"id":"protected-content-launch-member-area","productId":"product-launch-membership","productTitle":"Launch membership","assetId":"asset-launch-member-area","assetTitle":"Launch member area","entitlementTemplateId":"entitlement-template-launch-membership","entitlementTemplateTitle":"Launch membership entitlement","status":"protected_content_ready","contentKind":"member_area","title":"Launch member area readiness","publicSummary":"Public-safe metadata for a future protected member area.","accessPolicy":"Future delivery must require active subscription-backed membership entitlement, stale-state checks, and redacted audit evidence before member posts or files are returned.","privateContentBoundary":"Member post bodies, private files, community data, subscription identifiers, buyer identity, private R2 object keys, and signed URLs are excluded from this readiness record.","deliveryEnabled":true,"protectedBodyIncluded":false,"updatedAt":"2026-05-20T02:21:17.000Z"}],"redaction":{"privateContentBodiesIncluded":false,"rawR2KeysIncluded":false,"signedUrlsIncluded":false,"buyerDataIncluded":false,"progressDataIncluded":false,"deliveryEnabled":false},"delivery":{"id":"product-protected-content-delivery-contract","status":"protected-product-content-delivery-ready","issue":185,"followsIssue":181,"parentIssue":16,"apiRoute":"/api/products/protected-content","sourceDataRoute":"/products/source-data","authBoundary":"checkout-intent-and-entitlement-bearer-reference","lookupInputs":["checkoutIntentId","entitlementId","protectedContentId"],"eligibleContentKinds":["course_module","member_area"],"deliveryMode":"seeded-protected-fixture","trustedCheckoutStatuses":["paid","completed"],"redaction":{"buyerEmailIncluded":false,"buyerEmailHashIncluded":false,"rawStripeIdsIncluded":false,"sourceStripeEventIdsIncluded":false,"rawR2KeysIncluded":false,"signedUrlsIncluded":false,"metadataJsonIncluded":false,"protectedBodyIncludedInSourceData":false,"progressDataIncluded":false},"writeBoundary":"Issue #185 can return seeded protected course/member fixture bodies only for an active checkout-linked entitlement whose product/template scope matches the protected content section and whose checkout state is currently paid or completed. It does not expose buyer identity, raw Stripe IDs, webhook IDs, private R2 keys, signed URLs, metadata JSON, progress rows, arbitrary uploaded content, live fulfillment automation, or direct unauthenticated agent writes."},"privateFieldsExcluded":["lessonBody","videoUrl","transcriptBody","memberPostBody","progressState","privateR2ObjectKeys","signedUrls","buyerEmail","buyerEmailHash"],"writeBoundary":"Issue #181 exposes protected product content readiness metadata only. Issue #185 can return seeded protected fixture bodies only through checkout-intent and entitlement-scoped delivery checks. It does not deliver videos, transcripts, real member posts, progress records, signed URLs, private R2 objects, arbitrary uploaded content, or live fulfillment automation to customers or agents."}}