Skip to content

Commit 4effe87

Browse files
authored
feat: add backend composed of a Postgres database, Alembic to orchestrate migrations, a PostgREST web server, a message queue built on top of the Postgres database, and async Python jobs implemented by the Dramatiq framework (#1)
1 parent 0000000 commit 4effe87

35 files changed

Lines changed: 2219 additions & 0 deletions

.gitignore

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,34 @@
55
*.mo
66
*.pot
77

8+
# Python byte-compiled / optimized / DLL files
9+
__pycache__/
10+
*.py[cod]
11+
*$py.class
12+
13+
# Python Distribution / packaging
14+
.coverage
15+
.Python
16+
build/
17+
develop-eggs/
18+
dist/
19+
downloads/
20+
eggs/
21+
.eggs/
22+
include/
23+
lib/
24+
lib64/
25+
parts/
26+
sdist/
27+
var/
28+
wheels/
29+
pip-wheel-metadata/
30+
share/python-wheels/
31+
*.egg-info/
32+
.installed.cfg
33+
*.egg
34+
MANIFEST
35+
836
# macOS stuff
937
.DS_Store
1038

.pre-commit-config.yaml

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,3 +50,102 @@ repos:
5050
# Commenting this out because https://github.com/pappasam/toml-sort/issues/11
5151
# - id: pretty-format-toml
5252
# args: [--autofix]
53+
54+
#
55+
# Backend.
56+
#
57+
58+
# Sort imports.
59+
- repo: https://github.com/pycqa/isort
60+
rev: 6.0.1
61+
hooks:
62+
- id: isort
63+
name: Sort import statements
64+
files: ^backend/
65+
args: [--settings-path, backend/develop.toml]
66+
stages: [pre-commit]
67+
68+
# Add Black code formatters.
69+
- repo: https://github.com/ambv/black
70+
rev: 25.1.0
71+
hooks:
72+
- id: black
73+
name: Format code
74+
files: ^backend/
75+
args: [--config, backend/develop.toml]
76+
- repo: https://github.com/asottile/blacken-docs
77+
rev: 1.19.1
78+
hooks:
79+
- id: blacken-docs
80+
name: Format code in docstrings
81+
files: ^backend/
82+
types: [text, python]
83+
args: [--line-length, '120']
84+
additional_dependencies: [black==25.1.0]
85+
86+
# Upgrade and rewrite Python idioms.
87+
- repo: https://github.com/asottile/pyupgrade
88+
rev: v3.20.0
89+
hooks:
90+
- id: pyupgrade
91+
name: Upgrade code idioms
92+
files: ^backend/src/template_jobs/|^backend/tests/
93+
args: [--py313-plus]
94+
95+
# Similar to pylint, with a few more/different checks. For more available
96+
# extensions: https://github.com/DmytroLitvinov/awesome-flake8-extensions
97+
- repo: https://github.com/pycqa/flake8
98+
rev: 7.2.0
99+
hooks:
100+
- id: flake8
101+
name: Check flake8 issues
102+
files: ^backend/src/template_jobs/|^backend/tests/
103+
types: [text, python]
104+
additional_dependencies: [flake8-bugbear==24.12.12, flake8-builtins==2.5.0, flake8-comprehensions==3.16.0, flake8-docstrings==1.7.0, flake8-logging==1.7.0, flake8-mutable==1.2.0, flake8-noqa==1.4.0, flake8-print==5.0.0, flake8-pyi==25.5.0, flake8-pytest-style==2.1.0, flake8-rst-docstrings==0.3.1, pep8-naming==0.15.1]
105+
args: [--config, backend/.flake8]
106+
107+
# Run Pylint from the local repo to make sure venv packages
108+
# specified in pyproject.toml are available.
109+
- repo: local
110+
hooks:
111+
- id: pylint
112+
name: Check pylint issues
113+
entry: pylint
114+
language: python
115+
files: ^backend/src/template_jobs/|^backend/tests/
116+
types: [text, python]
117+
args: [--rcfile, backend/develop.toml]
118+
119+
# Type-check all Python code.
120+
- repo: local
121+
hooks:
122+
- id: mypy
123+
name: Check typing annotations
124+
entry: mypy
125+
language: python
126+
files: ^backend/src/template_jobs/|^backend/tests/
127+
types: [text, python]
128+
args: [--config-file, backend/develop.toml]
129+
130+
# Check for potential security issues.
131+
- repo: https://github.com/PyCQA/bandit
132+
rev: 1.8.3
133+
hooks:
134+
- id: bandit
135+
name: Check for security issues
136+
files: ^backend/src/template_jobs/|^backend/tests/
137+
types: [text, python]
138+
args: [--configfile, backend/develop.toml]
139+
additional_dependencies: ['bandit[toml]']
140+
141+
# On push to the remote, run the unit tests.
142+
- repo: local
143+
hooks:
144+
- id: pytest
145+
name: Run unit tests
146+
entry: env COVERAGE_CORE=sysmon pytest -c backend/develop.toml --cov-config backend/develop.toml backend/src/template_jobs/ backend/tests/ backend/docs/
147+
language: python
148+
verbose: true
149+
always_run: true
150+
pass_filenames: false
151+
stages: [pre-push]

Makefile

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
2+
# Use bash as the shell when executing a rule's recipe. For more details:
3+
# https://www.gnu.org/software/make/manual/html_node/Choosing-the-Shell.html
4+
SHELL := bash
5+
6+
7+
.PHONY: all all-frontend all-backend
8+
all: all-frontend all-backend
9+
all-frontend:
10+
$(MAKE) --directory frontend all
11+
all-backend:
12+
$(MAKE) --directory backend all
13+
14+
15+
.PHONY: init init-frontend init-backend
16+
init: init-frontend init-backend
17+
init-frontend:
18+
$(MAKE) --directory frontend init
19+
init-backend:
20+
$(MAKE) --directory backend init
21+
22+
23+
.PHONY: setup setup-frontend setup-backend
24+
setup: setup-frontend setup-backend
25+
pre-commit install
26+
setup-frontend:
27+
$(MAKE) --directory frontend setup
28+
setup-backend:
29+
$(MAKE) --directory backend setup
30+
31+
32+
.PHONY: check check-frontend check-backend
33+
check: check-frontend check-backend
34+
check-frontend:
35+
$(MAKE) --directory frontend check
36+
check-backend:
37+
$(MAKE) --directory backend check
38+
39+
40+
.PHONY: test test-frontend test-backend
41+
test: test-frontend test-backend
42+
test-frontend:
43+
$(MAKE) --directory frontend test
44+
test-backend:
45+
$(MAKE) --directory backend test
46+
47+
48+
.PHONY: build build-frontend build-backend build-docker build-docker-frontend build-docker-backend
49+
build: build-frontend build-backend build-docker
50+
build-docker: build-docker-frontend build-docker-backend
51+
build-frontend:
52+
$(MAKE) --directory frontend build
53+
build-docker-frontend:
54+
$(MAKE) --directory frontend build-docker
55+
build-backend:
56+
$(MAKE) --directory backend build
57+
build-docker-backend:
58+
$(MAKE) --directory backend build-docker
59+
60+
61+
.PHONY: docs docs-frontend docs-backend
62+
docs: docs-frontend docs-backend
63+
docs-frontend:
64+
$(MAKE) --directory frontend docs
65+
docs-backend:
66+
$(MAKE) --directory frontend docs
67+
68+
69+
.PHONY: compose-up compose-down compose-up-develop compose-down-develop
70+
compose-up:
71+
docker compose --file infra/docker-compose.yaml up
72+
compose-down:
73+
docker compose --file infra/docker-compose.yaml down
74+
compose-up-develop:
75+
docker compose --file infra/docker-compose-develop.yaml up
76+
compose-down-develop:
77+
docker compose --file infra/docker-compose-develop.yaml down
78+
79+
80+
.PHONY: clean clean-frontend clean-backend
81+
clean: clean-frontend clean-backend
82+
rm -fr .coverage .mypy_cache/ # These backend/ files are created at the base of the repo.
83+
clean-frontend:
84+
$(MAKE) --directory frontend clean
85+
clean-backend:
86+
$(MAKE) --directory backend clean
87+
88+
89+
.PHONY: nuke nuke-git-hooks nuke-frontend nuke-backend nuke-caches nuke-caches-frontend nuke-caches-backend
90+
nuke: clean nuke-git-hooks nuke-caches nuke-frontend nuke-backend
91+
nuke-caches: nuke-caches-frontend nuke-caches-backend
92+
nuke-git-hooks:
93+
find .git/hooks/ -type f ! -name '*.sample' -delete
94+
nuke-caches-frontend:
95+
$(MAKE) --directory frontend nuke-caches
96+
nuke-frontend:
97+
$(MAKE) --directory frontend nuke
98+
nuke-caches-backend:
99+
$(MAKE) --directory backend nuke-caches
100+
nuke-backend:
101+
$(MAKE) --directory backend nuke

README.md

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,51 @@
33
# A Full-Stack Web Application Template
44

55
This repository is an opinionated implementation of a full-stack web application template.
6+
7+
## Prerequisites
8+
9+
The following tools should be available on your machine to get started:
10+
11+
- [GNU make](https://www.gnu.org/software/make/) and related GNU tools to run the Makefiles which, in turn, orchestrate checking, building, testing, and deploying the entire software stack.
12+
- [pre-commit](https://pre-commit.com/) to manage various [git hooks](https://git-scm.com/book/en/v2/Customizing-Git-Git-Hooks) to enforce coding standards.
13+
- [commitizen](https://commitizen-tools.github.io/commitizen/) manages automatic version bumps for _semantic versioning_ based on the _conventional commit messages_ in this repository.
14+
- [Docker](https://www.docker.com/) to build and deploy application containers.
15+
16+
## Quick start
17+
18+
After checking out this repository the following steps should stand up the entire stack locally on your machine:
19+
20+
```
21+
make init
22+
. backend/.venv/bin/activate
23+
make setup
24+
make build
25+
make compose-up
26+
```
27+
28+
Now navigate to [localhost:3001](http://localhost:3001/) to read the interactive Swagger documentation for the API…
29+
30+
## Architecture
31+
32+
There are three main componenst in this repository, structured into three directories:
33+
34+
- **Frontend**: TBD. For more details see [here](frontend/README.md).
35+
- **Backend**: the backend is composed of a [PostgREST](https://github.com/PostgREST/postgrest) web server, a message queue based on Postgres, and asynchronous workers implemented in Python using the [Dramatiq](https://github.com/Bogdanp/dramatiq) framework. For more details see [here](backend/README.md).
36+
- **Infrastructure**: both frontend and backend build Docker images which are then orchestrated using [Docker Compose](https://docs.docker.com/compose/). For more details see [here](infra/README.md).
37+
38+
## Development
39+
40+
All of the development — checking and compiling code, running tests, and building Docker images — is managed by `make` and each component has its own Makefile.
41+
42+
To set up this project for development, follow these steps:
43+
44+
1. `make init`: initialize both frontend and backend.
45+
2. `make setup`: set up and install all tools and packages to build and test and run.
46+
3. `make check`: run code checks for both frontend and backend.
47+
4. `make test`: run all tests.
48+
5. `make build`: build both frontend and backend packages, then build the Docker images.
49+
6. `make docs`: generate documentation.
50+
7. `make compose-up` and `make compose-down` stand up and tear down the application locally.
51+
8. `make clean` and `make nuke` reset the build environment and remove all generated artifacts.
52+
53+
More details can be found in the documentation for each of the components.

backend/.flake8

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
# Unfortunately, Flake8 does not support pyproject.toml configuration.
2+
# https://github.com/PyCQA/flake8/issues/234
3+
#
4+
# More details regarding Flake8 and Black interplay:
5+
# https://github.com/psf/black/blob/main/docs/guides/using_black_with_other_tools.md#flake8
6+
[flake8]
7+
8+
# Enable a few additional checks.
9+
#
10+
# https://github.com/PyCQA/flake8-bugbear#how-to-enable-opinionated-warnings
11+
# B9: Bugbear's extended opinionated checks
12+
#
13+
# https://pycodestyle.pycqa.org/en/latest/intro.html#error-codes
14+
# W504: line break after binary operator (Black compliant)
15+
extend-select = B9, W504
16+
17+
# Disable several warnings that don't play nice with PEP8 or Black,
18+
# or that are a bit of a nuisance in general.
19+
#
20+
# http://www.pydocstyle.org/en/latest/error_codes.html
21+
# D105: Missing docstring in magic method
22+
#
23+
# https://pycodestyle.pycqa.org/en/latest/intro.html#error-codes
24+
# E203: whitespace before ‘,’, ‘;’, or ‘:’ (not Black compliant)
25+
# E501: line too long (managed better by Bugbear's B950)
26+
# W503: line break before binary operator (not Black compliant)
27+
#
28+
# https://github.com/peterjc/flake8-rst-docstrings#configuration
29+
# RST307: Error in "XXX" directive
30+
ignore = D105, E203, E501, RST307, W503
31+
per-file-ignores =
32+
33+
# More assorted goodness.
34+
max-line-length = 120
35+
show-source = true
36+
37+
# Ensure that Flake8 warnings are silenced correctly:
38+
# https://github.com/plinss/flake8-noqa#options
39+
noqa-require-code = true
40+
41+
# Ensure that Sphinx extensions of .rst are recognized:
42+
# https://github.com/peterjc/flake8-rst-docstrings#configuration
43+
rst-roles = class, func, ref
44+
rst-directives = envvar, exception
45+
rst-substitutions = version
46+
47+
# Ensure that Sphinx docstrings use Numpy format for docstrings:
48+
# https://github.com/PyCQA/flake8-docstrings
49+
#
50+
# For details on the Numpy format:
51+
# https://www.sphinx-doc.org/en/master/usage/extensions/example_numpy.html
52+
docstring-convention = numpy

backend/LICENSE.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
MIT License
2+
3+
Copyright (c) 1999–2025
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
6+
7+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
8+
9+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

0 commit comments

Comments
 (0)