Electronic building permit application for Swiss cantons.
This repository contains the source code for the web applications used to handle electronic building permits and comparable processes in the Swiss cantons of Berne, Grisons, Schwyz, Solothurn and Uri.
The following image shows a high-level overview of the architecture:
ember-ebau-core
.├── compose # docker-compose files
├── db # database Dockerfile and utils
├── django # backend code, containing both API and Caluma
├── document-merge-service # document generation templates and config
├── ember-caluma-portal # Caluma-based portal
├── ember-camac-ng # Ember.js app optimized for embedding in other applications
├── ember-ebau # Ember.js based application for internal area
├── ember-ebau-core # Ember.js addon for code sharing between multiple Ember.js apps
├── keycloak # Keycloak configuration for local development
├── proxy # Nginx configuration for local development
└── tools # miscellaneous utilities
Due to ongoing modernization work, some Frontend modules are not yet integrated in ember-ebau
, but instead are still part of ember-camac-ng
. Few Frontend modules are not part of this repository yet at all. The following table lists the most important modules in the "internal" part of the application and their respective completeness / integration state (in the demo
configuration).
Module | Description | Backend | Frontend | Part of ember-ebau |
---|---|---|---|---|
Main Nav (resource) | ||||
Dossier list | Show a list of dossiers | ✔️ | ✔️ | ✔️ |
Task list | Show a list of tasks | ✔️ | ✔️ | ✔️ |
Templates | Manage document templates (docx) | ✔️ | ✔️ | ✔️ |
Organization / Permissions | Manage own organization and permissions | ✔️ | ✔️ | ✔️ |
Static content | Static content, markdown editor | ✔️ | ✔️ | ✔️ |
Text components | Manage snippets for usage in text fields | ✔️ | ⏳ | ⏳ |
Subnav (instance resource) | ||||
Tasks | View and manage tasks | ✔️ | ✔️ | ✔️ |
Form | View and edit main form | ✔️ | ✔️ | ✔️ |
Distribution | Get feedback from other organizations | ✔️ | ✔️ | ✔️ |
Alexandria | Document management | ✔️ | ✔️ | ✔️ |
Template | Generate document from template | ✔️ | ✔️ | ✔️ |
Journal | Collaborative notebook | ✔️ | ✔️ | ✔️ |
History | Shows milestones and historical data | ✔️ | ✔️ | ✔️ |
Publication | Manage publication in newspaper | ✔️ | ✔️ | ✔️ |
Objections | Manage objections | ✔️ | ✔️ | ✔️ |
Responsible | Assign responsible users | ✔️ | ✔️ | ✔️ |
Claims | Ask applicant for additional info | ✔️ | ✔️ | ✔️ |
Rejection | Reject instance | ✔️ | ✔️ | ✔️ |
Billing | Manage billing entries | ✔️ | ✔️ | ✔️ |
Audit | Perform structured audit | ✔️ | ✔️ | ⏳ |
Audit-Log | Shows form changes | ✔️ | ⏳ | ⏳ |
The preferred development environment is based on Docker.
For local development:
Python:
Ember:
Docker can be used to get eBau up and running quickly. The following script guides you through the setup process. We recommend using the kt_gr
or kt_so
config for now, since other cantons still rely on legacy components for the internal area that are not part of this repository.
make start-dev-env
In case you want to manually modify /etc/hosts following domains need to point to 127.0.0.1 (localhost):
ebau-portal.local ebau.local ebau-keycloak.local ember-ebau.local ebau-rest-portal.local
For automatic checks during commit (formatting, linting) you can setup a git hook with the following commands:
pip install pre-commit
pre-commit install
After, you should be able to use to the following services:
The following administrator accounts are present in Keycloak or the DB, respectively:
Application | Role | Username | Password | Notes |
---|---|---|---|---|
demo | Admin | user | user | |
kt_schwyz | Admin | admin | admin | |
Publikation | adsy | adsy | ||
kt_uri | Admin | admin | admin | |
PortalUser | portal | portal | ||
kt_bern | Admin | user | user | |
kt_gr | Admin | admin | admin | |
Applicant | editor | editor | Applicant editor role | |
Applicant | readonly | readonly | Applicant readonly role | |
kt_so | Admin | admin | admin | |
Applicant | editor | editor | Applicant editor role | |
Applicant | readonly | readonly | Applicant readonly role |
make debug-django
With docker compose you can attach to a running container (basically equivalent to docker compose up
without the -d
flag)
and interact via stdin.
docker compose attach django
This will allow you to
a. send signals to the container
b. drop to a pdb shell when the application runs into a breakpoint
Since the dev config runs the django development-server that reloads on file changes, inserting those breakpoints is effective immediately after saving the file.
press CTRL-p + CTRL-q
NOTE: since by default the attach
process will forward signals to the container you'll have to exit pressing
said sequence (which is the default setting for --detach-keys
and can be overridden). Pressing CTRL-c
however
will not only kill the TTY but also send the SIGINT to the container and stop it.
DOCS: https://docs.docker.com/reference/cli/docker/container/attach/
docker-compose up -d --build db django
cd {ember|ember-camac-ng|ember-caluma-portal|ember-ebau} # Enter ember from the top level of the repo
pnpm install # Install dependencies
pnpm test # Run tests
pnpm start-proxy # Run dev server with proxy to django api
Since this is a large project with lots of files, the default setup of ember will possibly fail to rebuild properly as it can't watch all of those files.
In order to fix that, install watchman as file watcher and
adjust the inotify
settings:
echo fs.inotify.max_user_watches=1000000 | sudo tee -a /etc/sysctl.conf # adjust settings
sudo sysctl -p # re-read config
Make sure that the latter command only returns one value, otherwise the settings is duplicated and needs to be cleaned up.
Note however that the apps ember-caluma-portal
, ember-camac-ng
, ember-ebau
and the addon ember-ebau-core
share the same node modules tree through a pnpm workspace.
The common pnpm workspace allows us to share code (e.g. addons) between the apps which are part of this repo (instead of following the typical approach of publishing releases on npm). This also means that
node_modules
directoryember-caluma-portal
and ember-camac-ng
need to be kept in syncTo enable django-silk
for profiling, simply add DJANGO_ENABLE_SILK=True
to your django/.env
file. Then restart the django container and browse to
http://ebau.local/api/silk/.
To switch from the demo
config to kt_bern
, one has to make sure that the frontend apps take up the right
environment variables.
pnpm start-proxy
make kt_bern
docker-compose up -d && make loadconfig
docker-compose down
make kt_bern
docker-compose build
docker-compose up -d
The remote debugger settings for VS Code are committed to the repository.
.vscode/launch.json
.To enable debugging in the django container the ptvsd server must be started.
Since this debug server collides with other setups (PyCharm, PyDev) it will
only be started if the env var ENABLE_PTVSD_DEBUGGER
is set to True
in
django/.env
.
In order to talk to the /graphql
endpoint with authentication, you can install
a GraphQL Tool (much like Postman). Tools you might consider here:
The GWR module is developed in two separate repositories:
If you use the GWR module, you need to generate a Fernet key according to the documentation of the gwr backend.
You need to set this key in each environment/server in your env file. Generate a separate key for each environment, since this is used to store / read the gwr user passwords.
The API should be designed in a way, that allows it to be used by any eBau project. For needed customization, the following rules apply:
For different feature flags and permissions, see APPLICATIONS
in settings.py.
In development mode, the application is configured to send all email to a Mailpit instance, so unless you specify something else, no email will be sent out from the development environment.
You can access the Mailpit via http://ebau.local/mailpit/ . Any email sent out will be instantly visible there.
Section to collect information on modules and cantons. This section is intended to facilitate know-how transfer, vacation handovers and debugging support cases.
Module used in Kt. SZ and Kt. UR (soon-ish), which accompanies the construction process after the decision. The municipality (up to now only cases are covered where the lead authority is the municipality) and the applicant interact through a series of work-items with documents.
There are construction stages ("Bauetappen"), which consist of dynamically selectable construction steps. Construction steps are a series of work-items, which usually follow the pattern of starting with a work-item addressed to the applicant, followed by one or more work-items addressed to the municipality. The applicant confirms, that they have adhered to the defined regulations, and the muncipality verifies it. The final work-item allows the muncipality to decide whether to continue the process or re-iterate to the beginning of the construction step.
The module is heavily defined by the configured workflow. Which construction steps and therefore which work-items are performed is handled through dynamic tasks. Construction step configuration (such as which task belongs to which construction step) is configured in the meta of tasks belonging to a construction step. Construction steps are essentially a grouping of tasks, there is no model representing them.
Construction stages are a multiple instance work-item with a child-case. The child-case contains the construction step work-items. The first construction stage is created when initializing the construction monitoring process. After that, a new construction stage can be initialized by a create work-item mutation on the existing work-item (in the status ready). BEWARE: To ensure that a new construction stage can always be created as long as the construction monitoring process isn't completed, the construction stage work items remain ready, while the construction stage child case has already been completed.
The core logic is contained mainly in the construction monitoring workflow and form configuration of the canton, the caluma events for the construction monitoring, module settings, some custom visibility and permission logic.
In the canton of Solothurn we use a custom authorization mechanism for the eBau Portal. The eBau portal can only be used with a login from my.so.ch, their eGov portal software. Since they do not offer OIDC authorization, we had to implement a custom solution using Keycloak's token exchange and direct naked impersonation features.
The authorization is designed to retreive an encrypted and signed JWT token which is then converted to a regular OIDC JWT token by Keycloak:
sequenceDiagram
autonumber
participant F as eBau Portal
participant M as eGov Portal
participant B as eBau API
participant K as Keycloak
F->>+M: Redirect to prestation
Note right of M: Encrypted and signed JWT token with user data
M->>-F: Redirect to login with eGov token
F->>+B: Send token (POST to /api/v1/auth/token-exchange)
B-->>B: Decrypt and verify eGov token, extract user data from token
B-->>+K: Create or update user
K-->>B: Return user
B-->>K: Token exchange with direct naked impersonation
K-->>-B: Return token for user
B->>-F: Return token
To enable the feature, the following configuration must be done:
By default Keycloak is already properly configured to support this authorization mechanism. In order to configure another environment, please refer to the documentation
# .env
ENABLE_TOKEN_EXCHANGE=true
This will enable the feature with a dummy eGov portal hosted on our NGINX proxy. In order to test with the eGov portal test environment we need to set some more environment variables (the censored values can be found in Vault):
# .env
EGOV_PORTAL_URL=****
EGOV_PRESTATION_PATH=****
# django/.env
TOKEN_EXCHANGE_JWT_ISSUER=****
TOKEN_EXCHANGE_JWT_SECRET=****
TOKEN_EXCHANGE_JWE_SECRET=****
This project is licensed under the EUPL-1.2-or-later. See LICENSE for details.