Skip to content

Content Packs (One-Time Purchases & Downloads) #46

Description

@Niwer1525

Context

Photon currently manages server licenses via Stripe subscriptions. We need to introduce Content Packs: downloadable ZIP files sold separately as one-time purchases via Stripe Checkout, independent of subscription plans.

Key Requirements

  • Admin System: Administrators need a panel to upload and manage content-pack ZIP files and metadata (name, version, category, description).
  • Storage and Delivery: Store files on the server at /downloads/{pack_id}.zip. Deliver them through a protected endpoint that validates ownership.
  • Ownership Tracking: Track user purchases by linking user email/UUID to the content pack ID, including first-download timestamps and claim status. Unlimited copies are allowed.
  • Stripe Integration: Support one-time purchases (price_pack_vX) alongside ongoing subscriptions. Checkout sessions must dynamically route to the correct metadata field based on the product type.
  • Purchase Flow: One-time pack purchases must charge immediately and grant instant download access without a trial period. Display both options on the UI.

Database Schema Suggestions

Table : Packs

    id (TEXT, NOT NULL, PRIMARY KEY)
    name (TEXT, NOT NULL)
    description (TEXT, DEFAULT NULL)
    category (VARCHAR(255))
    stripe_price_id (TEXT, NOT NULL, UNIQUE)
    file_path (TEXT, DEFAULT "/downloads/{id}")
    version_number (TEXT, DEFAULT "1.0")

Table : PackOwnership

    user_email (VARCHAR(50))
    pack_id (TEXT, REFERENCES Packs id ON DELETE CASCADE)
    purchased_at (DATETIME, NOT NULL, DEFAULT CURRENT_TIMESTAMP)
    is_active (BOOLEAN, DEFAULT TRUE)
    PRIMARY KEY (user_email, pack_id)

API Endpoints

  • POST /api/content-packs/upload (Admin): Create/modify a content-pack entry and validate file upload to /downloads/{id}.
  • GET /admin/content-packs/list (Admin): Retrieve all active packs (JSON: name, id, version, category, status).
  • DELETE /api/content-packs/remove/:packId (Admin): Remove pack metadata and delete the file.
  • POST /checkout/create-session-{contentType} (User): Create Stripe session. Metadata must include product type ("subscription" vs "one-time-pack").
  • GET /downloads/{packId} (Owner): Validate ownership via middleware and serve the ZIP file (403 if unauthorized).

Frontend Components

  • Admin Panel: Add a "Content Packs Management" sidebar tab for uploading, listing, and deleting packs.
  • Purchase Page: Display one-time content-pack products alongside standard subscriptions.
  • User Dashboard: Add a section showing the user's claimed downloadable resources with download buttons.

## Metadata and Naming Conventions

  • File naming: {pack_id}.zip (e.g., worlds-v2.zip).
  • Stripe Checkout Metadata payload must look like this:
"client_reference_id": "pk_pack_worlds"
"type": "one-time-pack"
"content_pack_metadata_id": "my-world-packs-v3"

Security Considerations

  • Strict Ownership Validation: The download endpoint must verify the purchase before serving files or redirecting.
  • Rate Limiting: Implement a cap on download requests (e.g., 3 attempts per hour) to prevent link sharing.
  • Scalability: Design the delivery layer so it can easily be swapped to AWS S3 pre-signed URLs or Stripe signed URLs in the future.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions