Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 5 additions & 4 deletions .claude/skills/docs/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,14 +41,15 @@ All run from the `docs/` directory (or with `make -C docs <target>`):
| Command | What it does |
|---|---|
| `make apidocs` | Regenerate all `docs/api/*.rst` from source using sphinx-apidoc. Run this whenever Python modules are added or removed. |
| `make livehtml` | Build docs and serve with live reload at http://localhost:9000. Requires the docs Docker container (`docker compose -f docker-compose.docs.yml up`). |
| `make livehtml` | Build docs and serve with live reload at http://localhost:9000. Run inside the `docs` service (started with `just up`; see `docker-compose.local.yml`). |
| `make clean` | Remove `_build/` and `api/` directories for a fresh build. |
| `make html` | One-off HTML build into `_build/html/`. |

To serve with live reload locally (in Docker):
To serve with live reload locally (in Docker), start the stack so the `docs` service runs (from repo root):
```
docker compose -f docker-compose.docs.yml up
just up
```
The `docs` container runs `make livehtml` via `compose/local/django/start-docs`.

To regenerate API docs locally (sphinx-apidoc must be installed):
```
Expand Down Expand Up @@ -98,7 +99,7 @@ Line length: 88 characters (enforced by ruff). Wrap long docstring lines to stay
- `:class:\`~democrasite.webiscite.models.Bill\`` — class link
- `:func:\`~democrasite.webiscite.tasks.submit_bill\`` — function link
- `:meth:\`~democrasite.webiscite.webhooks.PullRequestHandler.opened\`` — method link
3. Verify the build: `docker compose -f docker-compose.docs.yml up`
3. Verify the build: `just up` and open http://localhost:9000/

### Adding a new Python module
1. Write a module-level docstring at the top of the file
Expand Down
6 changes: 3 additions & 3 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,9 +60,9 @@ Pytest is configured with `--ds=config.settings.test --reuse-db` in `pyproject.t

### Key Patterns

- **Constitution system** (`webiscite/constitution.py`, `constitution.json`): Maps files to protected line ranges. PRs touching protected code become "constitutional" bills requiring supermajority. Line numbers auto-update after merges.
- **Bill lifecycle**: OPEN → APPROVED/REJECTED/FAILED/CLOSED. Each Bill has a OneToOne to a Celery `PeriodicTask` that runs `submit_bill()` at voting period end.
- **Webhook flow** (`webiscite/webhooks.py`): GitHub push events → HMAC validation → create/update `PullRequest` → create `Bill`.
- **Constitution system** (`democrasite/webiscite/constitution.py`, repo-root `constitution.json`): Maps files to protected line ranges. PRs touching protected code become "constitutional" bills requiring supermajority. Line numbers auto-update after merges.
- **Bill lifecycle**: Draft PRs yield `DRAFT` bills until `ready_for_review`; then `OPEN` → APPROVED/REJECTED/FAILED/CLOSED (or `AMENDED` if the PR branch changes during voting). Each Bill has a OneToOne to a Celery Beat `PeriodicTask` that runs `submit_bill()` at voting period end.
- **Webhook flow** (`democrasite/webiscite/webhooks.py`): GitHub `pull_request` webhooks (open, reopen, close, synchronize, ready_for_review, etc.) → HMAC validation → create/update `PullRequest` and `Bill` as appropriate. `push` and `ping` are accepted with minimal handling.
- **Vote constraints**: One vote per user per bill (DB unique constraint). Votes can be changed.
- **Audit trail**: `django-simple-history` tracks changes on key models.

Expand Down
4 changes: 2 additions & 2 deletions CONTRIBUTING.rst
Original file line number Diff line number Diff line change
Expand Up @@ -120,8 +120,8 @@ Creating a Webhook

:obj:`democrasite.webiscite` needs `webhooks`_ to find out about events on
Github. `Create a webhook`_ in your fork of the repository, then generate a
secret key for your hook and store it in your environment (either through your
terminal or ``.env`` file) as ``GITHUB_SECRET_KEY``.
secret key for your hook and store it in ``.envs/.local/.django`` (or your shell) as
``GITHUB_WEBHOOK_SECRET`` so it matches the secret configured on GitHub.

To test your webhook, follow these `instructions`_. (If you have a preferred
tool for exposing your local server, feel free to replace smee with it.) If you
Expand Down
6 changes: 3 additions & 3 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ following the instructions in the guide.
Understanding the repository
^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Check out ``repo_map.txt`` in the root of the repository for a display of the
Check out ``repository_map.txt`` in the root of the repository for a display of the
repository layout and brief explanations for the purpose of each non-obvious file and
directory.

Expand Down Expand Up @@ -114,8 +114,8 @@ Setting up your users
how the site behaves for both kinds of users.

.. _`django-allauth`: https://docs.allauth.org/en/latest/introduction/index.html
.. _`GitHub`: https://django-allauth.readthedocs.io/en/latest/providers.html#github
.. _`Google`: https://docs.allauth.org/en/latest/socialaccount/providers/github.html
.. _`GitHub`: https://docs.allauth.org/en/latest/socialaccount/providers/github.html
.. _`Google`: https://docs.allauth.org/en/latest/socialaccount/providers/google.html

Linting
^^^^^^^
Expand Down
11 changes: 7 additions & 4 deletions docs/howto.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,18 @@ How To - Project Documentation
Get Started
----------------------------------------------------------------------

Documentation can be written as rst files in `democrasite/docs`.
Documentation source files live in the ``docs/`` directory at the repository root.


To build and serve docs, use the commands::
To build and serve docs with live reload, start the local stack (including the ``docs``
service) from the project root::

docker compose -f docker-compose.docs.yml up
just up

The docs container serves Sphinx at http://localhost:9000/ (see ``docker-compose.local.yml``).

Changes to files in `docs` will be picked up and reloaded automatically.
Changes to files under ``docs/`` and under ``democrasite/`` (watched by sphinx-autobuild)
will be picked up and reloaded automatically.

`Sphinx <https://www.sphinx-doc.org/>`_ is the tool used to build documentation.

