Skip to content

Commit b50a80a

Browse files
chore(release): prepare 1.2.6 metadata and release notes
Align version metadata and release documentation with the hardened absence and entitlement workflow changes. Document release integrity gates and provide updated multilingual changelog/manual context for the 1.2.6 rollout. Made-with: Cursor
1 parent 156cbcb commit b50a80a

19 files changed

Lines changed: 182 additions & 14 deletions

CHANGELOG.de.md

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,40 @@
11
## [Unreleased]
22

3+
## 1.2.6 – 2026-04-24
4+
5+
### Hinzugefügt
6+
7+
- **Forensik bei Abwesenheitsfreigaben**: `approved_by_user_id` wird nun direkt am Abwesenheitsdatensatz gespeichert (Freigabe/Ablehnung/Auto-Freigabe), inkl. Migration und API-Ausgabe.
8+
9+
### Geändert
10+
11+
- **Integrität der Urlaubsanspruch-Snapshots**: Deterministisches Key-Upsert auf `(user_id, period_key, as_of_date)` ergänzt und per Migrations-Unique-Index auf Datenbankebene abgesichert.
12+
- **Nebenläufigkeitskontrolle in kritischen Workflows**: Create/Update/Approve/Reject/Substitute-Flows sind nun mit nutzerspezifischen Mutations-Locks plus transaktionalen Rechecks/Row-Locks abgesichert, um Race-Conditions bei Überschneidungen und Überfreigaben zu verhindern.
13+
- **Release-Absicherung**: Workflow-bezogene Unit- und Integrationstests wurden auf die gehärteten Mutationspfade angepasst und erfolgreich ausgeführt.
14+
15+
### Behoben
16+
17+
- **Legacy-Snapshot-Reparaturpfad**: Upsert behandelt historische fehlerhafte Zeilen sowie parallele Unique-Key-Konflikte robust via deterministischem Retry-Update.
18+
- **Race-Condition bei Resturlaub-Updates**: `VacationYearBalanceMapper::upsert` löst gleichzeitige Unique-Key-Konflikte jetzt per Re-Read/Update-Fallback.
19+
20+
## 1.2.5 – 2026-04-22
21+
22+
### Geändert
23+
24+
- **Release-Paket aktualisiert**: App-Metadaten auf `1.2.5` angehoben und den signierten Release-Artefaktsatz für App-Store- und GitHub-Veröffentlichung neu erzeugt.
25+
26+
## 1.2.4 – 2026-04-21
27+
28+
### Geändert
29+
30+
- **Release-Stand veröffentlichbar gemacht**: App-Metadaten auf `1.2.4` angehoben und ein neuer signierter Release-Artefaktsatz (Archiv, Checksummen, App-Store-Signatur) für App-Store-/GitHub-Veröffentlichung erstellt.
31+
32+
## 1.2.3 – 2026-04-21
33+
34+
### Geändert
35+
36+
- **Release-Paket aktualisiert**: Neues signiertes App-Store-/GitHub-Release-Archiv für den aktuellen Code-Stand mit Docker-basiertem Signatur-Workflow erstellt.
37+
338
## 1.2.2 – 2026-04-21
439

540
### Behoben

CHANGELOG.md

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,41 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased]
99

10+
## 1.2.6 - 2026-04-24
11+
12+
### Added
13+
14+
- **Absence approval forensics**: Added `approved_by_user_id` persistence on absence records (approve/reject/auto-approve), with schema migration and API summary output.
15+
16+
### Changed
17+
18+
- **Vacation entitlement snapshot integrity**: Added deterministic key-based upsert on `(user_id, period_key, as_of_date)` and migration-backed unique index enforcement.
19+
- **Concurrency control in critical workflows**: Absence create/update/approve/reject/substitute flows now use user-scoped mutation locks plus transactional rechecks/row locks to prevent race-based overlap and over-approval inconsistencies.
20+
- **Release safety**: Workflow/unit/integration tests were updated and executed against the hardened mutation paths.
21+
22+
### Fixed
23+
24+
- **Legacy snapshot repair path**: Upsert now handles historical malformed rows and concurrent unique-key conflicts safely by retrying as deterministic update.
25+
- **Vacation balance write races**: `VacationYearBalanceMapper::upsert` now resolves concurrent unique-key collisions via re-read/update fallback.
26+
27+
## 1.2.5 - 2026-04-22
28+
29+
### Changed
30+
31+
- **Release packaging refresh**: Bumped app metadata to `1.2.5` and regenerated the signed release artifact set for App Store and GitHub publication.
32+
33+
## 1.2.4 - 2026-04-21
34+
35+
### Changed
36+
37+
- **Publishable release refresh**: Bumped app metadata to `1.2.4` and generated a new signed release artifact set (archive, checksums, and App Store signature) for App Store/GitHub publication.
38+
39+
## 1.2.3 - 2026-04-21
40+
41+
### Changed
42+
43+
- **Release packaging refresh**: Prepared a new signed App Store/GitHub release archive for the current code line using the Docker-based signing workflow.
44+
1045
## 1.2.2 - 2026-04-21
1146

