waffensachkunde
Waffensachkunde – Lernsoftware für die Sachkundeprüfung nach § 7 WaffG. Barrierefrei, offline, EUPL-1.2.
| 1 | # ===================================================================== |
| 2 | # electron-builder – Paketierung für Windows (NSIS) und macOS (DMG) |
| 3 | # --------------------------------------------------------------------- |
| 4 | # CODE-SIGNIERUNG IST BEWUSST DEAKTIVIERT. |
| 5 | # Die Anwendung wird privat weitergegeben, es gibt kein Entwicklerzertifikat. |
| 6 | # Folgen, die den Nutzenden erklärt werden müssen: |
| 7 | # - Windows SmartScreen zeigt beim ersten Start „Windows hat Ihren PC |
| 8 | # geschützt“ → „Weitere Informationen“ → „Trotzdem ausführen“. |
| 9 | # - macOS Gatekeeper blockiert die App → Rechtsklick auf die App → |
| 10 | # „Öffnen“ → im Dialog erneut „Öffnen“ (bzw. Systemeinstellungen → |
| 11 | # Datenschutz & Sicherheit → „Dennoch öffnen“). |
| 12 | # ===================================================================== |
| 13 | |
| 14 | appId: de.willerding.waffensachkunde |
| 15 | productName: Waffensachkunde Lernsoftware |
| 16 | copyright: © 2026 Olaf Willerding |
| 17 | |
| 18 | directories: |
| 19 | output: release |
| 20 | # Bewusst NICHT "build": die .gitignore im Projektwurzelverzeichnis |
| 21 | # ignoriert `build/`, dort abgelegte Icons würden also nie eingecheckt. |
| 22 | # Icons gehören nach build-resources/ (icon.ico für Windows, |
| 23 | # icon.icns bzw. icon.png >= 512x512 für macOS). |
| 24 | buildResources: build-resources |
| 25 | |
| 26 | # Nur die gebauten Bundles paketieren – die Quellen bleiben draußen. |
| 27 | # |
| 28 | # ACHTUNG, DIESE LISTE STEHT DREIMAL: hier und noch einmal unter `win:` und |
| 29 | # unter `mac:`. Das ist kein Versehen, sondern der Umgang mit einer Falle von |
| 30 | # electron-builder: Eine plattformeigene `files:`-Liste ERSETZT diese hier, |
| 31 | # statt sie zu ergänzen – und besteht sie ausschließlich aus |
| 32 | # Ausschlussmustern, stellt die Bibliothek ihr `**/*` voran |
| 33 | # (`containsOnlyIgnore` in app-builder-lib/out/fileMatcher.js). Bis Fassung |
| 34 | # 0.27.2 trugen beide Plattformblöcke nur je ein `!`-Muster; das ausgelieferte |
| 35 | # `app.asar` enthielt deshalb 592 Dateien statt der fünf aus `out/`, darunter |
| 36 | # `src/`, `tests/`, `e2e/`, `tools/`, alle tsconfig-Dateien und den |
| 37 | # HTML-Abdeckungsbericht des letzten Gate-Laufs (`coverage/`, 217 Dateien, |
| 38 | # 8.967.480 Byte). `app/tests/paketstand.test.ts` hält die drei Listen |
| 39 | # deckungsgleich; `app/e2e/gepackt.spec.ts` sieht am gebauten Paket nach. |
| 40 | files: |
| 41 | - out/**/* |
| 42 | - package.json |
| 43 | - '!**/*.map' |
| 44 | - '!**/{.eslintrc,.editorconfig,.prettierrc}' |
| 45 | - '!**/{test,tests,__tests__,e2e}/**' |
| 46 | # Die C-Quellen von better-sqlite3 – die SQLite-Amalgamation und der |
| 47 | # Aufsatz darauf. Nachgemessen 9,9 MiB (deps) plus 162 KiB (src) in jedem |
| 48 | # Paket, die nie jemand ausführt: `npmRebuild: false` weiter unten schaltet |
| 49 | # den Bau aus der Quelle ab, und `lib/binding.js` lädt ausschließlich eine |
| 50 | # fertige Datei aus `prebuilds/`. Bis Fassung 0.24.1 wurden sie mitgepackt. |
| 51 | - '!**/node_modules/better-sqlite3/{deps,src}/**' |
| 52 | - '!**/node_modules/better-sqlite3/binding.gyp' |
| 53 | |
| 54 | # Der amtliche Fragenkatalog liegt außerhalb von app/ und wird als Ressource |
| 55 | # mitgepackt. Ziel ist <app>/resources/katalog/ – genau dort sucht |
| 56 | # src/main/katalog.ts, wenn app.isPackaged true ist. Bewusst NICHT im |
| 57 | # asar-Archiv: so bleiben katalog.json und die Prüfzeichen normale Dateien, |
| 58 | # die mit fs gelesen werden können. |
| 59 | extraResources: |
| 60 | - from: ../content/katalog |
| 61 | to: katalog |
| 62 | filter: |
| 63 | - '**/*' |
| 64 | # Erklaerungen zu den Fragen. Eigener redaktioneller Inhalt, deshalb |
| 65 | # getrennt vom amtlichen Katalog; src/main/erklaerungen.ts sucht die |
| 66 | # Datei im gepackten Betrieb direkt unter <app>/resources/. |
| 67 | - from: ../content/erklaerungen.json |
| 68 | to: erklaerungen.json |
| 69 | # Glossar der Fachbegriffe (WCAG 3.1.3 und 3.1.4). |
| 70 | - from: ../content/glossar.json |
| 71 | to: glossar.json |
| 72 | # Die zitierten Normtexte. Ohne sie führte „Im Gesetz nachlesen" ins Leere: |
| 73 | # Eine vollständig offline arbeitende Software forderte zu etwas auf, das |
| 74 | # offline gerade nicht ging. Erzeugt aus content/gesetze/index.json mit |
| 75 | # data-pipeline/normtexte_bauen.py – und nur die zitierten Normen, denn der |
| 76 | # Index führt die sieben Gesetze vollständig, auch katalogfremde Normen. |
| 77 | # Gesetzestexte sind nach § 5 Abs. 1 UrhG gemeinfrei. |
| 78 | - from: ../content/normtexte.json |
| 79 | to: normtexte.json |
| 80 | # Die redaktionelle Feingliederung der Kapitel II bis IV. Der amtliche |
| 81 | # Katalog gliedert nur Kapitel I in Abschnitte; ohne diese Datei laesst sich |
| 82 | # von 230 Fragen nur das ganze Kapitel ueben. |
| 83 | - from: ../content/themen.json |
| 84 | to: themen.json |
| 85 | # Deutsche Fassung der EUPL 1.2 und die Übersicht der Fremdkomponenten. |
| 86 | # Beide zeigt der Bereich „Über diese Software“ an; MIT, BSD und Apache |
| 87 | # verlangen die Mitlieferung ihrer Texte. Ziel ist jeweils |
| 88 | # <app>/resources/ – genau dort sucht src/main/lizenzen.ts im gepackten |
| 89 | # Betrieb. |
| 90 | - from: ../LICENSE.de.txt |
| 91 | to: LICENSE.de.txt |
| 92 | - from: ../content/drittlizenzen.json |
| 93 | to: drittlizenzen.json |
| 94 | # Die Datenschutzerklärung, erzeugt aus docs/datenschutz.md über |
| 95 | # tools/datenschutz_anwendung.py. Bis 0.24.2 war sie in der Anwendung |
| 96 | # nirgends erreichbar: docs/ wird nicht mitgeliefert, und der einzige Weg |
| 97 | # nach außen führt zur Unterstützungsseite. src/main/datenschutz.ts sucht |
| 98 | # die Datei im gepackten Betrieb direkt unter <app>/resources/. |
| 99 | - from: ../content/datenschutz.json |
| 100 | to: datenschutz.json |
| 101 | |
| 102 | # better-sqlite3 ist ein natives Modul und muss außerhalb des asar-Archivs |
| 103 | # liegen, damit der Prozess die .node-Datei laden kann. |
| 104 | asar: true |
| 105 | asarUnpack: |
| 106 | - '**/node_modules/better-sqlite3/**' |
| 107 | |
| 108 | # Kein npmRebuild nötig: better-sqlite3 >= 12 liefert N-API-Prebuilds, die |
| 109 | # ABI-stabil sind und ohne Neubau unter Electron laufen. |
| 110 | npmRebuild: false |
| 111 | |
| 112 | # ── Windows ────────────────────────────────────────────────────────── |
| 113 | win: |
| 114 | # Fremde Fertigteile von better-sqlite3. `lib/binding.js` setzt den |
| 115 | # Dateinamen zur Laufzeit aus `process.platform` und `process.arch` |
| 116 | # zusammen; unter Windows kann also nur `win32-*.node` je geladen werden. |
| 117 | # Die sechs anderen wiegen nachgezählt 13.003.904 Byte = 12,4 MiB (darwin |
| 118 | # arm64/x64, linux arm64/x64, linuxmusl arm64/x64). Beide |
| 119 | # Windows-Architekturen bleiben – das Ziel unten baut zwar nur x64, aber |
| 120 | # diese Liste soll nicht stillschweigend falsch werden, wenn dort arm64 |
| 121 | # dazukommt. |
| 122 | # |
| 123 | # Vollständige Liste, nicht nur der Ausschluss: siehe den Hinweis über |
| 124 | # `files:` ganz oben. Was hier fehlt, wird nicht geerbt – es fehlt. |
| 125 | files: |
| 126 | - out/**/* |
| 127 | - package.json |
| 128 | - '!**/*.map' |
| 129 | - '!**/{.eslintrc,.editorconfig,.prettierrc}' |
| 130 | - '!**/{test,tests,__tests__,e2e}/**' |
| 131 | - '!**/node_modules/better-sqlite3/{deps,src}/**' |
| 132 | - '!**/node_modules/better-sqlite3/binding.gyp' |
| 133 | - '!**/node_modules/better-sqlite3/prebuilds/{darwin,linux,linuxmusl}-*.node' |
| 134 | target: |
| 135 | - target: nsis |
| 136 | arch: [x64] |
| 137 | artifactName: ${productName}-${version}-Setup-${arch}.${ext} |
| 138 | # Keine Signierung: weder Zertifikat noch Zeitstempel-Server. |
| 139 | signAndEditExecutable: true |
| 140 | signtoolOptions: null |
| 141 | |
| 142 | nsis: |
| 143 | oneClick: false |
| 144 | perMachine: false |
| 145 | allowToChangeInstallationDirectory: true |
| 146 | allowElevation: true |
| 147 | createDesktopShortcut: true |
| 148 | createStartMenuShortcut: true |
| 149 | shortcutName: Waffensachkunde |
| 150 | deleteAppDataOnUninstall: false |
| 151 | # Deutschsprachiger Installer. |
| 152 | installerLanguages: |
| 153 | - de_DE |
| 154 | language: '1031' # LCID für Deutsch (Deutschland) |
| 155 | |
| 156 | # ── Microsoft Store (AppX/MSIX) ────────────────────────────────────── |
| 157 | # |
| 158 | # WARUM DIESER WEG UND NICHT „EXE or MSI app“ |
| 159 | # Das Partner Center bietet beides an; die einfacher aussehende Option ist |
| 160 | # die teure. Microsoft verlangt für EXE/MSI ein Installationspaket, das von |
| 161 | # einer anerkannten Zertifizierungsstelle signiert ist, das der Betreiber |
| 162 | # selbst dauerhaft hostet (versionierte Adresse je Fassung) und das still |
| 163 | # installiert — der deutschsprachige NSIS-Assistent oben wäre unzulässig. |
| 164 | # Für MSIX übernimmt Microsoft Signierung und Auslieferung kostenlos. |
| 165 | # Begründung samt Belegstellen: docs/store-eintrag.md, Abschnitt 10 Punkt 1. |
| 166 | # |
| 167 | # WARUM NICHT IM `win.target` OBEN |
| 168 | # Ein zusätzliches Ziel dort verdoppelte die Bauzeit jedes gewöhnlichen |
| 169 | # `dist:win`, und `e2e/gepackt.spec.ts` misst ohnehin `release/win-unpacked/` |
| 170 | # aus dem NSIS-Bau. Das Store-Paket entsteht deshalb über einen eigenen |
| 171 | # Aufruf: `npm run dist:store`. |
| 172 | # |
| 173 | # WERKZEUGE |
| 174 | # Keine Installation nötig. `makeappx.exe` und `makepri.exe` bringt |
| 175 | # electron-builder in seinem eigenen Werkzeugpaket mit und lädt es beim |
| 176 | # ersten Lauf. |
| 177 | appx: |
| 178 | # Die drei Werte stammen wörtlich aus dem Partner Center, |
| 179 | # Produktverwaltung → Product Identity. Erfinden geht nicht: Weichen sie |
| 180 | # ab, lehnt der Upload das Paket ab, ohne zu sagen, welcher es war. |
| 181 | identityName: O-W.Waffensachkunde-Lernsoftware-OW |
| 182 | publisher: CN=54A4AD0C-C0C3-49B6-922C-7F62CBEC7197 |
| 183 | publisherDisplayName: O-W |
| 184 | |
| 185 | # ACHTUNG, hier schnappt eine Falle zu: `applicationId` fällt ohne diese |
| 186 | # Zeile auf `identityName` zurück, und electron-builder prüft ihn gegen |
| 187 | # /^([A-Za-z][A-Za-z0-9]*)(\.[A-Za-z][A-Za-z0-9]*)*$/ — **keine |
| 188 | # Bindestriche**, jedes Feld muss mit einem Buchstaben beginnen. Der |
| 189 | # Identitätsname enthält drei Bindestriche und fiele durch. Deshalb steht |
| 190 | # hier ein eigener, gültiger Wert; er ist nur programmintern und erscheint |
| 191 | # nirgends für Nutzende. |
| 192 | applicationId: WaffensachkundeLernsoftware |
| 193 | |
| 194 | displayName: Waffensachkunde Lernsoftware |
| 195 | # Kachelfarbe. `#1f2933` ist der dunkle Grundton der Anwendung; die |
| 196 | # Store-Kachel soll nicht heller strahlen als das Programm dahinter. |
| 197 | backgroundColor: '#1f2933' |
| 198 | languages: |
| 199 | - de-DE |
| 200 | |
| 201 | # Untergrenze des Betriebssystems. Ohne diese Zeile setzt electron-builder |
| 202 | # für x64 pauschal `10.0.14316.0` (AppxTarget.js) – eine Insider-Fassung |
| 203 | # von 2016. Der Store lässt die Installation dann auf Maschinen zu, auf |
| 204 | # denen die mitgelieferte Chromium-Fassung 150 gar nicht startet: Sie |
| 205 | # verlangt **Windows 10 1809 (Build 17763)**, so wie es |
| 206 | # `docs/store-eintrag.md` 8.4 auch als Systemanforderung angibt. Der |
| 207 | # Unterschied fiele nicht beim Bauen auf, sondern beim Anwender – als |
| 208 | # Programm, das sich installieren lässt und nicht startet. |
| 209 | minVersion: 10.0.17763.0 |
| 210 | # Getestet ist bislang ausschließlich unter Windows 11; die Angabe bleibt |
| 211 | # deshalb bei der Untergrenze, statt eine Erprobung zu behaupten, die es |
| 212 | # nicht gibt. Ein Durchlauf unter Windows 10 steht aus |
| 213 | # (`docs/store-eintrag.md`, Abschnitt 10 Punkt 5). |
| 214 | maxVersionTested: 10.0.17763.0 |
| 215 | |
| 216 | # Der Dateiname erbt sonst `win.artifactName` und hieße „…-Setup-x64.appx“. |
| 217 | # Ein Store-Paket ist kein Setup; wer beide Dateien nebeneinander liegen |
| 218 | # hat, soll sie am Namen unterscheiden können. |
| 219 | artifactName: ${productName}-${version}-Store-${arch}.${ext} |
| 220 | |
| 221 | # ── macOS ──────────────────────────────────────────────────────────── |
| 222 | mac: |
| 223 | # Dieselbe Rechnung wie unter Windows, gespiegelt: Unter macOS kann nur |
| 224 | # `darwin-*.node` geladen werden. Beide darwin-Fertigteile bleiben, denn |
| 225 | # das Ziel unten baut arm64 **und** x64. |
| 226 | # |
| 227 | # Vollständige Liste, nicht nur der Ausschluss: siehe den Hinweis über |
| 228 | # `files:` ganz oben. |
| 229 | files: |
| 230 | - out/**/* |
| 231 | - package.json |
| 232 | - '!**/*.map' |
| 233 | - '!**/{.eslintrc,.editorconfig,.prettierrc}' |
| 234 | - '!**/{test,tests,__tests__,e2e}/**' |
| 235 | - '!**/node_modules/better-sqlite3/{deps,src}/**' |
| 236 | - '!**/node_modules/better-sqlite3/binding.gyp' |
| 237 | - '!**/node_modules/better-sqlite3/prebuilds/{win32,linux,linuxmusl}-*.node' |
| 238 | target: |
| 239 | - target: dmg |
| 240 | arch: [arm64, x64] |
| 241 | category: public.app-category.education |
| 242 | artifactName: ${productName}-${version}-${arch}.${ext} |
| 243 | # `identity: null` schaltet die Signierung explizit ab. |
| 244 | identity: null |
| 245 | # Hardened Runtime und Notarisierung setzen eine Signierung voraus und |
| 246 | # sind deshalb ebenfalls aus. |
| 247 | hardenedRuntime: false |
| 248 | gatekeeperAssess: false |
| 249 | notarize: false |
| 250 | |
| 251 | dmg: |
| 252 | artifactName: ${productName}-${version}-${arch}.${ext} |
| 253 | contents: |
| 254 | - x: 140 |
| 255 | y: 200 |
| 256 | type: file |
| 257 | - x: 400 |
| 258 | y: 200 |
| 259 | type: link |
| 260 | path: /Applications |
| 261 | |
| 262 | # Keine automatischen Updates – die App wird manuell verteilt. |
| 263 | publish: null |