aplans is a service for administrating and monitoring action plans. It has the following components:
- admin UI for modifying action plan content
- REST API for distributing the information
The service was first used to implement monitoring for the Carbon-neutral Helsinki 2035 action plan. The ReactJS UI code is also open source.
In the project root directory, create and activate a Python virtual environment:
uv venv
source .venv/bin/activateInstall the required Python packages:
uv syncIf you have access to the Kausal private extensions, you should configure the PyPI index URL in your .envrc file:
export UV_INDEX_KAUSAL_USERNAME=...
export UV_INDEX_KAUSAL_PASSWORD=...Then install the dependencies like this:
uv sync --extra kausalCreate a .env file in your repo root with the following contents. Ask a teammate for the values of AZURE_AD_ variables.
DEBUG=1
DATABASE_URL=postgis:///aplans
AZURE_AD_CLIENT_ID=
AZURE_AD_CLIENT_SECRET=
Build the Kausal extensions:
- Clone the kausal-extensions repo
- Follow the kausal-extensions instructions to build the client
- Create a symlink in the root of kausal-watch-private
ln -s ../kausal-extensions/watch/kausal_watch_extensions .
Collect static files:
python manage.py collectstaticMake sure you have created a Postgres database with the same name (here aplans).
Run migrations:
python manage.py migrateCreate a superuser:
Note: You might need the following translations during the createsuperuser operation: käyttäjätunnus = username, sähköpostiosoite = e-mail
python manage.py createsuperuserTo access the admin UI with the created superuser, create and associate a Person with it:
python manage.py shell_plussuperuser = User.objects.get(email="<email of the superuser you created>")
organization = Organization.objects.get(abbreviation='Kausal') # Found only if database is prepopulated with the help of a coworker
person = Person.objects.create(
user=superuser,
first_name="<first name of your user>",
last_name="<last name of your user>",
email="<email of the superuser you created>",
organization=organization
)
person.save()Compile the translation files:
python manage.py compilemessagesRun the development server, the Admin UI will be available at localhost:8000:
python manage.py runserverNote: the database will be empty, ask a teammate for help to restore your local database from a backup
The project is containerized using Docker Compose. You will still need to set some
variables in your environment; see the first few lines in aplans/settings.py.
In particular, you will need to set the database credentials; for example:
POSTGRES_PASSWORD=change_me
DATABASE_URL=postgis://watch:change_me@db/watch
We use uv to manage dependencies. Invoke uv sync -P <PACKAGE> to upgrade one package,
and uv sync -U to upgrade all of them.
To extract translatable strings and update translations in the locale directory, run the following command (example for the de locale):
python manage.py makemessages --locale de --add-location=file --no-wrap --keep-pot
The option --keep-pot retains the .pot files that can be used as the source files for external translation services.
However, this does not update the translatable strings for the notification templates, which have the extension .mjml. To do this, run the following:
pybabel extract -F babel.cfg --input-dirs=. -o locale/notifications.pot --add-location=file --no-wrap
We use pybabel instead of makemessages because notification templates use Jinja2 and not the Django template language.
To create a new message catalog (.po file) from the generated .pot file, you can run the following (example for the de locale):
pybabel init -D notifications -i locale/notifications.pot -d locale -l de
For subsequently updating this catalog, run the following:
pybabel update -D notifications -i locale/notifications.pot -d locale -l de
The equivalent of compilemessages for the MJML templates is the following (example for the de locale):
pybabel compile -D notifications -d locale -l de