Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
38f4d8d91f |
+47
-1
@@ -26,6 +26,51 @@ Wiederherstellung*.
|
||||
|
||||
_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
|
||||
|
||||
### 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.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
|
||||
|
||||
@@ -180,6 +180,16 @@ existiert.
|
||||
./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
|
||||
Stand, fragt nach, schaltet um, baut neu und führt danach die beiden
|
||||
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` |
|
||||
| Prisma-Modelle | 33 | `grep -c '^model ' prisma/schema.prisma` |
|
||||
| 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` |
|
||||
| TypeScript-Fehler | 0 | `npm run typecheck` |
|
||||
|
||||
|
||||
+16
-6
@@ -131,14 +131,14 @@ cd /opt/betreuungs-cockpit
|
||||
|
||||
# Auf die letzte veröffentlichte Fassung wechseln,
|
||||
# nicht auf den laufenden Entwicklungsstand
|
||||
git checkout v1.1.0
|
||||
git checkout v1.1.1
|
||||
```
|
||||
|
||||
### Kontrolle
|
||||
|
||||
```bash
|
||||
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
|
||||
# Antwortet die Anwendung? (Port anpassen, falls du APP_PORT gesetzt hast)
|
||||
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:
|
||||
@@ -649,7 +649,7 @@ Erst **vom Proxy-Server aus** — kommt er überhaupt an?
|
||||
|
||||
```bash
|
||||
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
|
||||
@@ -700,7 +700,7 @@ Zum Schluss: **Fristen → Pflichtfristen ableiten**.
|
||||
- Du kommst mit E-Mail, Passwort und dem Code aus der App herein.
|
||||
- Unter **Fristen** stehen Einträge mit Paragraphenbezug.
|
||||
- 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
|
||||
```
|
||||
|
||||
> **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
|
||||
vergisst:
|
||||
|
||||
@@ -903,7 +913,7 @@ git fetch --tags
|
||||
git log --oneline HEAD..origin/main
|
||||
|
||||
# 3. Umschalten
|
||||
git checkout v1.1.0
|
||||
git checkout v1.1.1
|
||||
|
||||
# 4. Neu bauen und starten
|
||||
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
|
||||
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",
|
||||
"version": "1.1.0",
|
||||
"version": "1.1.1",
|
||||
"private": true,
|
||||
"description": "Arbeits- und Dokumentationswerkzeug fuer die ehrenamtliche rechtliche Betreuung",
|
||||
"engines": {
|
||||
|
||||
Regular → Executable
Regular → Executable
+7
@@ -288,6 +288,13 @@ fi
|
||||
|
||||
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"
|
||||
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 --------------------------------------------------------
|
||||
|
||||
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')
|
||||
|
||||
const UNVEROEFFENTLICHT = '## [Unveröffentlicht]'
|
||||
|
||||
Regular → Executable
+1
-1
@@ -17,7 +17,7 @@
|
||||
*/
|
||||
|
||||
/** 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:
|
||||
|
||||
@@ -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