kommunalassist-core 0.5.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- kommunalassist_core-0.5.0/.github/workflows/ci.yml +53 -0
- kommunalassist_core-0.5.0/.github/workflows/publish-pypi.yml +168 -0
- kommunalassist_core-0.5.0/.gitignore +6 -0
- kommunalassist_core-0.5.0/CHANGELOG.md +129 -0
- kommunalassist_core-0.5.0/LICENSE +16 -0
- kommunalassist_core-0.5.0/PKG-INFO +124 -0
- kommunalassist_core-0.5.0/README.md +107 -0
- kommunalassist_core-0.5.0/assist_core/__init__.py +12 -0
- kommunalassist_core-0.5.0/assist_core/adapters.py +67 -0
- kommunalassist_core-0.5.0/assist_core/apps.py +13 -0
- kommunalassist_core-0.5.0/assist_core/dto.py +130 -0
- kommunalassist_core-0.5.0/assist_core/engine.py +556 -0
- kommunalassist_core-0.5.0/assist_core/management/__init__.py +0 -0
- kommunalassist_core-0.5.0/assist_core/management/commands/__init__.py +0 -0
- kommunalassist_core-0.5.0/assist_core/management/commands/assist_rls.py +288 -0
- kommunalassist_core-0.5.0/assist_core/management/commands/seed_feiertage.py +71 -0
- kommunalassist_core-0.5.0/assist_core/mandant.py +89 -0
- kommunalassist_core-0.5.0/assist_core/migrations/0001_initial.py +87 -0
- kommunalassist_core-0.5.0/assist_core/migrations/0002_tenancy_registries_feiertage.py +206 -0
- kommunalassist_core-0.5.0/assist_core/migrations/__init__.py +0 -0
- kommunalassist_core-0.5.0/assist_core/models.py +621 -0
- kommunalassist_core-0.5.0/assist_core/ports/__init__.py +45 -0
- kommunalassist_core-0.5.0/assist_core/ports/base.py +107 -0
- kommunalassist_core-0.5.0/assist_core/regelkatalog/__init__.py +149 -0
- kommunalassist_core-0.5.0/assist_core/registry.py +34 -0
- kommunalassist_core-0.5.0/assist_core/tenancy.py +181 -0
- kommunalassist_core-0.5.0/docs/adr/ADR-001-app-label-und-tabellennamen.md +75 -0
- kommunalassist_core-0.5.0/pyproject.toml +40 -0
- kommunalassist_core-0.5.0/tests/__init__.py +0 -0
- kommunalassist_core-0.5.0/tests/conftest.py +8 -0
- kommunalassist_core-0.5.0/tests/settings.py +44 -0
- kommunalassist_core-0.5.0/tests/test_engine_umzug.py +341 -0
- kommunalassist_core-0.5.0/tests/test_feiertage.py +86 -0
- kommunalassist_core-0.5.0/tests/test_ports.py +53 -0
- kommunalassist_core-0.5.0/tests/test_registry.py +115 -0
- kommunalassist_core-0.5.0/tests/test_rls.py +208 -0
- kommunalassist_core-0.5.0/tests/test_seed_tenant.py +100 -0
- kommunalassist_core-0.5.0/tests/test_serie.py +107 -0
- kommunalassist_core-0.5.0/tests/test_tenancy.py +171 -0
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
# Test-Gate fuer jeden PR + main-Push: Ruff, Tests und makemigrations --check
|
|
4
|
+
# gegen Postgres 16, damit ein Verpackungs-/Migrations-Fehler hier auffaellt
|
|
5
|
+
# statt erst beim Adopter (vgl. publish-pypi.yml, dieselbe Postgres-Konvention).
|
|
6
|
+
|
|
7
|
+
on:
|
|
8
|
+
pull_request:
|
|
9
|
+
push:
|
|
10
|
+
branches: [main]
|
|
11
|
+
|
|
12
|
+
permissions:
|
|
13
|
+
contents: read
|
|
14
|
+
|
|
15
|
+
jobs:
|
|
16
|
+
test:
|
|
17
|
+
name: Ruff, Tests, makemigrations --check
|
|
18
|
+
runs-on: ubuntu-latest
|
|
19
|
+
services:
|
|
20
|
+
postgres:
|
|
21
|
+
image: postgres:16-alpine
|
|
22
|
+
env:
|
|
23
|
+
POSTGRES_USER: test_user
|
|
24
|
+
POSTGRES_PASSWORD: test_pass
|
|
25
|
+
POSTGRES_DB: test_db
|
|
26
|
+
ports:
|
|
27
|
+
- 5432:5432
|
|
28
|
+
options: >-
|
|
29
|
+
--health-cmd pg_isready
|
|
30
|
+
--health-interval 10s
|
|
31
|
+
--health-timeout 5s
|
|
32
|
+
--health-retries 5
|
|
33
|
+
env:
|
|
34
|
+
POSTGRES_HOST: 127.0.0.1
|
|
35
|
+
POSTGRES_PORT: "5432"
|
|
36
|
+
POSTGRES_DB: test_db
|
|
37
|
+
POSTGRES_USER: test_user
|
|
38
|
+
POSTGRES_PASSWORD: test_pass
|
|
39
|
+
steps:
|
|
40
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
|
|
41
|
+
- uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
|
|
42
|
+
with:
|
|
43
|
+
python-version: '3.12'
|
|
44
|
+
- name: Install package + dev deps
|
|
45
|
+
run: pip install -e ".[dev]" 'psycopg[binary]'
|
|
46
|
+
- name: ruff check
|
|
47
|
+
run: ruff check .
|
|
48
|
+
- name: ruff format --check
|
|
49
|
+
run: ruff format --check .
|
|
50
|
+
- name: pytest gegen Postgres
|
|
51
|
+
run: pytest -q
|
|
52
|
+
- name: makemigrations --check (keine fehlenden Migrationen)
|
|
53
|
+
run: python -m django makemigrations --check --settings=tests.settings
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
name: Publish kommunalassist-core to PyPI
|
|
2
|
+
|
|
3
|
+
# Triggert auf Git-Tags v*.*.*. Trusted Publishing (OIDC), kein API-Token-Secret.
|
|
4
|
+
# Setup einmalig: pypi.org/manage/account/publishing/ → GitHub-Trust-Publisher
|
|
5
|
+
# Owner: iilgmbh
|
|
6
|
+
# Repository: iil-assist-core # Repo-Name, NICHT der Projektname
|
|
7
|
+
# Workflow filename: publish-pypi.yml
|
|
8
|
+
# Environment name: pypi
|
|
9
|
+
|
|
10
|
+
on:
|
|
11
|
+
push:
|
|
12
|
+
tags:
|
|
13
|
+
- 'v*.*.*'
|
|
14
|
+
|
|
15
|
+
permissions:
|
|
16
|
+
contents: read
|
|
17
|
+
|
|
18
|
+
jobs:
|
|
19
|
+
build:
|
|
20
|
+
name: Build distribution
|
|
21
|
+
runs-on: ubuntu-latest
|
|
22
|
+
services:
|
|
23
|
+
postgres:
|
|
24
|
+
image: postgres:16
|
|
25
|
+
env:
|
|
26
|
+
POSTGRES_USER: t
|
|
27
|
+
POSTGRES_PASSWORD: t
|
|
28
|
+
POSTGRES_DB: t
|
|
29
|
+
ports:
|
|
30
|
+
- 5432:5432
|
|
31
|
+
options: >-
|
|
32
|
+
--health-cmd pg_isready
|
|
33
|
+
--health-interval 10s
|
|
34
|
+
--health-timeout 5s
|
|
35
|
+
--health-retries 5
|
|
36
|
+
steps:
|
|
37
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
|
|
38
|
+
with:
|
|
39
|
+
fetch-depth: 0
|
|
40
|
+
- uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
|
|
41
|
+
with:
|
|
42
|
+
python-version: '3.12'
|
|
43
|
+
- name: Verify version matches tag
|
|
44
|
+
run: |
|
|
45
|
+
PKG_VERSION=$(grep '^version = ' pyproject.toml | head -1 | sed -E 's/^version = "([^"]+)".*/\1/')
|
|
46
|
+
TAG_VERSION="${GITHUB_REF_NAME#v}"
|
|
47
|
+
echo "pyproject.toml: $PKG_VERSION"
|
|
48
|
+
echo "git tag: $TAG_VERSION"
|
|
49
|
+
if [ "$PKG_VERSION" != "$TAG_VERSION" ]; then
|
|
50
|
+
echo "❌ Version-Mismatch"; exit 1
|
|
51
|
+
fi
|
|
52
|
+
- name: Install build tools
|
|
53
|
+
run: pip install --upgrade build
|
|
54
|
+
- name: Build wheel + sdist
|
|
55
|
+
run: python -m build
|
|
56
|
+
- name: Smoke test (gegen gebautes Wheel, nicht den Quellbaum)
|
|
57
|
+
run: |
|
|
58
|
+
# Gegen das WHEEL testen, nicht gegen src/: ein Verpackungsfehler faellt
|
|
59
|
+
# sonst erst beim Adopter auf. Das Muster stammt aus iil-klickdummy; dort
|
|
60
|
+
# prueft es zusaetzlich mitgelieferte Schema-Dateien. Dieses Paket hat
|
|
61
|
+
# keine package-data, deshalb bleibt der Importtest.
|
|
62
|
+
#
|
|
63
|
+
# ACHTUNG bei Uebernahme: Paketname (Bindestrich) und Modulname
|
|
64
|
+
# (Unterstrich) sind zwei verschiedene Zeichenketten. Genau daran ist der
|
|
65
|
+
# erste Lauf gescheitert -- `iil-klickdummy` war ersetzt, `iil_klickdummy`
|
|
66
|
+
# nicht.
|
|
67
|
+
pip install dist/*.whl 'psycopg[binary]>=3.2'
|
|
68
|
+
# ALLE Module importieren, nicht nur das Top-Level. Bis 0.1.2 zog
|
|
69
|
+
# ports/base.py `apps.adapters.dto` aus dem Herkunfts-Repo -- das Paket
|
|
70
|
+
# war ausserhalb von frist-hub gar nicht importierbar, und `import
|
|
71
|
+
# assist_core` allein hat das nicht gesehen.
|
|
72
|
+
python -c "
|
|
73
|
+
import importlib, django
|
|
74
|
+
from django.conf import settings
|
|
75
|
+
settings.configure(
|
|
76
|
+
INSTALLED_APPS=['django.contrib.contenttypes','django.contrib.auth','assist_core'],
|
|
77
|
+
DATABASES={'default':{'ENGINE':'django.db.backends.postgresql','NAME':'t',
|
|
78
|
+
'USER':'t','PASSWORD':'t','HOST':'127.0.0.1','PORT':'5432'}},
|
|
79
|
+
USE_TZ=True, DEFAULT_AUTO_FIELD='django.db.models.BigAutoField')
|
|
80
|
+
django.setup()
|
|
81
|
+
import assist_core
|
|
82
|
+
for m in ('assist_core.models','assist_core.mandant','assist_core.dto',
|
|
83
|
+
'assist_core.ports','assist_core.regelkatalog'):
|
|
84
|
+
importlib.import_module(m)
|
|
85
|
+
print(' OK', m)
|
|
86
|
+
print('OK: alle Module importierbar, Version', assist_core.__version__)
|
|
87
|
+
"
|
|
88
|
+
|
|
89
|
+
# Ein Importtest sagt NICHT, ob die App benutzbar ist. Version 0.1.0 ging
|
|
90
|
+
# so durch, obwohl migrations/ nur __init__.py enthielt -- installierbar,
|
|
91
|
+
# aber ohne Tabellen. Gegen POSTGRES, nicht SQLite: Regelfreigabe fuehrt
|
|
92
|
+
# zwei JSONField, und SQLite ist bei jsonb und UniqueConstraint mit NULL
|
|
93
|
+
# nachsichtiger als die Zieldatenbank.
|
|
94
|
+
- name: migrate gegen Postgres (Wheel muss seine Tabellen anlegen koennen)
|
|
95
|
+
env:
|
|
96
|
+
PGHOST: 127.0.0.1
|
|
97
|
+
PGPORT: 5432
|
|
98
|
+
run: |
|
|
99
|
+
python -c "
|
|
100
|
+
import django
|
|
101
|
+
from django.conf import settings
|
|
102
|
+
settings.configure(
|
|
103
|
+
INSTALLED_APPS=['django.contrib.contenttypes','django.contrib.auth','assist_core'],
|
|
104
|
+
DATABASES={'default':{'ENGINE':'django.db.backends.postgresql','NAME':'t',
|
|
105
|
+
'USER':'t','PASSWORD':'t','HOST':'127.0.0.1','PORT':'5432'}},
|
|
106
|
+
USE_TZ=True, DEFAULT_AUTO_FIELD='django.db.models.BigAutoField')
|
|
107
|
+
django.setup()
|
|
108
|
+
from django.core.management import call_command
|
|
109
|
+
call_command('migrate', 'assist_core', verbosity=1)
|
|
110
|
+
from django.db import connection
|
|
111
|
+
with connection.cursor() as c:
|
|
112
|
+
c.execute(\"SELECT table_name FROM information_schema.tables WHERE table_schema='public'\")
|
|
113
|
+
tab = sorted(r[0] for r in c.fetchall() if not r[0].startswith('django_'))
|
|
114
|
+
assert tab, 'migrate hat keine Tabellen angelegt'
|
|
115
|
+
fremd = [t for t in tab if not t.startswith('assist_core_')]
|
|
116
|
+
assert not fremd, f'Fremde Tabellennamen im Paket: {fremd} (ADR-001)'
|
|
117
|
+
print('OK: Tabellen angelegt und korrekt benannt:', tab)
|
|
118
|
+
"
|
|
119
|
+
- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
|
|
120
|
+
with:
|
|
121
|
+
name: dist
|
|
122
|
+
path: dist/
|
|
123
|
+
|
|
124
|
+
publish:
|
|
125
|
+
name: Publish to PyPI (Trusted Publishing / OIDC)
|
|
126
|
+
needs: build
|
|
127
|
+
runs-on: ubuntu-latest
|
|
128
|
+
environment: pypi
|
|
129
|
+
permissions:
|
|
130
|
+
id-token: write
|
|
131
|
+
steps:
|
|
132
|
+
- uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
|
|
133
|
+
with:
|
|
134
|
+
name: dist
|
|
135
|
+
path: dist/
|
|
136
|
+
- uses: pypa/gh-action-pypi-publish@dc37677b2e1c63e2034f94d8a5b11f265b73ba33 # release/v1
|
|
137
|
+
with:
|
|
138
|
+
packages-dir: dist/
|
|
139
|
+
|
|
140
|
+
github-release:
|
|
141
|
+
name: GitHub Release
|
|
142
|
+
needs: publish
|
|
143
|
+
runs-on: ubuntu-latest
|
|
144
|
+
permissions:
|
|
145
|
+
contents: write
|
|
146
|
+
steps:
|
|
147
|
+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
|
|
148
|
+
- uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
|
|
149
|
+
with:
|
|
150
|
+
name: dist
|
|
151
|
+
path: dist/
|
|
152
|
+
- uses: softprops/action-gh-release@3d0d9888cb7fd7b750713d6e236d1fcb99157228 # v3
|
|
153
|
+
with:
|
|
154
|
+
name: "kommunalassist-core ${{ github.ref_name }}"
|
|
155
|
+
body: |
|
|
156
|
+
**kommunalassist-core** Release `${{ github.ref_name }}`.
|
|
157
|
+
|
|
158
|
+
Install:
|
|
159
|
+
```
|
|
160
|
+
pip install "kommunalassist-core>=${{ github.ref_name }}"
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
Grundlage: `meiki:ADR-044` (Paket-Topologie) ·
|
|
164
|
+
`meiki:ADR-022` v1.1 (Termin-Engine im Kern) ·
|
|
165
|
+
`meiki:ADR-043` (Produkt- und Verwertungsschnitt)
|
|
166
|
+
files: dist/*
|
|
167
|
+
draft: false
|
|
168
|
+
prerelease: false
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
Alle nennenswerten Änderungen an `kommunalassist-core` (bis 0.4.0 `iil-assist-core`).
|
|
4
|
+
|
|
5
|
+
Format nach [Keep a Changelog](https://keepachangelog.com/de/1.1.0/),
|
|
6
|
+
Versionierung nach [Semantic Versioning](https://semver.org/lang/de/).
|
|
7
|
+
|
|
8
|
+
## [0.5.0] — 2026-09-10
|
|
9
|
+
|
|
10
|
+
**Nur der Verteilname aendert sich: `iil-assist-core` → `kommunalassist-core`.**
|
|
11
|
+
Am Code aendert sich nichts.
|
|
12
|
+
|
|
13
|
+
Der bisherige Name trug den des Anbieters, obwohl das Produkt in einer
|
|
14
|
+
Kommunalverwaltung laeuft, und er kollidierte mit `iil-assist` — so heisst seit
|
|
15
|
+
2026-09-10 auch der Plattform-Mechanismus aus `platform:KONZ-platform-058`. Der
|
|
16
|
+
neue Name nennt den Markt statt des Anbieters, des einzelnen Hauses oder des
|
|
17
|
+
Projekts MEiKI, das endet (Owner-Entscheid 2026-09-10, Variante V1 zu
|
|
18
|
+
[meiki-hub#388](https://github.com/meiki-lra/meiki-hub/issues/388)).
|
|
19
|
+
|
|
20
|
+
**Was ein Adopter tun muss:** eine Zeile in `requirements.txt`. Der Importname
|
|
21
|
+
bleibt `assist_core`, App-Label und Tabellennamen (`assist_core_*`) bleiben
|
|
22
|
+
ebenfalls — dort steht kein Anbietername, und eine Umbenennung haette
|
|
23
|
+
Migrationen gekostet, ohne etwas zu loesen.
|
|
24
|
+
|
|
25
|
+
**Was mit `iil-assist-core` passiert:** Die Fassungen bis 0.4.0 bleiben auf PyPI
|
|
26
|
+
stehen. Sie zurueckzuziehen wuerde nur bestehende Installationen brechen; neue
|
|
27
|
+
Arbeit laeuft unter dem neuen Namen.
|
|
28
|
+
|
|
29
|
+
## [0.4.0] — 2026-09-10
|
|
30
|
+
|
|
31
|
+
Tenancy-Basis, RLS-Erzeuger und Registries (KONZ-meiki-009 U3,
|
|
32
|
+
iilgmbh/iil-assist-core#6 und #5).
|
|
33
|
+
|
|
34
|
+
### Added
|
|
35
|
+
|
|
36
|
+
- `assist_core.tenancy` — `TenantModel`/`TenantManager` fail-closed nach
|
|
37
|
+
platform:ADR-269: ohne aktiven Mandanten liefert der Manager `none()`.
|
|
38
|
+
Cross-Tenant gibt es nur über `all_tenants(grund=...)`, und der Zugriff landet
|
|
39
|
+
in der neuen append-only Tabelle `TenantAuditEintrag`. `tenant_context()` setzt
|
|
40
|
+
denselben Mandanten als Postgres-GUC `app.tenant_id` — **transaktionslokal**
|
|
41
|
+
(`set_config(..., true)`), nicht sessionweit.
|
|
42
|
+
- `manage.py assist_rls --apply|--check [--app-rolle <name>]` — Policy je Tabelle
|
|
43
|
+
mit Mandanten-Spalte, `USING (spalte = NULLIF(current_setting('app.tenant_id',
|
|
44
|
+
true), '')::<cast>)` **ohne** OR-Ausweich-Zweige, plus `FORCE ROW LEVEL
|
|
45
|
+
SECURITY` und `DROP POLICY IF EXISTS` (idempotent). Der Cast kommt aus dem
|
|
46
|
+
Django-Feldtyp (bigint/uuid). `--check` bricht mit Exit ≠ 0 ab, wenn eine
|
|
47
|
+
Policy fehlt oder einen aufmachenden Zweig trägt; `--app-rolle` setzt
|
|
48
|
+
`NOBYPASSRLS` und entzieht der App-Rolle `UPDATE`/`DELETE` auf den
|
|
49
|
+
Audit-Tabellen — append-only wird Rechtelage statt Python-Konvention.
|
|
50
|
+
- Registries als Tabellen: `Verfahren`, `Quellsystem`, `AdapterBindung`
|
|
51
|
+
(je Mandant, unique über `(tenant_id, kennung)` bzw. `(tenant_id, port)`) und
|
|
52
|
+
`Feiertagskalender` (Profil je Kennung, unique über `(kennung, jahr, datum)`).
|
|
53
|
+
Migration `0002_tenancy_registries_feiertage`.
|
|
54
|
+
- `manage.py seed_feiertage --kennung BY --jahr 2026` — Startbestand aus
|
|
55
|
+
`engine.feiertage_bayern_benannt()` als **Daten**, keine YAML im Paket.
|
|
56
|
+
- `assist_core.registry.pruefe_verfahren/pruefe_quellsystem` — Validierung an der
|
|
57
|
+
Grenze gegen die Registry-Tabelle des Mandanten, mit dokumentiertem Fallback
|
|
58
|
+
auf die `dto`-Enums, solange der Mandant keine Zeile gepflegt hat.
|
|
59
|
+
- `assist_core.adapters.resolve(tenant_id, port)` — löst die `AdapterBindung`
|
|
60
|
+
über `importlib` auf, aber nur gegen `settings.ASSIST_ADAPTER_ALLOWLIST`
|
|
61
|
+
(Default leer). Der Kern liefert weiterhin keinen Adapter mit.
|
|
62
|
+
- `engine.feiertage_fuer(tenant_id, jahr)` und `berechne_frist(...,
|
|
63
|
+
feiertage=...)` — der Mandanten-Kalender geht als Menge in die Rechnung.
|
|
64
|
+
`MandantEinstellung.feiertagskalender` (Default `"BY"`) sagt, welches Profil.
|
|
65
|
+
|
|
66
|
+
### Changed
|
|
67
|
+
|
|
68
|
+
- `regelkatalog.seed_entwuerfe(verfahren, pfad=None, tenant_id=None)` setzt
|
|
69
|
+
`tenant_scope_id` **beim Anlegen** und prüft Idempotenz je Mandant (#5). Der
|
|
70
|
+
Host-Workaround (`update()` nach dem Seed) entfällt: er machte die Entwürfe
|
|
71
|
+
kurzzeitig global sichtbar und ließ die Idempotenz-Prüfung eine vorhandene
|
|
72
|
+
globale Zelle für die Haus-Zelle halten.
|
|
73
|
+
- `dto.Verfahren`/`dto.Quellsystem` bleiben als `StrEnum` erhalten, sind aber
|
|
74
|
+
nicht mehr der **Typ** der DTO-Felder — `InboundEvent.quellsystem`,
|
|
75
|
+
`InboundEvent.verfahren_hinweis` und `Vorgang.verfahren` sind jetzt `str`.
|
|
76
|
+
Weil `StrEnum`-Werte `str` sind, brechen bestehende Aufrufer nicht.
|
|
77
|
+
- `ist_werktag()`/`naechster_werktag()` nehmen optional eine Feiertagsmenge;
|
|
78
|
+
ohne Angabe rechnen sie wie bisher mit dem BY-Kalender.
|
|
79
|
+
- README: die bayerischen Feiertage sind nicht mehr als „Produktkonstante nach
|
|
80
|
+
meiki:ADR-043" beschrieben, sondern als Profil je Kennung (KONZ-009 § 3.2).
|
|
81
|
+
|
|
82
|
+
### Hinweis für Konsumenten
|
|
83
|
+
|
|
84
|
+
- `tenant_id` bleibt `BigIntegerField` (platform:ADR-109 Fix B-1, meiki:ADR-025).
|
|
85
|
+
Der Vorschlag, in der ganzen Familie auf UUID zu wechseln (KONZ-meiki-009
|
|
86
|
+
§ 4.1, D-2), ist eine offene Owner-Entscheidung (meiki-hub#390) und wird hier
|
|
87
|
+
**nicht** vorweggenommen. Der Policy-Generator liest den Cast aus dem Feldtyp,
|
|
88
|
+
damit ein späterer Wechsel eine Feldmigration bleibt.
|
|
89
|
+
- Wer die DB-Seite will, muss `tenant_context()` **innerhalb** von
|
|
90
|
+
`transaction.atomic()` betreten. Ohne offene Transaktion wird der GUC bewusst
|
|
91
|
+
nicht gesetzt (ein `set_config(..., true)` im Autocommit gälte nur für eine
|
|
92
|
+
Anweisung) und der Kontextmanager protokolliert eine Warnung.
|
|
93
|
+
- Eine Katalog-Zeile mit `aenderbar_durch: niemand` lässt sich nicht
|
|
94
|
+
mandantengebunden seeden — `Regelfreigabe.clean()` weist das ab (§ 8.2).
|
|
95
|
+
Solche Kataloge werden ohne `tenant_id` importiert.
|
|
96
|
+
- `MandantEinstellung` behält den Standard-Manager (sie wird gelesen, bevor ein
|
|
97
|
+
Mandanten-Kontext existiert), bekommt aber eine RLS-Policy.
|
|
98
|
+
|
|
99
|
+
## [0.3.0] — 2026-09-10
|
|
100
|
+
|
|
101
|
+
### Added
|
|
102
|
+
|
|
103
|
+
- `assist_core.engine` — die Termin-Engine (`berechne_frist`, Feiertags-/
|
|
104
|
+
Werktagslogik für Bayern, Regel-Resolver) zieht aus `frist-hub` in den Kern
|
|
105
|
+
(KONZ-meiki-009 U1, B1). Signaturen unverändert, keine Verhaltensänderung.
|
|
106
|
+
- `assist_core.engine.serie()` — neue Serien-Berechnung (monatlich/quartals-
|
|
107
|
+
weise/jährlich) für StatistikAssist-Meldetermine, inkl. Werktags-Verschiebung.
|
|
108
|
+
- `assist_core.ports.base` — die fünf Ingress-Ports (`IdentityPort`,
|
|
109
|
+
`FachverfahrenPort`, `StatusPort`, `DmsPort`, `ClassificationPort`) ziehen aus
|
|
110
|
+
`frist-hub` in den Kern (KONZ-meiki-009 U1, B2), unverändert übernommen.
|
|
111
|
+
|
|
112
|
+
### Changed
|
|
113
|
+
|
|
114
|
+
- `assist_core.ports.base`-Docstring korrigiert: die Berechnung macht die
|
|
115
|
+
Engine im Kern (`assist_core.engine`), nicht mehr „der konsumierende Assist".
|
|
116
|
+
|
|
117
|
+
### Hinweis für Konsumenten
|
|
118
|
+
|
|
119
|
+
`frist-hub` muss ab `0.3.0` `berechne_frist` und die übrigen Engine-Funktionen
|
|
120
|
+
aus `assist_core.engine` importieren statt aus `apps.fristen.services`, und die
|
|
121
|
+
fünf Ports aus `assist_core.ports` statt aus `apps.adapters.ports`.
|
|
122
|
+
|
|
123
|
+
## [0.2.0]
|
|
124
|
+
|
|
125
|
+
Fachlogik raus, DTOs rein — das Paket wurde eigenständig (siehe Git-Historie).
|
|
126
|
+
|
|
127
|
+
## [0.1.0]
|
|
128
|
+
|
|
129
|
+
Erstbefüllung aus `frist-hub` (meiki-lra/frist-hub#142, M3).
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
Proprietäre Lizenz — IIL GmbH
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 IIL GmbH. Alle Rechte vorbehalten.
|
|
4
|
+
|
|
5
|
+
Dieses Paket ist eine wiederverwendbare Komponente im Sinne von meiki:ADR-043.
|
|
6
|
+
Die Rechte daran verbleiben bei der IIL GmbH.
|
|
7
|
+
|
|
8
|
+
Den Partnern der Kooperationsvereinbarung MEiKI (Landkreis Traunstein,
|
|
9
|
+
Hochschule Neu-Ulm, Technische Hochschule Rosenheim, Landkreis Günzburg) wird
|
|
10
|
+
ein nicht ausschließliches, nicht übertragbares und unentgeltliches
|
|
11
|
+
Nutzungsrecht für Zweck und Dauer des Verbundprojekts eingeräumt, nach dessen
|
|
12
|
+
Ende ein ebensolches für eigene wissenschaftliche Zwecke in Forschung und Lehre.
|
|
13
|
+
Weitergehende Nutzungsrechte werden zu marktüblichen Bedingungen eingeräumt.
|
|
14
|
+
|
|
15
|
+
Maßgeblich ist die Vereinbarung zwischen IIL GmbH und der Hochschule Neu-Ulm
|
|
16
|
+
nach § 7 Abs. 1 der Kooperationsvereinbarung MEiKI.
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: kommunalassist-core
|
|
3
|
+
Version: 0.5.0
|
|
4
|
+
Summary: Kern der Kommunalassist-Familie: Mandant, Termin-Engine (BRMS-Regelwerk mit Freigabe-Workflow), Adapter-Ports
|
|
5
|
+
Author-email: Achim Dehnert <achim.dehnert@iil.gmbh>
|
|
6
|
+
License-Expression: LicenseRef-Proprietary
|
|
7
|
+
License-File: LICENSE
|
|
8
|
+
Requires-Python: >=3.12
|
|
9
|
+
Requires-Dist: django<6.0,>=5.0
|
|
10
|
+
Requires-Dist: pyyaml>=6.0
|
|
11
|
+
Provides-Extra: dev
|
|
12
|
+
Requires-Dist: import-linter>=2.0; extra == 'dev'
|
|
13
|
+
Requires-Dist: pytest; extra == 'dev'
|
|
14
|
+
Requires-Dist: pytest-django; extra == 'dev'
|
|
15
|
+
Requires-Dist: ruff; extra == 'dev'
|
|
16
|
+
Description-Content-Type: text/markdown
|
|
17
|
+
|
|
18
|
+
# kommunalassist-core
|
|
19
|
+
|
|
20
|
+
Der gemeinsame Kern der **Kommunalassist**-Familie: **Mandant**, **Termin-Engine**
|
|
21
|
+
(Regelwerk mit Freigabe-Workflow) und die **Ports** zu Fachverfahren und DMS.
|
|
22
|
+
|
|
23
|
+
> **Namenswechsel 2026-09-10.** Das Paket hiess bis 0.4.0 `iil-assist-core`. Der
|
|
24
|
+
> Verteilname trug den Namen des Anbieters, obwohl das Produkt in einer
|
|
25
|
+
> Kommunalverwaltung laeuft — und er kollidierte mit `iil-assist`, dem
|
|
26
|
+
> Plattform-Mechanismus aus `platform:KONZ-platform-058`. **Der Importname
|
|
27
|
+
> bleibt `assist_core`**, ebenso App-Label und Tabellennamen: dort steht kein
|
|
28
|
+
> Anbietername, eine Umbenennung haette nur Migrationen gekostet und nichts
|
|
29
|
+
> geloest. Aendern muss ein Adopter genau eine Zeile in `requirements.txt`.
|
|
30
|
+
|
|
31
|
+
Grundlage: `meiki:ADR-044` (Paket-Topologie) · `meiki:ADR-022` v1.1 (die
|
|
32
|
+
Termin-Engine gehört in den Kern) · `meiki:ADR-025` (Mandantenfähigkeit).
|
|
33
|
+
|
|
34
|
+
## Warum es dieses Paket gibt
|
|
35
|
+
|
|
36
|
+
Die Termin-Engine hat **zwei** Konsumenten: FristAssist führt Wiedervorlagen,
|
|
37
|
+
StatistikAssist führt Meldetermine. Ein Meldetermin ist eine Frist mit Stichtag —
|
|
38
|
+
dieselbe Rechnung, zwei Zwecke. Läge die Engine hinter FristAssist, bräuchte
|
|
39
|
+
StatistikAssist FristAssist. Genau das schließt der Produktschnitt aus.
|
|
40
|
+
|
|
41
|
+
## Was drin ist
|
|
42
|
+
|
|
43
|
+
| Modul | Inhalt |
|
|
44
|
+
|---|---|
|
|
45
|
+
| `models` | `Regelfreigabe` (Regelwerk mit Zustandsmodell `entwurf → eingereicht → freigegeben → abgelehnt`), `RegelAuditEintrag`, `MandantEinstellung`, `TenantAuditEintrag`, Registries (`Verfahren`, `Quellsystem`, `AdapterBindung`, `Feiertagskalender`) |
|
|
46
|
+
| `tenancy` | `TenantModel`/`TenantManager` (fail-closed), `tenant_context()`, GUC `app.tenant_id` |
|
|
47
|
+
| `registry`/`adapters` | Validierung an der Grenze gegen die Registry-Tabelle; Adapter-Auflösung gegen eine Allowlist |
|
|
48
|
+
| `mandant` | Hauspraxis als Konfiguration — ohne gepflegte Einstellung wird **nichts geraten**, die Renderer liefern `None` |
|
|
49
|
+
| `regelkatalog` | einmaliger Import von Startbeständen. **Keine Betriebsquelle** — im Betrieb gilt allein die Tabelle |
|
|
50
|
+
| `engine` | die Termin-Engine — `berechne_frist()`, Regel-Resolver, `serie()` |
|
|
51
|
+
| `ports` | Schnittstellen zu Fachverfahren und DMS; die konkreten Adapter liegen beim Konsumenten |
|
|
52
|
+
|
|
53
|
+
## Engine
|
|
54
|
+
|
|
55
|
+
`assist_core.engine` ist die **eine Rechenstelle** für Termine (meiki:ADR-022
|
|
56
|
+
v1.1) — zwei Konsumenten (FristAssist, StatistikAssist), eine Implementierung.
|
|
57
|
+
`berechne_frist()` rechnet Fristen nach § 187/188/193 BGB mit Bekanntgabefiktion
|
|
58
|
+
und Bayern-Kalender-Korrektur; `serie()` leitet daraus wiederkehrende
|
|
59
|
+
Meldetermine (monatlich/quartalsweise/jährlich) für StatistikAssist ab. Die
|
|
60
|
+
bayerischen Feiertage (`feiertage_bayern()`, inkl. Mariä Himmelfahrt) sind seit
|
|
61
|
+
`0.4.0` **Startbestand statt Konstante**: Mariä Himmelfahrt gilt nur in Gemeinden
|
|
62
|
+
mit katholischer Mehrheit, das Augsburger Friedensfest nur in Augsburg. Der
|
|
63
|
+
Kalender ist deshalb ein Profil je Kennung (`Feiertagskalender`, Import über
|
|
64
|
+
`seed_feiertage`), das ein Haus kopieren und abweichend pflegen kann
|
|
65
|
+
(KONZ-meiki-009 § 3.2). Der Regel-Resolver liest Fristwerte
|
|
66
|
+
aus der Governance-Tabelle `Regelfreigabe`, mit Code-Katalog-Fallback, solange
|
|
67
|
+
keine Regel gepflegt ist.
|
|
68
|
+
|
|
69
|
+
## Mandant
|
|
70
|
+
|
|
71
|
+
Jede mandantengebundene Tabelle erbt von `assist_core.tenancy.TenantModel`
|
|
72
|
+
(`tenant_id` als `BigIntegerField`, platform:ADR-109). Der Manager ist
|
|
73
|
+
**fail-closed** — ohne aktiven Mandanten `none()`, nicht ungefiltert:
|
|
74
|
+
|
|
75
|
+
```python
|
|
76
|
+
with transaction.atomic(), tenant_context(4711):
|
|
77
|
+
Verfahren.objects.all() # Manager + Policy filtern beide
|
|
78
|
+
# Einziger Cross-Tenant-Pfad, schreibt TenantAuditEintrag:
|
|
79
|
+
Verfahren.objects.all_tenants(grund="Statistik")
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
## RLS
|
|
83
|
+
|
|
84
|
+
`manage.py assist_rls --apply [--app-rolle assist_app]` legt je Tabelle mit
|
|
85
|
+
Mandanten-Spalte eine Policy an — `USING (tenant_id = NULLIF(current_setting(
|
|
86
|
+
'app.tenant_id', true), '')::bigint)`, **ohne** OR-Ausweich-Zweige. Kein Mandant
|
|
87
|
+
heißt keine Zeile; nur `Regelfreigabe` öffnet über `tenant_scope_id IS NULL` die
|
|
88
|
+
globalen Regeln, nie fremde Mandanten. Der GUC ist transaktionslokal, Aufrufer
|
|
89
|
+
brauchen also `transaction.atomic()`. `--app-rolle` setzt `NOBYPASSRLS` und
|
|
90
|
+
entzieht `UPDATE`/`DELETE` auf den Audit-Tabellen; `--check` endet mit Exit ≠ 0,
|
|
91
|
+
wenn eine Policy fehlt oder einen aufmachenden Zweig trägt.
|
|
92
|
+
|
|
93
|
+
## Was **nicht** drin ist
|
|
94
|
+
|
|
95
|
+
Kein Hausinhalt. Keine Regelwerke, keine Vorlagen, keine Mandantenwerte, keine
|
|
96
|
+
Team- oder Fachbereichsbezeichnungen. Nach `meiki:ADR-044` ist alles, was sich je
|
|
97
|
+
Haus unterscheidet, **eine Zeile in Postgres** — nicht Code, nicht YAML.
|
|
98
|
+
|
|
99
|
+
Prüfbar: *ein zweites Haus geht durch Konfiguration und Uploads in Betrieb, nicht
|
|
100
|
+
durch einen Commit.*
|
|
101
|
+
|
|
102
|
+
## App-Label und Tabellennamen
|
|
103
|
+
|
|
104
|
+
`assist_core`, also `assist_core_*`. Kein `db_table` auf die Namen des
|
|
105
|
+
Herkunfts-Repos — siehe `docs/adr/ADR-001`.
|
|
106
|
+
|
|
107
|
+
Entschieden am 2026-09-09 zugunsten eines **echten Renames** statt einer
|
|
108
|
+
Zustands-Migration, weil es noch keinen produktiven Datenbestand gibt. Für das
|
|
109
|
+
Repo, das die Tabellen heute hält (`meiki-lra/frist-hub`), bedeutet das beim
|
|
110
|
+
Umstellen eine Umbenennungs-Migration — beim jetzigen Stand risikoarm, mit
|
|
111
|
+
produktiven Daten wäre sie es nicht. **Das Zeitfenster ist begrenzt.**
|
|
112
|
+
|
|
113
|
+
## CI
|
|
114
|
+
|
|
115
|
+
Jeder PR und jeder Push auf `main` läuft gegen Postgres 16: `ruff check`,
|
|
116
|
+
`ruff format --check`, `pytest` und `makemigrations --check` (siehe
|
|
117
|
+
`.github/workflows/ci.yml`).
|
|
118
|
+
|
|
119
|
+
## Stand
|
|
120
|
+
|
|
121
|
+
`0.4.0` — Tenancy-Basis, RLS-Erzeuger, Registries (KONZ-meiki-009 U3). Noch von
|
|
122
|
+
keinem Repo als Abhängigkeit gebunden. `tenant_id` bleibt `BigIntegerField`;
|
|
123
|
+
der Vorschlag, in der ganzen Familie auf UUID zu wechseln (KONZ-meiki-009 § 4.1,
|
|
124
|
+
D-2), ist offen und hier nicht vorweggenommen.
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
# kommunalassist-core
|
|
2
|
+
|
|
3
|
+
Der gemeinsame Kern der **Kommunalassist**-Familie: **Mandant**, **Termin-Engine**
|
|
4
|
+
(Regelwerk mit Freigabe-Workflow) und die **Ports** zu Fachverfahren und DMS.
|
|
5
|
+
|
|
6
|
+
> **Namenswechsel 2026-09-10.** Das Paket hiess bis 0.4.0 `iil-assist-core`. Der
|
|
7
|
+
> Verteilname trug den Namen des Anbieters, obwohl das Produkt in einer
|
|
8
|
+
> Kommunalverwaltung laeuft — und er kollidierte mit `iil-assist`, dem
|
|
9
|
+
> Plattform-Mechanismus aus `platform:KONZ-platform-058`. **Der Importname
|
|
10
|
+
> bleibt `assist_core`**, ebenso App-Label und Tabellennamen: dort steht kein
|
|
11
|
+
> Anbietername, eine Umbenennung haette nur Migrationen gekostet und nichts
|
|
12
|
+
> geloest. Aendern muss ein Adopter genau eine Zeile in `requirements.txt`.
|
|
13
|
+
|
|
14
|
+
Grundlage: `meiki:ADR-044` (Paket-Topologie) · `meiki:ADR-022` v1.1 (die
|
|
15
|
+
Termin-Engine gehört in den Kern) · `meiki:ADR-025` (Mandantenfähigkeit).
|
|
16
|
+
|
|
17
|
+
## Warum es dieses Paket gibt
|
|
18
|
+
|
|
19
|
+
Die Termin-Engine hat **zwei** Konsumenten: FristAssist führt Wiedervorlagen,
|
|
20
|
+
StatistikAssist führt Meldetermine. Ein Meldetermin ist eine Frist mit Stichtag —
|
|
21
|
+
dieselbe Rechnung, zwei Zwecke. Läge die Engine hinter FristAssist, bräuchte
|
|
22
|
+
StatistikAssist FristAssist. Genau das schließt der Produktschnitt aus.
|
|
23
|
+
|
|
24
|
+
## Was drin ist
|
|
25
|
+
|
|
26
|
+
| Modul | Inhalt |
|
|
27
|
+
|---|---|
|
|
28
|
+
| `models` | `Regelfreigabe` (Regelwerk mit Zustandsmodell `entwurf → eingereicht → freigegeben → abgelehnt`), `RegelAuditEintrag`, `MandantEinstellung`, `TenantAuditEintrag`, Registries (`Verfahren`, `Quellsystem`, `AdapterBindung`, `Feiertagskalender`) |
|
|
29
|
+
| `tenancy` | `TenantModel`/`TenantManager` (fail-closed), `tenant_context()`, GUC `app.tenant_id` |
|
|
30
|
+
| `registry`/`adapters` | Validierung an der Grenze gegen die Registry-Tabelle; Adapter-Auflösung gegen eine Allowlist |
|
|
31
|
+
| `mandant` | Hauspraxis als Konfiguration — ohne gepflegte Einstellung wird **nichts geraten**, die Renderer liefern `None` |
|
|
32
|
+
| `regelkatalog` | einmaliger Import von Startbeständen. **Keine Betriebsquelle** — im Betrieb gilt allein die Tabelle |
|
|
33
|
+
| `engine` | die Termin-Engine — `berechne_frist()`, Regel-Resolver, `serie()` |
|
|
34
|
+
| `ports` | Schnittstellen zu Fachverfahren und DMS; die konkreten Adapter liegen beim Konsumenten |
|
|
35
|
+
|
|
36
|
+
## Engine
|
|
37
|
+
|
|
38
|
+
`assist_core.engine` ist die **eine Rechenstelle** für Termine (meiki:ADR-022
|
|
39
|
+
v1.1) — zwei Konsumenten (FristAssist, StatistikAssist), eine Implementierung.
|
|
40
|
+
`berechne_frist()` rechnet Fristen nach § 187/188/193 BGB mit Bekanntgabefiktion
|
|
41
|
+
und Bayern-Kalender-Korrektur; `serie()` leitet daraus wiederkehrende
|
|
42
|
+
Meldetermine (monatlich/quartalsweise/jährlich) für StatistikAssist ab. Die
|
|
43
|
+
bayerischen Feiertage (`feiertage_bayern()`, inkl. Mariä Himmelfahrt) sind seit
|
|
44
|
+
`0.4.0` **Startbestand statt Konstante**: Mariä Himmelfahrt gilt nur in Gemeinden
|
|
45
|
+
mit katholischer Mehrheit, das Augsburger Friedensfest nur in Augsburg. Der
|
|
46
|
+
Kalender ist deshalb ein Profil je Kennung (`Feiertagskalender`, Import über
|
|
47
|
+
`seed_feiertage`), das ein Haus kopieren und abweichend pflegen kann
|
|
48
|
+
(KONZ-meiki-009 § 3.2). Der Regel-Resolver liest Fristwerte
|
|
49
|
+
aus der Governance-Tabelle `Regelfreigabe`, mit Code-Katalog-Fallback, solange
|
|
50
|
+
keine Regel gepflegt ist.
|
|
51
|
+
|
|
52
|
+
## Mandant
|
|
53
|
+
|
|
54
|
+
Jede mandantengebundene Tabelle erbt von `assist_core.tenancy.TenantModel`
|
|
55
|
+
(`tenant_id` als `BigIntegerField`, platform:ADR-109). Der Manager ist
|
|
56
|
+
**fail-closed** — ohne aktiven Mandanten `none()`, nicht ungefiltert:
|
|
57
|
+
|
|
58
|
+
```python
|
|
59
|
+
with transaction.atomic(), tenant_context(4711):
|
|
60
|
+
Verfahren.objects.all() # Manager + Policy filtern beide
|
|
61
|
+
# Einziger Cross-Tenant-Pfad, schreibt TenantAuditEintrag:
|
|
62
|
+
Verfahren.objects.all_tenants(grund="Statistik")
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## RLS
|
|
66
|
+
|
|
67
|
+
`manage.py assist_rls --apply [--app-rolle assist_app]` legt je Tabelle mit
|
|
68
|
+
Mandanten-Spalte eine Policy an — `USING (tenant_id = NULLIF(current_setting(
|
|
69
|
+
'app.tenant_id', true), '')::bigint)`, **ohne** OR-Ausweich-Zweige. Kein Mandant
|
|
70
|
+
heißt keine Zeile; nur `Regelfreigabe` öffnet über `tenant_scope_id IS NULL` die
|
|
71
|
+
globalen Regeln, nie fremde Mandanten. Der GUC ist transaktionslokal, Aufrufer
|
|
72
|
+
brauchen also `transaction.atomic()`. `--app-rolle` setzt `NOBYPASSRLS` und
|
|
73
|
+
entzieht `UPDATE`/`DELETE` auf den Audit-Tabellen; `--check` endet mit Exit ≠ 0,
|
|
74
|
+
wenn eine Policy fehlt oder einen aufmachenden Zweig trägt.
|
|
75
|
+
|
|
76
|
+
## Was **nicht** drin ist
|
|
77
|
+
|
|
78
|
+
Kein Hausinhalt. Keine Regelwerke, keine Vorlagen, keine Mandantenwerte, keine
|
|
79
|
+
Team- oder Fachbereichsbezeichnungen. Nach `meiki:ADR-044` ist alles, was sich je
|
|
80
|
+
Haus unterscheidet, **eine Zeile in Postgres** — nicht Code, nicht YAML.
|
|
81
|
+
|
|
82
|
+
Prüfbar: *ein zweites Haus geht durch Konfiguration und Uploads in Betrieb, nicht
|
|
83
|
+
durch einen Commit.*
|
|
84
|
+
|
|
85
|
+
## App-Label und Tabellennamen
|
|
86
|
+
|
|
87
|
+
`assist_core`, also `assist_core_*`. Kein `db_table` auf die Namen des
|
|
88
|
+
Herkunfts-Repos — siehe `docs/adr/ADR-001`.
|
|
89
|
+
|
|
90
|
+
Entschieden am 2026-09-09 zugunsten eines **echten Renames** statt einer
|
|
91
|
+
Zustands-Migration, weil es noch keinen produktiven Datenbestand gibt. Für das
|
|
92
|
+
Repo, das die Tabellen heute hält (`meiki-lra/frist-hub`), bedeutet das beim
|
|
93
|
+
Umstellen eine Umbenennungs-Migration — beim jetzigen Stand risikoarm, mit
|
|
94
|
+
produktiven Daten wäre sie es nicht. **Das Zeitfenster ist begrenzt.**
|
|
95
|
+
|
|
96
|
+
## CI
|
|
97
|
+
|
|
98
|
+
Jeder PR und jeder Push auf `main` läuft gegen Postgres 16: `ruff check`,
|
|
99
|
+
`ruff format --check`, `pytest` und `makemigrations --check` (siehe
|
|
100
|
+
`.github/workflows/ci.yml`).
|
|
101
|
+
|
|
102
|
+
## Stand
|
|
103
|
+
|
|
104
|
+
`0.4.0` — Tenancy-Basis, RLS-Erzeuger, Registries (KONZ-meiki-009 U3). Noch von
|
|
105
|
+
keinem Repo als Abhängigkeit gebunden. `tenant_id` bleibt `BigIntegerField`;
|
|
106
|
+
der Vorschlag, in der ganzen Familie auf UUID zu wechseln (KONZ-meiki-009 § 4.1,
|
|
107
|
+
D-2), ist offen und hier nicht vorweggenommen.
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"""kommunalassist-core — der gemeinsame Kern der Kommunalassist-Familie.
|
|
2
|
+
|
|
3
|
+
Was hier liegt, brauchen **mehrere** Assists: die Mandanten-Einstellung, die
|
|
4
|
+
Termin-Engine mit ihrem Regelwerk und Freigabe-Workflow, und die Ports zu
|
|
5
|
+
Fachverfahren und DMS.
|
|
6
|
+
|
|
7
|
+
Grundlage: `meiki:ADR-044` (Paket-Topologie) und `meiki:ADR-022` v1.1 — die
|
|
8
|
+
Termin-Engine hat zwei Konsumenten (FristAssist und StatistikAssist) und darf
|
|
9
|
+
deshalb nicht hinter einem von beiden liegen.
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
__version__ = "0.5.0"
|