Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
38f4d8d91f |
+47
-1
@@ -26,6 +26,51 @@ Wiederherstellung*.
|
|||||||
|
|
||||||
_Noch nichts._
|
_Noch nichts._
|
||||||
|
|
||||||
|
## [1.1.1] – 2026-08-23
|
||||||
|
|
||||||
|
### Behoben
|
||||||
|
|
||||||
|
- **`./scripts/update.sh` endete in „Permission denied".** Die
|
||||||
|
Shell-Skripte lagen ohne Ausführungsrecht im Repository (Modus 644 statt
|
||||||
|
755). Die Anleitung sagt `./scripts/update.sh` — auf Linux ging genau
|
||||||
|
das nicht.
|
||||||
|
|
||||||
|
Ursache ist der Entwicklungsrechner: Unter Windows steht
|
||||||
|
`core.filemode=false`, dort merkt git von einem fehlenden
|
||||||
|
Ausführungsrecht nichts. Aufgefallen ist es erst auf dem Server.
|
||||||
|
|
||||||
|
**Wer von 1.1.0 oder älter kommt**, braucht einmalig den Umweg — das
|
||||||
|
alte Skript ist ja noch das nicht ausführbare:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
bash scripts/update.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
Danach stimmt das Recht, und der Punktschrägstrich funktioniert.
|
||||||
|
|
||||||
|
- **`update.sh` setzt das Recht nach dem Umschalten selbst.** Wer Dateien
|
||||||
|
von Hand kopiert hat — etwa um an das Skript zu kommen, bevor es in der
|
||||||
|
laufenden Fassung existierte —, verliert es dabei. Ein `chmod +x` nach
|
||||||
|
dem Umschalten fängt das ab.
|
||||||
|
|
||||||
|
- **Das Versionsskript datierte in UTC.** Eine Veröffentlichung nach
|
||||||
|
22 Uhr deutscher Sommerzeit bekam im Changelog das Datum des Vortages —
|
||||||
|
diese Fassung hier war der erste Fall. Es rechnet jetzt in
|
||||||
|
`Europe/Berlin`, wie alles andere in dieser Anwendung auch.
|
||||||
|
|
||||||
|
### Geprüft
|
||||||
|
|
||||||
|
- Vier neue Prüfungen (`tests/skripte.test.ts`) sehen sich nicht das
|
||||||
|
Programm an, sondern die **Verpackung**: Liegt jedes `.sh` ausführbar im
|
||||||
|
Index? Hat es eine Shebang-Zeile? Kommt `scripts/` ins Docker-Abbild?
|
||||||
|
Sind die Sicherungsskripte in der Compose-Datei eingehängt?
|
||||||
|
|
||||||
|
Das ist der zweite Fehler dieser Art — vorher fehlte `scripts/` ganz im
|
||||||
|
Abbild (1.0.1). Beide Male war der Code richtig und kein Test schlug an,
|
||||||
|
weil keiner hinsah, wie die Dateien beim Server ankommen. Jetzt tut es
|
||||||
|
einer. Die Gegenprobe ist gemacht: Mit zurückgesetztem Recht schlägt er
|
||||||
|
fehl und nennt die Datei.
|
||||||
|
|
||||||
## [1.1.0] – 2026-08-22
|
## [1.1.0] – 2026-08-22
|
||||||
|
|
||||||
### Hinzugefügt
|
### Hinzugefügt
|
||||||
@@ -466,7 +511,8 @@ Was davon wann angegangen wird, steht in [`docs/ROADMAP.md`](docs/ROADMAP.md).
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
[Unveröffentlicht]: https://git.wilde-server.de/florian.wilde/betreuungs-cockpit/compare/v1.1.0...HEAD
|
[Unveröffentlicht]: https://git.wilde-server.de/florian.wilde/betreuungs-cockpit/compare/v1.1.1...HEAD
|
||||||
|
[1.1.1]: https://git.wilde-server.de/florian.wilde/betreuungs-cockpit/compare/v1.1.0...v1.1.1
|
||||||
[1.1.0]: https://git.wilde-server.de/florian.wilde/betreuungs-cockpit/compare/v1.0.5...v1.1.0
|
[1.1.0]: https://git.wilde-server.de/florian.wilde/betreuungs-cockpit/compare/v1.0.5...v1.1.0
|
||||||
[1.0.5]: https://git.wilde-server.de/florian.wilde/betreuungs-cockpit/compare/v1.0.4...v1.0.5
|
[1.0.5]: https://git.wilde-server.de/florian.wilde/betreuungs-cockpit/compare/v1.0.4...v1.0.5
|
||||||
[1.0.4]: https://git.wilde-server.de/florian.wilde/betreuungs-cockpit/compare/v1.0.3...v1.0.4
|
[1.0.4]: https://git.wilde-server.de/florian.wilde/betreuungs-cockpit/compare/v1.0.3...v1.0.4
|
||||||
|
|||||||
@@ -180,6 +180,16 @@ existiert.
|
|||||||
./scripts/update.sh
|
./scripts/update.sh
|
||||||
```
|
```
|
||||||
|
|
||||||
|
> **Kommst du von 1.1.0 oder älter?** Dort lag `update.sh` ohne
|
||||||
|
> Ausführungsrecht im Repository — `./scripts/update.sh` endet dann in
|
||||||
|
> „Permission denied". Einmalig hilft:
|
||||||
|
>
|
||||||
|
> ```bash
|
||||||
|
> bash scripts/update.sh
|
||||||
|
> ```
|
||||||
|
>
|
||||||
|
> Ab 1.1.1 ist das Recht gesetzt und der Punktschrägstrich funktioniert.
|
||||||
|
|
||||||
Das Skript sichert zuerst, zeigt den Changelog zwischen altem und neuem
|
Das Skript sichert zuerst, zeigt den Changelog zwischen altem und neuem
|
||||||
Stand, fragt nach, schaltet um, baut neu und führt danach die beiden
|
Stand, fragt nach, schaltet um, baut neu und führt danach die beiden
|
||||||
SQL-Skripte aus. Schlägt die Sicherung fehl, wird nicht aktualisiert.
|
SQL-Skripte aus. Schlägt die Sicherung fehl, wird nicht aktualisiert.
|
||||||
@@ -573,7 +583,7 @@ Fehler, die während des Baus aufgefallen sind.
|
|||||||
| Zeilen TypeScript/TSX | 72.080 | `git ls-files "*.ts" "*.tsx" \| xargs wc -l` |
|
| Zeilen TypeScript/TSX | 72.080 | `git ls-files "*.ts" "*.tsx" \| xargs wc -l` |
|
||||||
| Prisma-Modelle | 33 | `grep -c '^model ' prisma/schema.prisma` |
|
| Prisma-Modelle | 33 | `grep -c '^model ' prisma/schema.prisma` |
|
||||||
| Seiten | 79 | `find src/app -name page.tsx \| wc -l` |
|
| Seiten | 79 | `find src/app -name page.tsx \| wc -l` |
|
||||||
| Unit-Tests (Vitest) | 496 | `npm test` |
|
| Unit-Tests (Vitest) | 500 | `npm test` |
|
||||||
| End-to-End-Tests (Playwright) | 37 | `npm run test:e2e` |
|
| End-to-End-Tests (Playwright) | 37 | `npm run test:e2e` |
|
||||||
| TypeScript-Fehler | 0 | `npm run typecheck` |
|
| TypeScript-Fehler | 0 | `npm run typecheck` |
|
||||||
|
|
||||||
|
|||||||
+16
-6
@@ -131,14 +131,14 @@ cd /opt/betreuungs-cockpit
|
|||||||
|
|
||||||
# Auf die letzte veröffentlichte Fassung wechseln,
|
# Auf die letzte veröffentlichte Fassung wechseln,
|
||||||
# nicht auf den laufenden Entwicklungsstand
|
# nicht auf den laufenden Entwicklungsstand
|
||||||
git checkout v1.1.0
|
git checkout v1.1.1
|
||||||
```
|
```
|
||||||
|
|
||||||
### Kontrolle
|
### Kontrolle
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
ls docker-compose.yml Dockerfile .env.example # alle drei da
|
ls docker-compose.yml Dockerfile .env.example # alle drei da
|
||||||
git describe --tags # v1.1.0
|
git describe --tags # v1.1.1
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -299,7 +299,7 @@ betreuungs-cockpit-sicherung-1 Up
|
|||||||
```bash
|
```bash
|
||||||
# Antwortet die Anwendung? (Port anpassen, falls du APP_PORT gesetzt hast)
|
# Antwortet die Anwendung? (Port anpassen, falls du APP_PORT gesetzt hast)
|
||||||
curl -s http://127.0.0.1:3000/api/gesundheit
|
curl -s http://127.0.0.1:3000/api/gesundheit
|
||||||
# {"status":"bereit","version":"1.1.0","commit":"..."}
|
# {"status":"bereit","version":"1.1.1","commit":"..."}
|
||||||
```
|
```
|
||||||
|
|
||||||
Kommt hier nichts, sieh in die Logs:
|
Kommt hier nichts, sieh in die Logs:
|
||||||
@@ -649,7 +649,7 @@ Erst **vom Proxy-Server aus** — kommt er überhaupt an?
|
|||||||
|
|
||||||
```bash
|
```bash
|
||||||
curl -s http://10.0.0.5:3000/api/gesundheit
|
curl -s http://10.0.0.5:3000/api/gesundheit
|
||||||
# {"status":"bereit","version":"1.1.0",...}
|
# {"status":"bereit","version":"1.1.1",...}
|
||||||
```
|
```
|
||||||
|
|
||||||
Kommt hier nichts, liegt es an 7a: falsche `APP_BIND`, Firewall, oder der
|
Kommt hier nichts, liegt es an 7a: falsche `APP_BIND`, Firewall, oder der
|
||||||
@@ -700,7 +700,7 @@ Zum Schluss: **Fristen → Pflichtfristen ableiten**.
|
|||||||
- Du kommst mit E-Mail, Passwort und dem Code aus der App herein.
|
- Du kommst mit E-Mail, Passwort und dem Code aus der App herein.
|
||||||
- Unter **Fristen** stehen Einträge mit Paragraphenbezug.
|
- Unter **Fristen** stehen Einträge mit Paragraphenbezug.
|
||||||
- Unter **Protokoll** siehst du deine eigene Anmeldung.
|
- Unter **Protokoll** siehst du deine eigene Anmeldung.
|
||||||
- Unten links in der Seitenleiste steht `Version 1.1.0 · <commit>`.
|
- Unten links in der Seitenleiste steht `Version 1.1.1 · <commit>`.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -843,6 +843,16 @@ cd /opt/betreuungs-cockpit
|
|||||||
./scripts/update.sh
|
./scripts/update.sh
|
||||||
```
|
```
|
||||||
|
|
||||||
|
> **Kommst du von 1.1.0 oder älter?** Dort lag `update.sh` ohne
|
||||||
|
> Ausführungsrecht im Repository — `./scripts/update.sh` endet dann in
|
||||||
|
> „Permission denied". Einmalig hilft:
|
||||||
|
>
|
||||||
|
> ```bash
|
||||||
|
> bash scripts/update.sh
|
||||||
|
> ```
|
||||||
|
>
|
||||||
|
> Ab 1.1.1 ist das Recht gesetzt und der Punktschrägstrich funktioniert.
|
||||||
|
|
||||||
Das war es. Das Skript nimmt dir die Schritte ab, die man von Hand
|
Das war es. Das Skript nimmt dir die Schritte ab, die man von Hand
|
||||||
vergisst:
|
vergisst:
|
||||||
|
|
||||||
@@ -903,7 +913,7 @@ git fetch --tags
|
|||||||
git log --oneline HEAD..origin/main
|
git log --oneline HEAD..origin/main
|
||||||
|
|
||||||
# 3. Umschalten
|
# 3. Umschalten
|
||||||
git checkout v1.1.0
|
git checkout v1.1.1
|
||||||
|
|
||||||
# 4. Neu bauen und starten
|
# 4. Neu bauen und starten
|
||||||
GIT_COMMIT=$(git rev-parse --short HEAD) BUILD_ZEIT=$(date -Iseconds) docker compose up -d --build
|
GIT_COMMIT=$(git rev-parse --short HEAD) BUILD_ZEIT=$(date -Iseconds) docker compose up -d --build
|
||||||
|
|||||||
+1
-1
@@ -9,7 +9,7 @@ Zeit spart. Er steht weit unten, wenn er nur schön wäre.
|
|||||||
Diese Datei ist eine Absichtserklärung, kein Vertrag. Was sich im Betrieb
|
Diese Datei ist eine Absichtserklärung, kein Vertrag. Was sich im Betrieb
|
||||||
als wichtiger herausstellt, rutscht nach oben.
|
als wichtiger herausstellt, rutscht nach oben.
|
||||||
|
|
||||||
Stand: 22.08.2026 · Aktuelle Fassung: **1.1.0** ([CHANGELOG](../CHANGELOG.md))
|
Stand: 23.08.2026 · Aktuelle Fassung: **1.1.1** ([CHANGELOG](../CHANGELOG.md))
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "betreuungs-cockpit",
|
"name": "betreuungs-cockpit",
|
||||||
"version": "1.1.0",
|
"version": "1.1.1",
|
||||||
"private": true,
|
"private": true,
|
||||||
"description": "Arbeits- und Dokumentationswerkzeug fuer die ehrenamtliche rechtliche Betreuung",
|
"description": "Arbeits- und Dokumentationswerkzeug fuer die ehrenamtliche rechtliche Betreuung",
|
||||||
"engines": {
|
"engines": {
|
||||||
|
|||||||
Regular → Executable
Regular → Executable
+7
@@ -288,6 +288,13 @@ fi
|
|||||||
|
|
||||||
gut "$(git describe --tags --always)"
|
gut "$(git describe --tags --always)"
|
||||||
|
|
||||||
|
# Das Ausfuehrbarkeitsbit kommt normalerweise aus dem Repository mit. Wer
|
||||||
|
# Dateien von Hand kopiert hat - etwa um an dieses Skript zu kommen, bevor
|
||||||
|
# es in der laufenden Fassung existierte -, hat es verloren. Dann waere der
|
||||||
|
# naechste Aufruf ein "Permission denied", und man sucht an der falschen
|
||||||
|
# Stelle.
|
||||||
|
chmod +x scripts/*.sh 2>/dev/null || true
|
||||||
|
|
||||||
schritt "Bauen und starten"
|
schritt "Bauen und starten"
|
||||||
printf ' Das dauert beim ersten Mal einige Minuten.\n\n'
|
printf ' Das dauert beim ersten Mal einige Minuten.\n\n'
|
||||||
|
|
||||||
|
|||||||
+6
-1
@@ -97,7 +97,12 @@ schreiben('src/lib/version.ts', ersetzt)
|
|||||||
|
|
||||||
// --- 3. CHANGELOG.md --------------------------------------------------------
|
// --- 3. CHANGELOG.md --------------------------------------------------------
|
||||||
|
|
||||||
const heute = new Date().toISOString().slice(0, 10)
|
// Deutsche Zeit, nicht UTC. Sonst bekommt eine Veroeffentlichung nach
|
||||||
|
// 22 Uhr (Sommerzeit) das Datum des Vortages - dieselbe Zeitzonenfalle,
|
||||||
|
// derentwegen die Fristen im Schema @db.Date sind.
|
||||||
|
const heute = new Intl.DateTimeFormat('sv-SE', {
|
||||||
|
timeZone: 'Europe/Berlin',
|
||||||
|
}).format(new Date())
|
||||||
let changelog = lesen('CHANGELOG.md')
|
let changelog = lesen('CHANGELOG.md')
|
||||||
|
|
||||||
const UNVEROEFFENTLICHT = '## [Unveröffentlicht]'
|
const UNVEROEFFENTLICHT = '## [Unveröffentlicht]'
|
||||||
|
|||||||
Regular → Executable
+1
-1
@@ -17,7 +17,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/** Muss zur "version" in der package.json passen. */
|
/** Muss zur "version" in der package.json passen. */
|
||||||
export const VERSION = '1.1.0'
|
export const VERSION = '1.1.1'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Kurzer Git-Stand, beim Bauen hineingereicht:
|
* Kurzer Git-Stand, beim Bauen hineingereicht:
|
||||||
|
|||||||
@@ -0,0 +1,87 @@
|
|||||||
|
import { execFileSync } from 'node:child_process'
|
||||||
|
import { readFileSync } from 'node:fs'
|
||||||
|
import { describe, expect, it } from 'vitest'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Die Betriebsskripte müssen im Repository so liegen, dass sie auf dem
|
||||||
|
* Server auch laufen.
|
||||||
|
*
|
||||||
|
* Anlass sind zwei Fehler, die beide erst im Betrieb aufgefallen sind und
|
||||||
|
* beide nichts mit dem Programm zu tun hatten, sondern mit der Verpackung:
|
||||||
|
*
|
||||||
|
* 1. `scripts/` fehlte im Docker-Abbild — `node scripts/totp-geheimnis.mjs`
|
||||||
|
* lief ins Leere (behoben in 1.0.1).
|
||||||
|
* 2. Die `.sh`-Dateien lagen mit Modus 644 im Repository. Die Anleitung
|
||||||
|
* sagt `./scripts/update.sh`, auf Linux kam „Permission denied".
|
||||||
|
*
|
||||||
|
* Beide Male hat kein Test angeschlagen, weil beide Male der Code richtig
|
||||||
|
* war. Diese Datei prüft deshalb nicht Verhalten, sondern Verpackung.
|
||||||
|
*
|
||||||
|
* Der Ausführbarkeitsbit wird aus dem Git-Index gelesen, nicht vom
|
||||||
|
* Dateisystem: Unter Windows steht `core.filemode=false`, dort sagt das
|
||||||
|
* Dateisystem nichts aus. Maßgeblich ist, was ausgecheckt wird.
|
||||||
|
*/
|
||||||
|
|
||||||
|
function gitVerfuegbar(): boolean {
|
||||||
|
try {
|
||||||
|
execFileSync('git', ['rev-parse', '--git-dir'], { stdio: 'pipe' })
|
||||||
|
return true
|
||||||
|
} catch {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Liefert [Modus, Pfad] je Datei, so wie sie im Index steht. */
|
||||||
|
function eintraegeImIndex(muster: string): [string, string][] {
|
||||||
|
const ausgabe = execFileSync('git', ['ls-files', '-s', muster], { encoding: 'utf8' })
|
||||||
|
return ausgabe
|
||||||
|
.split('\n')
|
||||||
|
.filter((zeile) => zeile.trim() !== '')
|
||||||
|
.map((zeile) => {
|
||||||
|
const [angaben, pfad] = zeile.split('\t')
|
||||||
|
return [angaben!.split(' ')[0]!, pfad!]
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const mitGit = gitVerfuegbar()
|
||||||
|
|
||||||
|
describe.skipIf(!mitGit)('Betriebsskripte', () => {
|
||||||
|
it('legt jedes Shell-Skript ausführbar ab', () => {
|
||||||
|
const skripte = eintraegeImIndex('scripts/*.sh')
|
||||||
|
|
||||||
|
// Wenn hier nichts steht, stimmt das Muster nicht mehr - das waere
|
||||||
|
// ein stiller Ausfall der Pruefung.
|
||||||
|
expect(skripte.length).toBeGreaterThan(0)
|
||||||
|
|
||||||
|
for (const [modus, pfad] of skripte) {
|
||||||
|
expect(modus, `${pfad} muss ausführbar sein (100755, ist ${modus})`).toBe('100755')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
it('gibt jedem Shell-Skript eine Shebang-Zeile', () => {
|
||||||
|
for (const [, pfad] of eintraegeImIndex('scripts/*.sh')) {
|
||||||
|
const ersteZeile = readFileSync(pfad, 'utf8').split('\n')[0] ?? ''
|
||||||
|
expect(ersteZeile, `${pfad} braucht eine Shebang-Zeile`).toMatch(/^#!/)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
it('nimmt scripts/ ins Docker-Abbild auf', () => {
|
||||||
|
// Der Fehler aus 1.0.1: Die Wartungsskripte lagen im Repository, aber
|
||||||
|
// nicht im Behaelter. Aufgefallen ist es erst, als sie gebraucht wurden.
|
||||||
|
const dockerfile = readFileSync('Dockerfile', 'utf8')
|
||||||
|
// Die Zeile traegt zusaetzliche Schalter (--from, --chown) - deshalb
|
||||||
|
// nicht auf eine feste Reihenfolge festlegen, sondern nur darauf, dass
|
||||||
|
// scripts/ ins Abbild kopiert wird.
|
||||||
|
expect(dockerfile).toMatch(/^COPY.*\/scripts\s+\.\/scripts\s*$/m)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('bindet die Sicherungsskripte aus scripts/ in die Compose-Datei ein', () => {
|
||||||
|
// Sie werden als Volume in den Sicherungsdienst gehaengt. Ein
|
||||||
|
// umbenanntes Skript faellt sonst erst um 03:15 Uhr auf - im Log,
|
||||||
|
// das niemand liest.
|
||||||
|
const compose = readFileSync('docker-compose.yml', 'utf8')
|
||||||
|
for (const name of ['sicherung.sh', 'wiederherstellung.sh']) {
|
||||||
|
expect(compose, `${name} wird nicht eingebunden`).toContain(`./scripts/${name}:`)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
Reference in New Issue
Block a user