patx/projectpay

A Heroku ready, invoice maker powered by Stripe and MicroPie with an extremely clean interface.

$ git clone https://gitman.io/git/patx/projectpay

ProjectPay

ProjectPay is a small web app for creating project payment pages and collecting payments through Stripe Checkout. It gives an admin user a private project dashboard, creates shareable payment links for customers, and records successful Stripe payments against each project.

Features

  • Password-protected admin area
  • Create, edit, search, and delete projects
  • Line-item project pricing with scope and terms text
  • Public, tokenized project payment pages
  • Stripe Checkout payment flow
  • Stripe webhook handling for successful payments
  • Payment history and automatic paid/open project status updates
  • MongoDB-backed storage

Tech Stack

  • Python ASGI app built with micropie
  • MongoDB via pymongo
  • Stripe Checkout and webhooks via stripe
  • Uvicorn for local and production serving

Requirements

  • Python 3.10 or newer recommended
  • MongoDB
  • Stripe account, if you want live payment collection

Local Setup

  1. Create and activate a virtual environment:

bash python3 -m venv .venv source .venv/bin/activate

  1. Install dependencies:

bash pip install -r requirements.txt

  1. Start MongoDB locally, or point the app at a hosted MongoDB database.

  2. Create a .env file:

```bash APP_ENV=development ADMIN_PASSWORD=change-me MONGODB_URI=mongodb://localhost:27017 MONGODB_DB=projectpay APP_BASE_URL=http://127.0.0.1:8000 PUBLIC_LOGO_URL= PUBLIC_DARK_LOGO_URL= PUBLIC_LOGO_ALT=ProjectPay Logo PUBLIC_APP_ICON_URL=https://gitman.io/patx/afterdarklabs/raw/docs/favicon.png

STRIPE_SECRET_KEY= STRIPE_WEBHOOK_SECRET= STRIPE_PRODUCT_ID= STRIPE_CURRENCY=usd STRIPE_MINIMUM_AMOUNT_CENTS=100 ```

  1. Run the app:

bash python3 app.py

  1. Open http://127.0.0.1:8000/login and sign in with ADMIN_PASSWORD.

Environment Variables

Variable Required Default Description
APP_ENV Required unset Set to development locally and production for deployed environments. Startup fails if this is missing or unrecognized.
ADMIN_PASSWORD Required outside development admin in development only Password for the admin dashboard. Production startup fails if this is missing or set to admin.
APP_BASE_URL Required outside development Derived from request headers in development only Public base URL used to generate customer payment links and Stripe return URLs.
PUBLIC_LOGO_URL Optional unset Logo image URL shown on public project payment pages. No logo is shown when this is empty.
PUBLIC_DARK_LOGO_URL Optional PUBLIC_LOGO_URL Dark-mode logo image URL shown on public project payment pages. When empty, the normal logo is used.
PUBLIC_LOGO_ALT Optional ProjectPay Logo Alt text for the public payment page logo.
PUBLIC_APP_ICON_URL Optional https://gitman.io/patx/afterdarklabs/raw/docs/favicon.png PNG icon URL used by the web app manifest.
MONGODB_URI Optional mongodb://localhost:27017 MongoDB connection string.
MONGODB_DB Optional invoice_maker MongoDB database name. Use projectpay or another explicit name for new installs.
MONGODB_SERVER_SELECTION_TIMEOUT_MS Optional 5000 MongoDB connection timeout in milliseconds.
LOGIN_RATE_LIMIT_ATTEMPTS Optional 5 Failed login attempts allowed per client IP during the rate-limit window. Set to 0 to disable.
LOGIN_RATE_LIMIT_WINDOW_SECONDS Optional 900 Login rate-limit window in seconds.
STRIPE_SECRET_KEY Required for payments unset Stripe secret API key.
STRIPE_WEBHOOK_SECRET Required for webhook processing unset Signing secret for the Stripe webhook endpoint.
STRIPE_PRODUCT_ID Required for payments unset Stripe Product ID used when creating custom-amount prices.
STRIPE_CURRENCY Optional usd Currency for Stripe Checkout and display formatting.
STRIPE_MINIMUM_AMOUNT_CENTS Optional 100 Minimum customer payment amount in cents.
HOST Optional 127.0.0.1 Host used by python3 app.py. The Heroku Procfile binds Uvicorn to 0.0.0.0 separately.
PORT Optional 8000 Port used by python3 app.py and the included Procfile.

