Developmentο
Code Quality, Conventional Commits, and Releasesο
Code quality is maintained by pre-commit hooks and .vscode/settings.json
locally; then also enforced with GitHub Actions in the remote repository.
Python scripts are required to follow
black
code style.HTML, CSS, and Javascript files are checked with
prettier
.Markdown files are checked with
markdownlint
.
Commit messages are required to follow the conventional commits standard. This is enforced by the commitlint
pre-commit hook and the CI/CD pipeline.
The release process is automated with GitHub Actions. When a new tag is pushed, the CI/CD pipeline will automatically build and deploy the app to the production server based on the semantic release standards, and create a Changelog file with the changes since the last release.
Developing in Dev Containersο
Dev Containers are a the recommended way to develop this project. You simply clone this repository and open it in VS Code. Make sure that the Docker daemon is running, then use >Dev Containers: Reopen in Container
command in VS Code. This will create containers with the following applications:
- Flask
Accessible at
https://localhost:5000
. It uses the self-signed SSL certificate generated in.devcontainer/ssl
. Never use these certificates for production!This is where the app runs. It is based on the official Python image with the packages from
requirements.txt
installed.It also has additional packages installed for development, such as
black
,pytest
, andpre-commit
.
- pgAdmin
Accessible at
http://localhost:5002
. You can use this to manage the Postgres database.It is already configured to connect to the Postgres container. When prompted for the database password, use
password
.
- Postgres
When Flask is initialized, it will create the tables in this database.
If you need to access the database, it is available at
localhost:5432
.
Debuggingο
The configuration in .vscode/launch.json
allows us to use the VSCode debugger to set breakpoints and inspect variables. The Flask instance run this way will be available at http://localhost:5001
.
Testing Stripe Webhooksο
For testing with Stripe, youβll need to get the webhook secret (whsec_...
) using this Stripe CLI command:
stripe listen --forward-to https://localhost:5000/app/webhook --skip-verify
If you want to test subscription events used by this app, run the following to make stripe CLI listen and forward the following events:
customer.subscription.updated
customer.subscription.deleted
stripe listen -e customer.subscription.updated,customer.subscription.deleted,checkout.session.completed --forward-to https://localhost:5000/app/webhook/stripe --skip-verify
This returns the webhook signing secret we use to verify that Stripe
is the one sending webhook requests. This secret needs to be saved in
the .env
file as shown in .env.template
.
Hint
Some of the functionality will not work in your local development environment without having this listener forward the events from Stripe to the local instance of this app. For example, the account balance will not increment as this depends on the event from Stripe.
Developing in a Virtual Environmentο
I do not recommend using a virtual environment for development, but here is the legacy documentation I had for it before I switched to devcontainers.
Clone the repo, navigate to the repo directory,
Create a virtual environment:
python -m venv env
Activate the virtual environment:
For Windows:
env\Scripts\activate
For macOS/Linux:
source env/bin/activate
Install the dependencies inside the virtual environment:
pip install -r requirements.txt
Set the environment variables listed in the
.env.template
fileGenerate a self signed SSL certificate for using https locally. On Linux or with WSL in the root path:
openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -days 365 -nodes
Run
flask run
How to Build On Top of This Appο
Adding New Pagesο
In both
public
andprivate
directories, you can copy thesample-page.html
as a starter and rename it (e.g.Βtest.html
). The generic routing inviews.py
will automatically be served at/test
directory.Update the page title at
{% set page_title = "Sample Page" %}
.Insert a link to this page in
components/header/nav-menu.html
. For the active page highlighting, we also need to update the path for active link condition in this class:class="nav-link {% if path == 'sample-page' %}active{% endif %}"
.Insert content between
{% block content %}
and{% endblock content %}
as needed.
Note that URLs with trailing slashes (e.g.Β /test/
) are redirected to
the alternatives without one (e.g.Β /test
).
Defining More Configuration Variablesο
If you need to have more config variables (e.g.Β credentials for a new OAuth provider):
Define environment variables for them both in your local
.env
file and in prod,In
app/config.py
, add a new attribute for theConfig
class. Use theconfig
method from decouple.You can then call the config value anywhere in the app as
app.config[""]
.
Updating Dependenciesο
To include new Python packages, you can first install them in your local
virtual environment during development. Before pushing a change with a
new package, also update the dependencies using
pip freeze > requirements.txt
.