Expand Down
42 changes: 42 additions & 0 deletions docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,50 @@
Democrasite Documentation
======================================================================


|Built with Cookiecutter Django| |Ruff| |Continuous integration| |Coverage report| |Documentation status|

.. |Built with Cookiecutter Django| image:: https://img.shields.io/badge/built%20with-Cookiecutter%20Django-ff69b4.svg?logo=cookiecutter
:target: https://github.com/pydanny/cookiecutter-django/

.. |Ruff| image:: https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json
:target: //github.com/astral-sh/ruff

.. |Continuous integration| image:: https://github.com/mfosterw/cookiestocracy/actions/workflows/ci.yml/badge.svg
:target: https://github.com/mfosterw/cookiestocracy/actions/workflows/ci.yml

.. |Coverage report| image:: https://codecov.io/gh/mfosterw/cookiestocracy/graph/badge.svg?token=NPV1TLXZIW
:target: https://codecov.io/gh/mfosterw/cookiestocracy

.. |Documentation status| image:: https://readthedocs.org/projects/cookiestocracy/badge/?version=latest
:target: https://cookiestocracy.readthedocs.io/en/latest/?badge=latest


:License: MIT

Democrasite is a website which automatically merges changes based on popular
approval. For more information on the nature and purpose of the project, visit
our `about page`_. This page is meant for people who want to fork the
repository and/or contribute to the project. This project is approximately in beta
development (hence the repository being named "cookiestocracy" - a reference
to cookiecutter and `kakistocracy`_). The alpha version is `here`_ and the
full version doesn't exist yet.

* Homepage:
https://democrasite.dev
* Source code:
https://github.com/mfosterw/cookiestocracy
* Documentation:
https://cookiestocracy.readthedocs.io/en/latest/

.. _`about page`: https://democrasite.dev/about/
.. _`kakistocracy`: https://en.wikipedia.org/wiki/Kakistocracy
.. _`here`: https://github.com/mfosterw/democrasite-testing


.. toctree::
:maxdepth: 2
:titlesonly:
:caption: Contents:

README
Expand Down
12 changes: 8 additions & 4 deletions docs/webiscite.rst
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,14 @@ creates a :class:`~democrasite.webiscite.models.PullRequest` instance.

If the user who created the pull request has a democrasite account, a new
:class:`~democrasite.webiscite.models.Bill`
is created with the information from the pull request and made visible on the
homepage immediately. A :class:`~django_celery_beat.models.PeriodicTask` is
also scheduled to execute :func:`~democrasite.webiscite.tasks.submit_bill`
once the voting period ends.
is created with the information from the pull request. If the pull request is
still a GitHub draft, the bill stays in ``DRAFT`` status (no voting) until the
PR is marked ready for review, which publishes it via
:meth:`~democrasite.webiscite.webhooks.PullRequestHandler.ready_for_review`.
Otherwise the bill is ``OPEN`` on the homepage. A
:class:`~django_celery_beat.models.PeriodicTask` is scheduled to execute
:func:`~democrasite.webiscite.tasks.submit_bill` once the voting period ends
(enabled when the bill leaves ``DRAFT``).

:func:`~democrasite.webiscite.tasks.submit_bill` verifies that the pull
request is still open and that its SHA has not changed since the bill was
Expand Down
37 changes: 28 additions & 9 deletions repository_map.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,14 @@ The documentation in this file is meant to be very brief. If you don't understan
word or are not familiar with a tool, google it!