Stripe Setup

  1. Create a Product in Stripe and copy its product ID into STRIPE_PRODUCT_ID.
  2. Add a webhook endpoint that points to:

text https://your-domain.example/webhook/stripe

  1. Subscribe the webhook endpoint to the checkout.session.completed event. If you enable delayed payment methods, also subscribe to checkout.session.async_payment_succeeded.
  2. Copy the webhook signing secret into STRIPE_WEBHOOK_SECRET.
  3. Set STRIPE_SECRET_KEY to your Stripe secret key.

ProjectPay records payments from signed Stripe webhooks. The customer return page may show a thank-you message immediately after Checkout redirects back, but the project balance is updated only after a successful payment webhook is received and processed.

For local webhook testing, use the Stripe CLI:

stripe listen --forward-to localhost:8000/webhook/stripe

Then copy the whsec_... value from the Stripe CLI output into STRIPE_WEBHOOK_SECRET.

Usage

  1. Sign in at /login.
  2. Create a project with a customer name, optional email, line items, and scope or terms.
  3. Open the project detail page and copy the generated payment link.
  4. Send the payment link to the customer.
  5. The customer opens the public project page and clicks Make a Payment.
  6. Stripe Checkout collects the payment.
  7. Stripe sends a webhook back to ProjectPay, and the payment is recorded.

Deployment

The included Procfile runs the app with Uvicorn:

web: uvicorn app:app --host 0.0.0.0 --port $PORT

For production, set at least:

  • APP_ENV=production
  • ADMIN_PASSWORD
  • APP_BASE_URL
  • MONGODB_URI
  • MONGODB_DB
  • STRIPE_SECRET_KEY
  • STRIPE_WEBHOOK_SECRET
  • STRIPE_PRODUCT_ID

Use HTTPS in production so Stripe webhooks, customer payment redirects, and MicroPie's Secure session cookie work reliably. If a local browser does not retain the secure session cookie over plain HTTP, use HTTPS locally or a secure tunnel.

Heroku

The included Procfile already binds Uvicorn to 0.0.0.0 and Heroku's dynamic $PORT. For Heroku, set config vars explicitly:

heroku config:set APP_ENV=production
heroku config:set ADMIN_PASSWORD='replace-with-a-strong-password'
heroku config:set APP_BASE_URL='https://your-app.herokuapp.com'
heroku config:set PUBLIC_APP_ICON_URL='https://gitman.io/patx/afterdarklabs/raw/docs/favicon.png'
heroku config:set MONGODB_URI='mongodb+srv://...'
heroku config:set MONGODB_DB=projectpay
heroku config:set STRIPE_SECRET_KEY='sk_live_...'
heroku config:set STRIPE_WEBHOOK_SECRET='whsec_...'
heroku config:set STRIPE_PRODUCT_ID='prod_...'

On Heroku dynos, login rate limiting uses the final X-Forwarded-For value added by Heroku's router instead of the router's internal connection address.

Customization

  • Set PUBLIC_LOGO_URL, PUBLIC_DARK_LOGO_URL, and PUBLIC_LOGO_ALT to brand the public payment page.
  • Set PUBLIC_APP_ICON_URL to change the icon used by /manifest.json.
  • Update styles in templates/base.html.
  • The current default database name is invoice_maker; set MONGODB_DB=projectpay for a fresh ProjectPay deployment.
  • Currency formatting is optimized for USD. Non-USD currencies display as CURRENCY amount.

Data Model

ProjectPay creates and manages these MongoDB collections:

  • projects
  • payments
  • checkout_sessions
  • webhook_events
  • counters
  • sessions
  • login_attempts

Indexes are created automatically when the app first touches the database.

Security Notes

  • Set APP_ENV explicitly; startup fails if it is missing or misspelled.
  • Do not deploy with APP_ENV=development.
  • Do not deploy with the default ADMIN_PASSWORD=admin.
  • Admin sessions are server-side and stored in MongoDB behind MicroPie's opaque session_id cookie.
  • Browser POST forms use CSRF tokens stored in the server-side session.
  • Login attempts are rate-limited by client IP.
  • Project search treats search text as a literal string before sending it to MongoDB regex queries.
  • Stripe webhook storage keeps minimized event summaries instead of full raw event payloads.
  • Keep Stripe and MongoDB credentials out of source control.
  • The public project URL uses a random share token, but anyone with the link can view the project payment page.

License

ProjectPay is released under the MIT License.