Digital Product Publishing System — Implementation Summary
Date: 2025-10-23
Status: Ready for Implementation
PRD Version: v1.0
Executive Summary
ValkyrAI has 80% of the infrastructure needed to ship a production-grade Digital Product Publishing System. The system leverages existing ThorAPI-generated models, workflows, and ACL security — no major architectural changes required.
What Exists (Foundation)
✅ Data Layer (ThorAPI-Generated)
Product,Invoice,LineItem— Commerce modelsDigitalAsset,DownloadAccess,FileRecord— Fulfillment entitiesProductFunnelWizard,FunnelStage,FunnelTemplate— Funnel generationFileUploadSession— Resumable multipart uploads
✅ Services & APIs
DigitalFulfillmentService— ACL-based download grants + signed URLsFileController—/files/uploads/init,/files/uploads/completeStripeCheckoutModule— Stripe payment integrationStripeWebhookModule— Payment success handlerAclService—/v1/auth/acl/grant,/v1/auth/acl/revokeValkyrWorkflowService— Async workflow orchestration
✅ Frontend (React/RTK Query)
- Auto-generated service hooks for all entities
FileUploadSessionreducers + middlewareProductFunnelWizardhooks
What's Missing (Build Tasks)
1. OpenAPI Schema Enhancements
File: valkyrai/src/main/resources/openapi/api.hbs.yaml
Add to Product schema:
contentDataId(UUID) — Link to uploaded filedeliveryMode(enum) — DIGITAL_DOWNLOAD, STREAMING, LICENSE_KEY, PHYSICALmaxDownloads(integer) — Download limitsexpiresAfterDays(integer) — Entitlement expiry
Regenerate: mvn clean install in thorapi, then valkyrai
2. Backend Services (3 files)
a) DppsOrchestrationService.java
createProductFromUpload(fileRecordId, request)— Wraps file → productpublishProduct(productId, publishRequest)— Creates funnel
b) DppsPurchaseFulfillmentWorkflow.java
- Registers workflow:
DPPS_Purchase_Fulfillment - Tasks: VerifyPayment → GrantAccess → NotifyBuyer → PostPurchase
c) DownloadController.java
GET /v1/download/{downloadAccessId}?validityMinutes=15- Generates signed URLs with ACL checks
- Enforces download limits + expiry
3. ExecModule Wrapper
DigitalFulfillmentModule.java — Workflow-compatible wrapper for existing DigitalFulfillmentService
4. Frontend Components (4 files)
a) FileUploader.tsx
- Drag-drop with
react-dropzone - Resumable uploads via
/files/uploads/init+/files/uploads/complete
b) ProductForm.tsx
- Formik form pre-filled from file metadata
- Calls
useCreateProductMutation()
c) PublishProduct.tsx
- Triggers
useStartFunnelWizardMutation() - Polls for completion, then calls
publishFunnelendpoint
d) DppsWizard.tsx
- Orchestrates multi-step flow: Upload → Product → Publish → Complete
5. Email Template
SQL Migration: V999__dpps_email_templates.sql
Template name: dpps_download_ready
Architecture Decisions
✅ Reuse DownloadAccess (Not DigitalDownload)
Decision: The PRD's DigitalDownload entity is already implemented as DownloadAccess with equivalent functionality:
digitalAssetId(links to product)principalId(buyer)salesOrderLineItemId(purchase record)downloadToken(UUID)downloadCount,maxDownloadsRemaininggrantedAt,expiresAt
No new entity needed.
✅ Funnel Entity: Reuse ProductFunnelWizard
Decision: The PRD's Funnel entity is already implemented as ProductFunnelWizard:
productIdwizardStatus(DRAFT, IN_PROGRESS, COMPLETED)brand,targetAudiencedeliveryMode
No new entity needed.
✅ Workflow Execution Model
Decision: Use existing ValkyrWorkflowService async execution:
executeWorkflow()returnsCompletableFuture- State persisted via
@Transactional(REQUIRES_NEW)helpers - Auth context propagated to async threads
No changes to workflow engine.
✅ ACL Permissions Strategy
Decision: Use existing Spring Security ACL:
- Upload: Asset lands in ACL-protected folder (creator + ROLE_ADMIN + ROLE_SYSTEM)
- Purchase: Grant READ to buyer via
aclService.grantPermission(oid, buyerUsername, BasePermission.READ) - Download: Enforce ACL via
@PreAuthorize("hasPermission(#downloadAccessId, 'DownloadAccess', 'READ')")
No new permission model.
Security Review Checklist
- All asset paths private (never expose raw S3 keys)
- ACL enforced at object level (Product, DigitalAsset, DownloadAccess)
- Download routes require ACL + entitlement
- Signed URLs have TTL ≤ 15 minutes (configurable)
- SecureField/KMS for Stripe keys
- Audit logs on grant/revoke
- Rate limiting on download endpoint (per principal)
Performance Requirements (From PRD)
Upload
- Chunk size: 5-32 MB
- Parallel chunks: ≤ 6
- Exponential backoff on retry
- Resume from last completed chunk
Checkout
- P95 latency: < 2s (entitlement check + signed URL issue)
- Cache positive checks: 60s
- Idempotency keys on payment + entitlement writes
Download
- Signed URL lifetime: 15 minutes (default)
- Refresh flow supported
- Throttling per principal
- P95: < 500ms URL generation
Observability & Metrics
Events to Emit
upload.started,upload.completedproduct.created,product.publishedcheckout.started,checkout.succeeded,checkout.failedentitlement.granteddownload.issued,download.completed
Prometheus Counters
- Upload success rate
- Product creation funnel drop-off
- Checkout conversion rate
- Download link redemption rate
- Error classes (by HTTP status)
Grafana Dashboards
- TTFP (Time-to-First-Product) histogram
- Payment → fulfillment latency
- Download success rate (99.9% SLO)
Testing Strategy
Unit Tests
DppsOrchestrationServicemethodsDownloadControllerACL enforcementDigitalFulfillmentModuleworkflow integration
Integration Tests
- Full flow: Upload → Product → Funnel → Payment → Download
- ACL permissions: Creator, Buyer, Admin roles
- Download limits + expiry handling
- Payment webhook idempotency
E2E Tests
- Upload 100MB file (resume on network failure)
- Stripe test mode payment (live webhook)
- Email delivery via Mailtrap
- Download link redemption (TTL validation)
Rollout Plan
Phase 1 (Dev) — 1 Week
- Deploy to staging
- 3 internal test products
- Measure: upload reliability, P95 latency
- Gate: All acceptance criteria pass
Phase 2 (Beta) — 2 Weeks
- 25 creators invited
- Stripe test mode only
- Add revocation + refund handling
- Gate: < 1% support tickets per 100 orders
Phase 3 (GA) — Ongoing
- Shopify bridge (RestApiModule)
- Multi-file products (FileZipModule)
- Coupons & bundles
- License key generation (LicenseModule)
Success Criteria (From PRD Section 26)
- All acceptance criteria pass in staging (Stripe test mode)
- No mocks remain; only generated services used
- Observability dashboards deployed (Grafana)
- Security review signed off (ACL, TTL, revocation tests)
- Runbooks updated for Support & Ops
- 3 internal products successfully published and purchased
Open Questions (From PRD Section 24)
-
Guest checkout vs. account required?
- Recommendation: Allow guest checkout, auto-create Principal on payment success
-
Default entitlement expiry?
- Recommendation: Perpetual (null expiry), with Product-level override
-
License key generation?
- Phase 2 feature: Add LicenseModule if needed for SaaS products
Implementation Estimate
Complexity: Medium (Incremental)
- Backend: 15-20 hours (3 services + 1 controller + 1 module)
- Frontend: 12-15 hours (4 components + RTK Query wiring)
- Testing: 8-10 hours (unit + integration + E2E)
- DevOps: 5 hours (migrations, env vars, Grafana)
Total: 40-50 hours (1-2 weeks for solo developer)
Next Steps
- Review & Approve PRD — Stakeholder sign-off
- Day 1: OpenAPI schema enhancement → ThorAPI regeneration
- Day 2-3: Backend services (orchestration + workflow + download)
- Day 4-5: Frontend components (wizard + upload + forms)
- Day 6: Integration testing + fixes
- Day 7: Staging deployment + internal dogfood
Reference Documents
- PRD: Original requirement document (26 sections)
- Implementation Plan:
DPPS_IMPLEMENTATION_PLAN.md(detailed) - Quick Start:
DPPS_QUICK_START.md(day-by-day guide) - Tech Context:
ValorIDE_docs/techContext.md - ACL Guide:
web/src/main/resources/templates/typescript-redux-query/README.ACL.md
Risk Mitigation
Risk: Large file upload timeouts
Mitigation: Chunked resumable uploads + CDN ingress endpoints
Risk: Webhook race conditions
Mitigation: Idempotency keys; store provider event IDs; serialize by buyer+invoice
Risk: Leaked links
Mitigation: Short TTL + bound to principal; server verifies ACL & entitlement every time
Definition of Done ✅
- All PRD acceptance criteria pass in staging
- No mocks; only ThorAPI-generated services
- Grafana dashboards live
- Security review complete
- Runbooks updated
- 3 products successfully purchased and downloaded
Status: Ready for Implementation
Estimated Delivery: 2 weeks (with existing foundation)