A webapp for small ecommerce sites. Features include: shopping cart, inventory tracking, Stripe integration, basic admin, login system, and emails.
This is a work in progress. The functionality is somewhat modular; see MODULES.md for more information about how modules work.
- Rainey Arcade (shop module used for virtual products)
- Jade Thompson's art portfolio (gallery module + blog)
- Make an instance for The Rainbow Farm (shop module used for real products)
- Allow different websites with similar functionality to share a codebase
- Example: Website A is an online shop with a blue theme and a gallery to showcase images.
- Example: Website B is an online shop with a red theme and a simple blog.
- Example: Website C is a simple blog with a white theme and a gallery to showcase images.
- Linux
- Python 3.10+
- uWSGI
- Flask
- Huey (a task queuer for sending email)
- SQL-Alchemy
- WTForms
- Stripe
- Webpack
- ReactJS (for the shop & gallery modules)
- See setup.py and package.json for more detail
- Install npm
npm install
in this directory.npm run build
to bundle/compile static resources with Webpack.- Create a Python virtual env, activate it.
sudo apt install python3-venv; python3 -m venv env; source env/bin/activate
- Do
pip install .
in the root of this repo. - Use
python3 scripts/database.py new
to create a new database. - Use the
scripts/dev-backend.sh
shell script to run a development uWSGI server (localhost:5000
). - OR use
python3 -m muffin_shop
for Flask's built-in development server (this will also put Flask in debug mode). - See the readme inside
/install
for help with setting up a production server.
- A
.env
file will auto-generate after the first run. It holds secrets, so keep it safe. - You can also generate the
.env
file by runningpython3 scripts/manage.py init
- Set
CONFIG_PATH
to the instance's config directory (copyconfig/client/skel
for a template) - Note: The skeleton config is a mixture of symlinks and copies to maximize my convenience.
- Example config path:
config/client/<instance_name>
- Create
static/client/<instance_name>
and makecss
,img
,js
dirs as needed for static assets - The
config/client/<instance_name>/modules.json
file defines what modules are loaded and which is the main index.
- Stop running server with
systemctl
. - Go to the root of this repo.
git pull
the new code.- Run
prod-build.sh
to bundle/compile/hocuspocus the JavaScript. - Activate the venv and
pip install .
flask db upgrade
to apply any database migrations.- To use the
flask
command you must haveFLASK_APP
in your environment (the.env
file).
- Run
scripts/dev-frontend.sh
to open a split-pane tmux session with live-reloading backend and frontend. - Run
scripts/dev-backend.sh
for just a live-reloading backend. - Run
python scripts/database.py test --shop
for an example database with products in the shop. - Run
scripts/dev-shop.sh
to replace any existing db with a shop-testing db, and runscripts/dev-frontend.sh
- Systemd starts Nginx and uWSGI
- Nginx serves files from
/static
directly and passes the other requests through to uWSGI - uWSGI creates worker processes each running a Python interpreter. Each worker imports the application callable (Flask object) from
muffin_shop/run.py
. - The WSGI application is created by the Main module, specifically by
create_app
defined inmuffin_shop/helpers/main/app_factory.py
- When uWSGI receives a connection, it picks one of its idle workers and calls the WSGI application in that process.
- Black formatter for Python
- Prettier formatter for everything else
- Except HTML because Jinja templates aren't easy to format
- Unix line endings
- Absolute Python imports only
- route: A URL fragment such as "/" or "/about". Used to create a URL map
- controller: Function that responds to a user request, returning eiher a template (HTML) or JSON
- in Flask terms: a function registered with the decorator
@blueprint.route
which becomes a value in theapp.view_functions
dictionary - in Django terms: a view function (same idea, different boilerplate)
- in Flask terms: a function registered with the decorator
- template: HTML file using Jinja templating engine to embed data injected by the controller
- model: A class-based abstraction on top of database tables, using SQLAlchemy
- form: A class-based abstraction on top of HTML forms which provides validators for the user input, using WTForms
- helper: Pure function that can be shared throughout the codebase
- Files that can be cached / files served traditionally by the web server (e.g., images, CSS, JavaScript)
- Site-specific configuration including logging, modules, html templates, markdown
- This is only for configuration that can be committed to source control
- Note: Site-specific secrets should be in .env files (e.g.,
.env.my_site.production
)
- "Skeleton" for a new site-specific config - basically a ton of symlinks you can selectively replace
- Core pieces of the module system needed by every module
- Entrypoint:
run.py
- Functions registered to routes (URL endpoints) which could return a template or JSON
- Models shape data in the database (using SQLAlchemy)
- Models manipulate data at the request of controllers
- Server-side form validation using WTForms
- Extra helpers for modules such as utility functions, Flask plugins, asynchronous tasks
- React components to be bundled by Webpack (outputs into
/static/js/dist
)