Skip to main content

Make Post Sell

The Make Post Sell monolith platform service.

You can use the SaaS or self-host! Accepts credit cards (Stripe), PayPal, Monero (XMR), and Dogecoin (DOGE) payments.

Our blog acts as our user guide & also uses make_post_sell!

Features

  • Multi-tenant SaaS — each shop gets its own subdomain or custom domain

  • Payments — Stripe, PayPal, Adyen, Monero (XMR), Dogecoin (DOGE); payment webhooks verify signatures and fail closed

  • Coupons & Gift Cards — dollar/percent-off coupons with redemption limits; per-shop gift cards with balances and transactions

  • Auctions & Make-an-Offer — eBay-style bidding and negotiated offers per product (pricing_mode), live updates over bounded SSE

  • Shop Home Layouts & Categories — flat grid, filter chips, or sectioned lanes; tags derived linguistically from titles+descriptions (suggest-then-approve, auto-hydrate on edit)

  • Creator Analytics — anonymous page signals (no cookies, no IPs), per-shop and per-product dashboards, referrer/device/engagement metrics

  • Watch Mode — continuous media playback with DJ crossfade transitions, discovery ring, queue management, and autoplay

  • Pop-out Player — draggable media window with keyboard shortcuts, /random and /tv endpoints

  • Email Subscriptions — digest emails (immediately, daily, weekly) with @mention notifications

  • Feeds — RSS, Atom, and sitemap generation per shop

  • AJAX Comments — real-time comment posting without page reload, preserves media playback

  • Related Content — Jaccard similarity ranking with thumbnails

  • Bring Your Own Bucket — shops can point uploads at their own S3-compatible bucket + CDN; media never streams through the app server

  • REST API v1 — HMAC-signed product/content creation and file upload

  • 21-Day Trials — per-shop trial with grandfathering for existing shops

  • Feature Kill Switches — ship features dark, flip per-deployment via env

  • Lazy Carts — in-memory until a product is added, no empty rows from bots

  • CSS Grid Lanes — optional masonry layout per shop

  • Vanilla JS — no jQuery, no framework dependencies; capability-driven presentation (every flow works without JavaScript)

  • Public Domain — all contributed code is placed in the public domain

See CHANGELOG.rst for detailed release history, docs/architecture.md for the feature/ticket matrix, and docs/roadmap-scale-and-operators.md for the current audit findings and prioritized roadmap (scale readiness, operator tooling, profitability).

Quick Start: Operating a Server with PyPI or Source Code

Before you start, navigate to the directory where you want to install make_post_sell database & files.

This Makefile-based workflow lets you choose between installing make_post_sell from PyPI packages or directly from the source code (editable mode). Both flows create a virtual environment in ./env and store configuration and SQLite data in the persistent ./data directory.

  1. Install make_post_sell

    • PyPI Installation: Download the Makefile and run:

      wget "https://git.unturf.com/engineering/make-post-sell/make_post_sell/-/raw/master/Makefile"
      make install-from-pypi
    • Source Installation (Editable Mode): Clone the repository and run:

      git clone ssh://git@git.unturf.com:2222/engineering/make-post-sell/make_post_sell.git
      make install-from-source
    • Production Installation (Non‑Editable): For production use (non‑editable even from source), run:

      git clone ssh://git@git.unturf.com:2222/engineering/make-post-sell/make_post_sell.git
      make install-from-source-prod
  2. Activate the Virtual Environment

    Before running any commands, activate the virtual environment:

    source env/bin/activate
  3. Start the Development Server

    You’ll want to configure the system in data/development.ini.

    Typically I control most stuff with environment vars, for example vars.sh:

    # boto3 style credentials for s3/digital-ocean spaces.
    # this is for storing content & physical products.
    export MPS_APP_MAIN_BUCKET="removed"
    export MPS_APP_SECURE_UPLOADS_ACCESS_KEY="removed"
    export MPS_APP_SECURE_UPLOADS_SECRET_KEY="removed"
    
    # stripe keys for collecting credit cards & crypto.
    # NOTE: These are used by tests, shops configure their own keys in the UI
    export MPS_TEST_STRIPE_PUBLIC_API_KEY="pk_test_removed"
    export MPS_TEST_STRIPE_SECRET_API_KEY="sk_test_removed"
    
    # the root domain acts as a SaaS for many shop domains!
    export MAKE_POST_SELL_ROOT_DOMAIN="example.com"
    export MAKE_POST_SELL_ROOT_URL="http://example.com:6501"
    
    # optional: email for the root domain owner
    export MAKE_POST_SELL_DOMAIN_OWNER_EMAIL="admin@example.com"
    
    # optional: DKIM email signing (commented out by default)
    # export MPS_APP_DKIM_PRIVATE_KEY_PATH="/path/to/dkim/private.key"
    # export MPS_APP_DKIM_SELECTOR="selector"
    
    # production: Stripe webhook signing secret. Payment webhooks
    # fail closed — without this, Stripe webhook recovery (unlocking
    # purchases when a checkout dies after the charge) returns 403.
    # export MPS_STRIPE_WEBHOOK_SECRET="whsec_..."

    With the virtual environment active, start the server:

    source vars.sh
    make serve

    Then browse to http://127.0.0.1:6501/ to view the app.