1247
### Fixed

appinfo/info.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ gehosteten Nextcloud.
5454
- PHP 8.1–8.4
5555
]]></description>
5656

57-
<version>1.2.2</version>
57+
<version>1.2.6</version>
5858
<licence>AGPL-3.0-or-later</licence>
5959
<author mail="info@software-by-design.de" homepage="https://software-by-design.de">Alexander Mäule</author>
6060

appinfo/version

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
1.2.0
1+
1.2.6

docs/README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@ This folder contains the documentation included with ArbeitszeitCheck for admini
66

77
| Document | Description |
88
|----------|-------------|
9-
| [User-Manual.en.md](User-Manual.en.md) | Short end-user/admin guide (calendar vs Nextcloud Calendar, absences, roles, app-admin allowlist usage, overtime/undertime traffic light notifications, revision-safe month closure including optional grace period and auto-finalization) |
10-
| [User-Manual.de.md](User-Manual.de.md) | Kurzanleitung für Endnutzer/Admins (Deutsch), inkl. App-Admin-Whitelist sowie Monatsnachweis mit Karenz und Auto-Finalisierung |
9+
| [User-Manual.en.md](User-Manual.en.md) | Short end-user/admin guide (calendar vs Nextcloud Calendar, absences, roles, dashboard quick-actions workspace with role-based overview blocks, manager approvals tabs for absences/time-entry corrections, app-admin allowlist usage, overtime/undertime traffic light notifications, revision-safe month closure including optional grace period and auto-finalization) |
10+
| [User-Manual.de.md](User-Manual.de.md) | Kurzanleitung für Endnutzer/Admins (Deutsch), inkl. Dashboard-Schnellaktionen mit rollenbasierten Übersichten, Manager-Reitern für Abwesenheiten/Korrekturen, App-Admin-Whitelist sowie Monatsnachweis mit Karenz und Auto-Finalisierung |
1111
| [GDPR-Compliance-Guide.en.md](GDPR-Compliance-Guide.en.md) | How to operate ArbeitszeitCheck in a GDPR-compliant way (legal basis, data minimization, employee rights, retention) |
1212
| [Compliance-Implementation.en.md](Compliance-Implementation.en.md) | Technical implementation of ArbZG compliance checks (breaks, rest periods, real-time vs batch) |
1313
| [Compliance-Implementation.de.md](Compliance-Implementation.de.md) | Same content in German |

docs/User-Manual.de.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,14 +60,18 @@ Im Auswahldialog erscheinen nur Konten aus der Nextcloud-`admin`-Gruppe.
6060
## 4. Alltägliche Aufgaben
6161