.
├── .claude // Claude Code agent skills (optional local tooling)
│   └── skills
│   ├── docs
│   │   └── SKILL.md
│   ├── new-bill-feature
│   │   └── SKILL.md
│   └── test-webhook
│   └── SKILL.md
├── .devcontainer // devcontainer files
│   ├── bashrc.override.sh // bash initialization
│   └── devcontainer.json // devcontainer config
Expand Down Expand Up @@ -60,7 +68,7 @@ word or are not familiar with a tool, google it!
│   └── traefik // reverse proxy and load balancer
│   ├── Dockerfile
│   └── traefik.yml
├── config // django configuration and app defintion
├── config // django configuration and app definition
│   ├── settings // django settings files. See https://docs.djangoproject.com/en/dev/ref/settings/
│   │   ├── __init__.py
│   │   ├── base.py // common settings shared between environments
Expand All @@ -78,7 +86,9 @@ word or are not familiar with a tool, google it!
│   │   │   └── activitypub.json
│   │   ├── migrations // database definitions and changes, created by django migration commands
│   │   │   ├── __init__.py
│   │   │   └── 0001_initial.py
│   │   │   ├── 0001_initial.py
│   │   │   ├── 0002_historicalnote_historicallike_historicalperson_and_more.py
│   │   │   └── 0003_alter_person_following.py
│   │   ├── tests
│   │   │   ├── __init__.py
│   │   │   ├── conftest.py // test configuration and fixtures definitions
Expand Down Expand Up @@ -211,7 +221,12 @@ word or are not familiar with a tool, google it!
│   │   │   ├── __init__.py
│   │   │   ├── 0001_initial.py
│   │   │   ├── 0002_remove_bill_submit_task_bill__submit_task.py
│   │   │   └── 0003_vote_unique_user_bill_vote.py
│   │   │   ├── 0003_vote_unique_user_bill_vote.py
│   │   │   ├── 0004_remove_bill_status_changed_and_more.py
│   │   │   ├── 0005_alter_bill_name_alter_historicalbill_name_and_more.py
│   │   │   ├── 0006_remove_bill_unique_open_pull_request_and_more.py
│   │   │   ├── 0007_alter_bill__submit_task.py
│   │   │   └── 0008_alter_bill_status_alter_historicalbill_status.py
│   │   ├── tests
│   │   │   ├── api
│   │   │   │   ├── __init__.py
Expand All @@ -232,29 +247,31 @@ word or are not familiar with a tool, google it!
│   │   ├── apps.py // app definition
│   │   ├── constitution.py // constitution parsing and processing
│   │   ├── context_processors.py // template context processors
│   │   ├── managers.py // custom managers/querysets (e.g. bill annotations)
│   │   ├── models.py // database and ORM object definitions
│   │   ├── tasks.py // asynchronous tasks to run with celery
│   │   ├── urls.py // app url route definitions
│   │   ── views.py // route behavior definitions
│   │   └── webhooks.py // webhook route behavior, e.g. github pr opened
│   │   ── views.py // route behavior definitions
│   │   └── webhooks.py // GitHub webhook handling (pull_request, push, ping)
│   ├── __init__.py
│   └── conftest.py // global test configuration and fixture definitions
├── docs // documentation setup and files
│   ├── api // files automatically generated from source code by apidocs
│   │   ├── *
│   ├── __init__.py
│   ├── conf.py // sphinx configuration file
│   ├── CONTRIBUTING.rst // contributing guide (included in Sphinx toctree)
│   ├── howto.rst // instructions for creating docs
│   ├── index.rst
│   ├── make.bat // build commands for sphinx using windows
│   ├── Makefile // build commands for sphinx
│   ├── readthedocs.db // dummy database for local development
│   ├── README.rst // project overview (mirrors root README for RTD)
│   ├── users.rst
│   └── webiscite.rst
├── locale // translations
│   └── README.rst
├── requirements // python dependencies
│   ├── base.txt // base dependencies shared across enviornments
│   ├── base.txt // base dependencies shared across environments
│   ├── local.txt // local development
│   └── production.txt // production deployment
├── .dockerignore // files not to copy into docker containers
Expand All @@ -263,21 +280,23 @@ word or are not familiar with a tool, google it!
├── .gitignore // files which should not be tracked by git
├── .pre-commit-config.yaml // configuration for linting and checks to run before each commit
├── .readthedocs.yml // configuration for documentation website
├── CLAUDE.md // guidance for Claude Code / AI assistants working in this repo
├── constitution.json // constitution definition, see about page
├── CONTRIBUTING.rst // contributing guide
├── CONTRIBUTORS.txt // list of project contributors. Be sure to add yourself!
│   // dockerfiles for docker compose live in "compose/"
├── docker-compose.local.yml // docker compose configuration for local development
├── docker-compose.production.yml // docker compose configuration for production deployment
├── docker-compose.telemetry.yml // Prometheus, Loki, Tempo, Grafana (expects external compose networks)
├── justfile // command shortcuts for local development NOT using devcontainer
├── LICENSE // Legal permissible uses of the software. MIT license is very liberal
├── manage.py // file for running django management commands
├── pyproject.toml // python tool configuration, incl. pytest, mypy, and ruff
├── README.rst // general info and introduction to project
└── repository_map.txt // documentation about the layout and purpose of the repository (this file!)

63 directories, 228 files // that's kinda a lot ngl
71 directories, 260 files

This file was generated using:
rg --files --hidden --ignore --glob '!.git/' "$@" | tree --fromfile --dirsfirst -a
git ls-files | tree --fromfile --dirsfirst -a
and annotated by hand. Other methods generally ignore too few or too many files.
Loading