Running Tests

We use pytest (parallel via pytest-xdist, isolated DB per worker). Tests need environment variables (Stripe test keys etc.), so source them first:

source vars.sh
make test

The suite has three layers, and new features are expected to land with coverage in all three: unit (test_models.py, no DB), integration (test_integration.py), and functional (test_functional.py, full WSGI app through webtest).

SQL Migrations

If your deployment is brand new, you don’t need to run any migrations.

Otherwise, it should be safe to run this at anytime to catch your database up (make backup-db first — it’s cheap):

make backup-db
make migrate

To look at the current revision and the history:

make migration-status

To cut a new migration script:

make migration m="add foo column to bar table"

Always use make migration — it autogenerates a cryptographically unique revision ID by comparing your models against the database. Never hand-write a migration file or invent a revision ID; a made-up ID corrupts the migration chain and breaks deploys everywhere.

Two rules for editing the generated script before you commit it:

  • Migrations must be idempotentmake init-db creates all tables from models, so guard create_table with a table-exists check and add_column with a column-exists check (copy the _table_exists / _column_exists helpers from any recent file in make_post_sell/scripts/alembic/versions/).

  • SQLite needs server_default="..." (raw SQL string) for NOT NULL columns added to existing tables — default= does nothing for existing rows.

misc

You may source the new Python virtual environment during development:

# source env/bin/activate.fish
. env/bin/activate

Python Pyramid Shell

If you want to use an interactive Python interpreter to interact with Make Post Sell app/models & DB:

pshell development.ini

For example, we needed to migrate production data using this script:

# begin the database transaction.
request.tm.begin()

suses = models.stripe_user_shop.get_all_stripe_user_shop_objects(request.dbsession)
for sus in suses:
    try:
        sus.active_card_id = sus.stripe_customer_default_source.id
        request.dbsession.add(sus)
    except AttributeError:
        pass

# flush / commit all changes stored the the sqlachemy session.
request.dbsession.flush()

# commit/close the database transaction to really make changes.
request.tm.commit()

Contributing

  • Establish communication with Russell or another admin to bless your git.unturf.com gitlab account & put you into the proper roles.

  • Russell should see your account request but due to spam you have to ask him directly for approval via email or some other means of comms.

  • Clone repo & make commits

  • Create merge requests, we automatically run the unit & headless functional tests on each commit

  • On merge we release to the production site & see the change across users.

  • If you touch requirements.py3.txt, run make pins-lock and commit the regenerated requirements-prod.lock in the same MR — CI builds the production virtualenv from the lock file, so a forgotten lock ships an artifact missing your dependency (tests still pass; prod imports fail).

Optionally, format your code.

This is not set in stone, but if you want to use a formatter this is the path for now!

Python

black (manual)

Jinja2

None (not needed, neither is an HTML formatter)

JavaScript

Prettier or biome (manual)

CSS

Prettier or biome (manual)

Licence

All contributed code is placed in the public domain.

source code: https://git.unturf.com/engineering/make-post-sell/make_post_sell

MakePostSell & make-post-sell are trademarked, do not misrepresent the brand.

Feel free to white label any code or themes into your own brand.

Original Developer: Russell Ballestrini

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

make_post_sell-1.5.1.tar.gz (891.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

make_post_sell-1.5.1-py3-none-any.whl (1.0 MB view details)

Uploaded Python 3

File details

Details for the file make_post_sell-1.5.1.tar.gz.

File metadata

  • Download URL: make_post_sell-1.5.1.tar.gz
  • Upload date:
  • Size: 891.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/5.1.1 CPython/3.12.3

File hashes

Hashes for make_post_sell-1.5.1.tar.gz
Algorithm Hash digest
SHA256 9ffe79067fd1e97908b36ab110f3ee6ce54a7c15afa8b94e7a4b386f96e49f85
MD5 2fd02971c53b25047970092f56de7f50
BLAKE2b-256 8e86d6fe3e0f428a693d671be6426a33bfb300defdbe04d79702407ea0b3c3d4

See more details on using hashes here.

File details

Details for the file make_post_sell-1.5.1-py3-none-any.whl.

File metadata

  • Download URL: make_post_sell-1.5.1-py3-none-any.whl
  • Upload date:
  • Size: 1.0 MB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/5.1.1 CPython/3.12.3

File hashes

Hashes for make_post_sell-1.5.1-py3-none-any.whl
Algorithm Hash digest
SHA256 cd234869e98874b7d4f46f748ba4f4e3ee1698898640186d017ca2ed686392df
MD5 0b1031f148cee37419af932fd27201eb
BLAKE2b-256 c43e198ecd6871abc19f7348e8b5bd14ccb08fb5bc7f0949b1f6246169977e2b

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page