6262
- **Kommen/Gehen und Pausen** über die Zeiterfassung; Korrekturen und Begründungen nach internen Regeln.
63+
- **Dashboard-Schnellaktionen (Workspace):**
64+
- Das Dashboard enthält einen eigenen Schnellaktionsbereich mit **Mein Status**, **Aktuelle Sitzung** und direkten Aktionen für **Clock In**, **Pause**, **Fortsetzen** und **Clock Out**.
65+
- Je nach Rolle zeigt dieselbe Seite zusätzlich **Teamübersicht** (Führungskraft) und **Unternehmensübersicht** (Admin) mit kompakten Statuslisten.
66+
- Wenn eine Aktion wegen einer abgelaufenen Nextcloud-Sitzung fehlschlägt, Seite aktualisieren und erneut ausführen.
6367
- **Pausierter Eintrag (wieder aufnehmen oder korrigieren):**
6468
- Wenn ein Eintrag den Status **Pausiert** hat, zeigt das Dashboard bei **Clock In** die Aktion **Fortsetzen (nach Pause)** und setzt den gleichen Tages-Eintrag fort (statt einen Duplikat-Eintrag zu erzeugen).
6569
- Pausierte Einträge sind in den letzten 14 Tagen wieder normal **bearbeitbar/löschbar** (sofern nicht bereits genehmigt).
6670
- Beim Speichern mit Endzeit wird ein pausierter Eintrag automatisch als **Abgeschlossen** (`completed`) finalisiert.
6771
- **Abwesenheiten** beantragen und ggf. auf Freigabe warten. **Resturlaub** und Überträge werden angezeigt, wenn die Administration das gepflegt hat.
6872
- **App-Teams (empfohlene Einrichtung):** Wenn Ihre Organisation **App-Teams** nutzt und in der App **kein:e Vorgesetzte:r** für Ihr Team hinterlegt ist, werden Anträge **ohne** Vertretung beim Absenden **automatisch genehmigt**—es gäbe sonst niemanden mit Managerfreigabe. Mit **Vertretung** läuft zuerst der Vertretungs-Schritt. Die Oberfläche kann dazu einen kurzen Hinweis anzeigen.
6973
- **Älteres Gruppenmodell:** Verhalten folgt dem früheren „gleiche Gruppe“-Modell; die Administration sollte sicherstellen, dass Genehmigungen für Ihre Organisation weiterhin sinnvoll möglich sind.
70-
- **Manager-Dashboard** (als Führungskraft): Unter **Ausstehende Genehmigungen** erscheint der **Abwesenheitstyp in Ihrer Sprache** (z. B. Urlaub, Krankheit), nicht technische Kurzbezeichnungen. Wo freigeschaltet, bietet **Abwesenheiten der Mitarbeitenden** eine eigene Listen-/Filteransicht.
74+
- **Manager-Dashboard** (als Führungskraft): Unter **Ausstehende Genehmigungen** können Sie zwischen den Reitern **Abwesenheiten** und **Zeiteintrag-Korrekturen** wechseln. Bei Abwesenheiten erscheint der **Abwesenheitstyp in Ihrer Sprache** (z. B. Urlaub, Krankheit), nicht technische Kurzbezeichnungen. Wo freigeschaltet, bietet **Abwesenheiten der Mitarbeitenden** eine eigene Listen-/Filteransicht.
7175
- **Mobile Nutzung (Smartphone/Tablet):** Die Oberfläche ist responsiv optimiert (klarere Abschnittsabstände, größere Touch-Ziele, iPhone-Safe-Area-Berücksichtigung). Auf sehr kleinen Displays funktionieren Formulare meist am besten im Hochformat, breite Tabellen/Berichte im Querformat.
7276
- **Berichte** für Zeiträume erstellen und erlaubte Exporte nutzen (CSV, DATEV, …).
7377
- **Compliance-Hinweise** (z. B. fehlende Pausen) nach Vorgabe des Arbeitgebers bearbeiten.

docs/User-Manual.en.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,14 +61,18 @@ Only users in Nextcloud's `admin` group are eligible in this picker.
6161
## 4. Everyday tasks
6262

6363
- **Clock in / out** and **breaks**: Use the time tracking UI; follow your organization’s rules for corrections and comments.
64+
- **Dashboard quick actions workspace**:
65+
- The dashboard includes a dedicated quick-actions area with **My status**, **Current session**, and direct buttons for **Clock In**, **Pause**, **Continue**, and **Clock Out**.
66+
- Depending on your role, the same page can also show **Team overview** (manager) and **Company overview** (admin) with compact status lists.
67+
- If a request fails because your Nextcloud session expired, refresh the page and retry.
6468
- **Paused entry (resume or fix):**
6569
- If an entry is in **Paused** state, the dashboard shows **Resume after break** on clock-in and continues the same-day entry instead of creating a duplicate.
6670
- Paused entries are editable/deletable again within the normal 14-day edit window (as long as they are not already approved).
6771
- When saved with an end time, a paused entry is finalized automatically as **Completed**.
6872
- **Absences**: Create requests; wait for approval if your workflow requires it. Vacation balances and carryover (**Resturlaub**) may be shown if your admin configured them.
6973
- **App teams (recommended setup):** If your organization uses **app-managed teams** and **no manager is assigned** to your team in the app, requests you submit **without** a substitute are **approved automatically** when you send them—there is nobody who could approve them in the manager workflow. If you **do** pick a substitute, the substitute step still runs first. The UI may show a short explanation when this applies.
7074
- **Legacy group-based setup:** Behavior follows the older “same group” model; your admin should ensure approvals remain workable for your organization.
71-
- **Manager dashboard** (if you are a team lead): Under **Pending approvals**, absence requests list each person with the **absence type in your language** (e.g. vacation vs sick leave), not raw internal codes. Where enabled, **Employee absences** provides a dedicated list/filter view of team absences.
75+
- **Manager dashboard** (if you are a team lead): Under **Pending approvals**, you can switch between **Absences** and **Time entry corrections** tabs. Absence requests list each person with the **absence type in your language** (e.g. vacation vs sick leave), not raw internal codes. Where enabled, **Employee absences** provides a dedicated list/filter view of team absences.
7276
- **Overtime balance traffic light**: On the dashboard, your balance can appear as green/yellow/red and distinguishes overtime vs undertime warnings. This is an orientation signal; your organization defines policy actions.
7377
- **Mobile use (phones/tablets):** The UI is optimized for responsive use with clearer section spacing, larger touch targets, and iPhone safe-area aware layout. If you use a very small screen, prefer portrait mode for forms and landscape for wide tables/reports.
7478
- **Reports**: Generate period reports or exports your admin allows (CSV, DATEV, etc.).

lib/Migration/Version1017Date20260420120000.php

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ public function changeSchema(IOutput $output, Closure $schemaClosure, array $opt
2929
$table->addColumn('created_at', Types::DATETIME, ['notnull' => true]);
3030
$table->addColumn('updated_at', Types::DATETIME, ['notnull' => true]);
3131
$table->setPrimaryKey(['id'], 'at_tariff_rule_sets_pk');
32-
$table->addUniqueIndex(['tariff_code', 'version'], 'at_tariff_rule_sets_code_ver_uq');
32+
$table->addUniqueIndex(['tariff_code', 'version'], 'at_trs_code_ver_uq');
3333
$table->addIndex(['status'], 'at_tariff_rule_sets_status_idx');
3434
$table->addIndex(['valid_from', 'valid_to'], 'at_tariff_rule_sets_valid_idx');
3535
}
@@ -44,8 +44,8 @@ public function changeSchema(IOutput $output, Closure $schemaClosure, array $opt
4444
$table->addColumn('created_at', Types::DATETIME, ['notnull' => true]);
4545
$table->addColumn('updated_at', Types::DATETIME, ['notnull' => true]);
4646
$table->setPrimaryKey(['id'], 'at_tariff_rule_modules_pk');
47-
$table->addIndex(['rule_set_id'], 'at_tariff_rule_modules_ruleset_idx');
48-
$table->addIndex(['module_type'], 'at_tariff_rule_modules_type_idx');
47+
$table->addIndex(['rule_set_id'], 'at_trm_ruleset_idx');
48+
$table->addIndex(['module_type'], 'at_trm_type_idx');
4949
}
5050

5151
if (!$schema->hasTable('at_user_vacation_policies')) {
@@ -63,7 +63,7 @@ public function changeSchema(IOutput $output, Closure $schemaClosure, array $opt
6363
$table->addColumn('updated_at', Types::DATETIME, ['notnull' => true]);
6464
$table->setPrimaryKey(['id'], 'at_user_vac_policy_pk');
6565
$table->addIndex(['user_id'], 'at_user_vac_policy_user_idx');
66-
$table->addIndex(['effective_from', 'effective_to'], 'at_user_vac_policy_effective_idx');
66+
$table->addIndex(['effective_from', 'effective_to'], 'at_uvp_effective_idx');
6767
$table->addIndex(['tariff_rule_set_id'], 'at_user_vac_policy_tariff_idx');
6868
}
6969

@@ -81,8 +81,8 @@ public function changeSchema(IOutput $output, Closure $schemaClosure, array $opt
8181
$table->addColumn('computed_by', Types::STRING, ['notnull' => true, 'length' => 64, 'default' => 'system']);
8282
$table->addColumn('policy_fingerprint', Types::STRING, ['notnull' => false, 'length' => 128]);
8383
$table->setPrimaryKey(['id'], 'at_entitlement_snapshots_pk');
84-
$table->addIndex(['user_id', 'period_key'], 'at_entitlement_snapshots_user_period_idx');
85-
$table->addIndex(['computed_at'], 'at_entitlement_snapshots_computed_idx');
84+
$table->addIndex(['user_id', 'period_key'], 'at_ents_user_period_idx');
85+
$table->addIndex(['computed_at'], 'at_ents_computed_idx');
8686
}
8787

8888
return $schema;

release/APPSTORE-RELEASE.md

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,37 @@ Submit; fix any validation errors (wrong checksum/signature almost always means
228228

229229
---
230230

231+
## 7.5 Mandatory release-asset identity check (hard gate)
232+
233+
Before App Store submit, verify that your local archive and the GitHub release asset are exactly the same bytes.
234+
235+
```bash
236+
VERSION=X.Y.Z
237+
APPID=arbeitszeitcheck
238+
GH_REPO=aSoftwareByDesignRepository/nextcloud-arbeitszeitcheck
239+
LOCAL_ARCHIVE="build/release/${APPID}-${VERSION}.tar.gz"
240+
VERIFY_DIR="$(mktemp -d)"
241+
242+
gh release download "v${VERSION}" \
243+
--repo "${GH_REPO}" \
244+
--pattern "${APPID}-${VERSION}.tar.gz" \
245+
--dir "${VERIFY_DIR}" \
246+
--clobber
247+
248+
sha256sum "${LOCAL_ARCHIVE}" "${VERIFY_DIR}/${APPID}-${VERSION}.tar.gz"
249+
cmp -s "${LOCAL_ARCHIVE}" "${VERIFY_DIR}/${APPID}-${VERSION}.tar.gz" && echo "OK: byte-identical"
250+
251+
rm -rf "${VERIFY_DIR}"
252+
```
253+
254+
Release policy:
255+
256+
- If `OK: byte-identical` is missing, stop and do not submit to App Store.
257+
- Recreate one canonical archive, then re-run checksum/signature and upload steps.
258+
- App Store upload must use exactly that canonical archive (or the downloaded matching GitHub asset).
259+
260+
---
261+
231262
## 8. Required chat handoff (every release)
232263

233264
After release creation and before closing the task, always paste these two items in chat:
@@ -262,5 +293,6 @@ This handoff is mandatory for every release so upload data can be copied without
262293
- [ ] OpenSSL base64 signature **from the same tarball file**
263294
- [ ] Nothing uploaded to git except docs/checksums (no `.tar.gz`, no keys)
264295
- [ ] **GitHub Release** on **`nextcloud-arbeitszeitcheck`**: tag `vX.Y.Z`, attach **`build/release/arbeitszeitcheck-X.Y.Z.tar.gz`**, `gh --repo aSoftwareByDesignRepository/nextcloud-arbeitszeitcheck` (**required**)
296+
- [ ] Byte-identity gate passed (`cmp` + identical SHA-256 local archive vs downloaded GitHub release asset)
265297
- [ ] App Store upload uses **that same** tarball bytes
266298
- [ ] Chat handoff posted: App Store signature + direct GitHub tarball URL

release/CHECKSUMS-1.2.2.txt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
1-
11e9d091392b33b018b494c4ec0d9fac4f5031b97b8a475ecef8899f9f94b05c arbeitszeitcheck-1.2.2.tar.gz
2-
b7359b358391efa8eccc225e1af69517fe66f7e903a6d67b7636f64b140c3994d73229eabc6d198b81e4677a6fa68c41239c80078dd280c9ec6b8a8bb58272d1 arbeitszeitcheck-1.2.2.tar.gz
1+
# arbeitszeitcheck-1.2.2.tar.gz
2+
2494c74f5264b6a78063d5c399248b16103ab2a12f5c7e78da9c4579e7b9b8c9 arbeitszeitcheck-1.2.2.tar.gz
3+
547e219c971117e4020518765253eb431bb8c549635b125706571c4274e84a70d58f045e6fda0c603d4177e0858e235c14552d5cd15bdb6e5b6beca0f8e0dfae arbeitszeitcheck-1.2.2.tar.gz

0 commit comments

Comments
 (0)