134 Commits

Author SHA1 Message Date
shahondin1624 a0ad92dd47 Merge pull request 'refactor(MemberService): extract generic syncSubEntities() method' (#204) from fix/duplicate-sync-methods into main 2026-04-30 08:14:04 +02:00
shahondin1624 19adf0ba87 chore: move issue-204 plan to done 2026-04-30 08:13:11 +02:00
shahondin1624 bfb57b4e1e refactor(MemberService): extract generic syncSubEntities() method
Factor out the duplicated sync logic from syncAddresses(), syncPhones(),
and syncEmails() into a single generic syncSubEntities() method that
accepts callables for fetch/update/create/delete operations. Each
specialized sync method is now a thin ~10-line wrapper.

(Closes #204)
2026-04-30 08:12:35 +02:00
shahondin1624 c4f5f8e7fb Merge pull request 'fix(MemberService): wrap multi-step writes in database transactions' (#203) from fix/missing-database-transactions into main
Database Portability Tests / Unit Tests (PlatformHelper) (push) Failing after 38s
Database Portability Tests / Integration (mysql) (push) Has been skipped
Database Portability Tests / Integration (postgres) (push) Has been skipped
Database Portability Tests / Integration (sqlite) (push) Has been skipped
Database Portability Tests / Verify no MySQL-specific SQL (push) Successful in 6s
2026-04-29 22:11:02 +02:00
shahondin1624 0ffc993d3f chore: move issue-203 plan to done
Database Portability Tests / Unit Tests (PlatformHelper) (pull_request) Failing after 37s
Database Portability Tests / Integration (mysql) (pull_request) Has been skipped
Database Portability Tests / Integration (postgres) (pull_request) Has been skipped
Database Portability Tests / Integration (sqlite) (pull_request) Has been skipped
Database Portability Tests / Verify no MySQL-specific SQL (pull_request) Successful in 5s
2026-04-29 22:09:20 +02:00
shahondin1624 e1d24d4d54 fix(MemberService): wrap multi-step writes in database transactions
Add IDBConnection dependency to MemberService and wrap create(),
update(), and softDelete() in transactions (beginTransaction/commit/
rollback). This ensures atomicity when inserting/updating members
alongside sub-entities (addresses, phones, emails) — a failure at
any step now rolls back the entire operation instead of leaving
orphaned records.

(Closes #203)
2026-04-29 22:08:38 +02:00
shahondin1624 5c67fc763a Merge pull request 'Fix findArchived() filtering all members in memory (Closes #202)' (#202) from fix/find-archived-filtering-in-memory into main
Database Portability Tests / Unit Tests (PlatformHelper) (push) Failing after 37s
Database Portability Tests / Integration (mysql) (push) Has been skipped
Database Portability Tests / Integration (postgres) (push) Has been skipped
Database Portability Tests / Integration (sqlite) (push) Has been skipped
Database Portability Tests / Verify no MySQL-specific SQL (push) Successful in 5s
2026-04-29 21:14:55 +02:00
shahondin1624 ccda3ee570 Fix findArchived() filtering all members in memory (Closes #202)
Database Portability Tests / Unit Tests (PlatformHelper) (pull_request) Failing after 42s
Database Portability Tests / Integration (mysql) (pull_request) Has been skipped
Database Portability Tests / Integration (postgres) (pull_request) Has been skipped
Database Portability Tests / Integration (sqlite) (pull_request) Has been skipped
Database Portability Tests / Verify no MySQL-specific SQL (pull_request) Successful in 5s
Replace in-memory array_filter with a dedicated SQL query
WHERE deleted_at IS NOT NULL in MemberMapper::findArchived().

This fixes broken pagination (limit/offset now apply to archived
members only), eliminates unnecessary data transfer, and follows
the same pattern as the countArchived() fix from #201.
2026-04-29 21:13:32 +02:00
shahondin1624 d28dcd4541 Merge pull request 'Fix countArchived() loading all members into memory (Closes #201)' (#201) from fix/n-plus-one-queries-member-list into main
Database Portability Tests / Unit Tests (PlatformHelper) (push) Failing after 38s
Database Portability Tests / Integration (mysql) (push) Has been skipped
Database Portability Tests / Integration (postgres) (push) Has been skipped
Database Portability Tests / Integration (sqlite) (push) Has been skipped
Database Portability Tests / Verify no MySQL-specific SQL (push) Successful in 5s
2026-04-29 19:17:36 +02:00
shahondin1624 d4e25fe739 Fix countArchived() loading all members into memory (Closes #201)
Database Portability Tests / Unit Tests (PlatformHelper) (pull_request) Failing after 38s
Database Portability Tests / Integration (mysql) (pull_request) Has been skipped
Database Portability Tests / Integration (postgres) (pull_request) Has been skipped
Database Portability Tests / Integration (sqlite) (pull_request) Has been skipped
Database Portability Tests / Verify no MySQL-specific SQL (pull_request) Successful in 5s
Replace in-memory filtering with a SQL COUNT(*) query in the mapper,
matching the pattern of the existing countAll() method.
2026-04-29 19:13:52 +02:00
shahondin1624 967bacf231 docs: add tea CLI workflow to CLAUDE.md for Gitea operations 2026-04-28 21:56:46 +02:00
shahondin1624 ee569250ad Fix N+1 query problem in MemberService (Closes #200)
Database Portability Tests / Unit Tests (PlatformHelper) (push) Failing after 40s
Database Portability Tests / Integration (mysql) (push) Has been skipped
Database Portability Tests / Integration (postgres) (push) Has been skipped
Database Portability Tests / Integration (sqlite) (push) Has been skipped
Database Portability Tests / Verify no MySQL-specific SQL (push) Successful in 5s
- MemberMapper: 8 new *WithRelations() methods that fetch members with
  addresses, phones, and emails in a single query using LEFT JOINs
- MemberMapper: addJoinClauses() and fetchWithRelations() private helpers
  that handle JOIN duplication (one member × multiple sub-entities)
- MemberService: refactored findAll, findByFamily, findByStatus, search,
  findByBirthdayThisMonth, findWithUnpaidFees, findFiltered, fullTextSearch
  to delegate to joined mapper methods
- MemberService: added arrayToMember() and arrayToAddress() helpers so
  buildMatchContext() works with flat-array results from fullTextSearch
- MemberServiceTest: updated all existing tests to mock new method names
  and return flat-array format with nested sub-entities
- MemberServiceTest: added 10 new tests covering joined methods, backward
  compatibility, and correct shape of returned data
- Moved issue-200 plan from open/ to done/
2026-04-28 21:35:42 +02:00
shahondin1624 b29a268b1d Restructure .plans/ into done/ and open/ subdirectories
- Move completed plan files to .plans/done/
- Move 18 open plan files to .plans/open/
- Update .gitignore to exclude .verified_plans temp file
- Verified all 18 open plans still describe unimplemented issues
2026-04-28 20:30:55 +02:00
shahondin1624 53b3fd945a Release v0.3.2: Inventory tracking, test infra, and bugfixes
Database Portability Tests / Integration (mysql) (push) Has been skipped
Database Portability Tests / Integration (postgres) (push) Has been skipped
Database Portability Tests / Integration (sqlite) (push) Has been skipped
Database Portability Tests / Verify no MySQL-specific SQL (push) Successful in 5s
Database Portability Tests / Unit Tests (PlatformHelper) (push) Failing after 43s
Inventory:
- General material, stock items, and sales CRUD
- Category management with CategoryPicker component
- Inventory reports service
- Database migrations and mappers

Frontend:
- Inventory view with tabs (Allgemeinmaterial, Verkaufsmaterial, Verkäufe)
- Forms for general material, stock items, and sales
- Search bar fix: flexbox wrapper with inline icon replaces broken NcTextField icon slot

Tests:
- All 1,491 tests pass (zero errors, warnings, deprecations)
- BundleImportServiceTest: fixed ZipArchive empty-file deprecation
- BundleImportService: null-coalescing for targetFields
- PHPUnit test infra: make test target via container

CLAUDE.md:
- Added Testing section as PR gating criterion
v0.3.2
2026-04-22 10:15:22 +02:00
shahondin1624 ff60c4088e Add Testing section to CLAUDE.md
All PHPUnit tests must pass before merging. Zero errors/warnings/deprecations is the baseline.
2026-04-22 10:14:01 +02:00
shahondin1624 9a55ef4677 Fix BundleImportServiceTest: 0 errors, 0 warnings
Database Portability Tests / Integration (mysql) (push) Has been skipped
Database Portability Tests / Integration (postgres) (push) Has been skipped
Database Portability Tests / Integration (sqlite) (push) Has been skipped
Database Portability Tests / Verify no MySQL-specific SQL (push) Successful in 4s
Database Portability Tests / Unit Tests (PlatformHelper) (push) Failing after 51s
- createZipContent: check file_exists before file_get_contents, handle
  ZipArchive close on empty archives
- extractCsvFiles: check filesize before ZipArchive::open to avoid
  'Using empty file is deprecated' warning
- previewBundle: use null coalescing for $schema['targetFields']
2026-04-22 10:09:13 +02:00
shahondin1624 a9f3dc82ae Add Makefile test target for running PHPUnit inside container
Supports:
  make test              # all suites (Unit, Integration, DatabasePortability)
  make test suite=Unit
  make test suite=Integration
  make test suite=DatabasePortability

Also switches composer to install dev dependencies so PHPUnit is available.
2026-04-22 09:59:06 +02:00
shahondin1624 38858c8002 Bump version to 0.3.1
Fix inventory search bar: use flexbox wrapper with inline Magnify icon
and native input instead of NcTextField with broken :show-icon slot.
v0.3.1
2026-04-22 09:46:52 +02:00
shahondin1624 7450160e9e (Closes #?) Fix inventory search bar icon overlap with text input
The NcTextField :show-icon prop with #icon slot doesn't work correctly
in @nextcloud/vue v9 — it renders a default icon that overlaps the text.
Replaced with a wrapper div that uses an absolutely positioned Magnify
icon alongside a clean NcTextField input.
2026-04-22 09:38:37 +02:00
shahondin1624 05c62d1a21 Bump version to 0.3.0 for release v0.3.0 2026-04-22 08:53:46 +02:00
shahondin1624 5a3e1c9ef2 feat: bulk-reveal encrypted Allergien on member list (admin-only) (#198)
Database Portability Tests / Unit Tests (PlatformHelper) (push) Failing after 35s
Database Portability Tests / Integration (mysql) (push) Has been skipped
Database Portability Tests / Integration (postgres) (push) Has been skipped
Database Portability Tests / Integration (sqlite) (push) Has been skipped
Database Portability Tests / Verify no MySQL-specific SQL (push) Successful in 4s
v0.2.11
2026-04-17 21:58:15 +02:00
shahondin1624 bcf92aeaea chore: pin container DNS to 1.1.1.1 / 8.8.8.8
The container inherits the host's resolver by default. If the host is
behind a DNS64 gateway (common for IPv6-transitioned home networks,
some mobile carriers, and certain NAT64 setups), the resolver returns
IPv6-only `64:ff9b::/96`-synthesized addresses for IPv4-only services.
A default Docker bridge network is IPv4-only, so those synthesized
addresses are unreachable and every outbound HTTPS call (self-update
check, Nextcloud calendar/contacts sync) fails with "No DNS record
found". Pinning to public resolvers sidesteps the synthesis entirely.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-17 21:51:32 +02:00
shahondin1624 62f7053e5b feat: manual update via tarball + signature upload (#197) v0.2.10 2026-04-17 21:37:53 +02:00
shahondin1624 d960361ba0 fix: surface real errors + restore sub-entity saves on member update (#196)
Database Portability Tests / Unit Tests (PlatformHelper) (push) Failing after 37s
Database Portability Tests / Integration (mysql) (push) Has been skipped
Database Portability Tests / Integration (postgres) (push) Has been skipped
Database Portability Tests / Integration (sqlite) (push) Has been skipped
Database Portability Tests / Verify no MySQL-specific SQL (push) Successful in 4s
v0.2.9
2026-04-17 21:31:07 +02:00
shahondin1624 fa702e30f3 feat: Abfrage-Builder NOT + visual brackets + full field coverage (#194) (#195)
Database Portability Tests / Integration (mysql) (push) Has been skipped
Database Portability Tests / Integration (postgres) (push) Has been skipped
Database Portability Tests / Integration (sqlite) (push) Has been skipped
Database Portability Tests / Verify no MySQL-specific SQL (push) Successful in 3s
Database Portability Tests / Unit Tests (PlatformHelper) (push) Failing after 36s
v0.2.8
2026-04-17 20:17:08 +02:00
shahondin1624 eb555a2fbd feat: add consistent rows-per-page setting to all display tables
Add shared PaginationControls component and usePageSize/useClientPagination
composables so every list view has a configurable "Zeilen pro Seite" dropdown
(10/20/50/100) persisted per table to localStorage. Also fix MemberController
returning paginated count instead of true total when no filters are active.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
v0.2.7
2026-04-12 18:10:05 +02:00
shahondin1624 53f42dca5f chore: bump version to 0.2.6 for release
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
v0.2.6
2026-04-12 16:19:40 +02:00
shahondin1624 da856faf08 fix: seed default Stufen via IRepairStep for PostgreSQL/SQLite compatibility
Database Portability Tests / Unit Tests (PlatformHelper) (push) Failing after 36s
Database Portability Tests / Integration (mysql) (push) Has been skipped
Database Portability Tests / Integration (postgres) (push) Has been skipped
Database Portability Tests / Integration (sqlite) (push) Has been skipped
Database Portability Tests / Verify no MySQL-specific SQL (push) Successful in 4s
The original seed migration (Version000014) runs inside a transaction that
silently fails on PostgreSQL and SQLite during batch migration execution.
Add a post-migration IRepairStep that runs outside the migration transaction
and idempotently inserts the 3 default Stufen if the table is empty. MySQL
installs with existing data are unaffected (skips automatically).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 16:11:11 +02:00
shahondin1624 f9ff72bf21 feat: add sortable columns to FamilyList and FeeOverview, fix backup UI
Make Mitglieder, Aktive Kinder, and Ansprechpartner columns sortable in
FamilyList. Add sorting to all FeeOverview columns (Mitglied, Betrag,
Bezahlt, Zahlungsdatum). Minor backup store and view fixes.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 16:11:02 +02:00
shahondin1624 82d27d419d fix: improve self-update reliability and error handling
Add proper error handling in BackupController update endpoints instead of
generic handleAction. SelfUpdateService now auto-runs occ upgrade after
update, handles .tar.gz file extensions for PharData, accepts configurable
min download size for signatures, and fixes apps_paths config parsing.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 16:10:46 +02:00
shahondin1624 06ca348a0d feat: improve Lager file management with dedicated folder creation
Add ensureLagerFolder endpoint and getLagerFilesById to browse Lager files
by ID rather than manual path. Rework LagerDetail file browser UI and add
folder links in LagerList.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 16:10:31 +02:00
shahondin1624 dc6e4d910d feat: add time-of-day (uhrzeit) field to injury tracking
Add optional uhrzeit column to mv_injuries via migration 17. Update the
Injury entity, service, form component, and list view to capture and
display the time an injury occurred.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 16:10:18 +02:00
shahondin1624 c67b9f04a0 chore: bump version to 0.2.5 and add webpack content hash for cache busting
Version bump across info.xml, webpack.config.js, and main.js. Webpack now
outputs content-hashed filenames and templates/index.php dynamically resolves
them. Makefile cleans stale JS bundles before rebuilding.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 16:10:06 +02:00
shahondin1624 9ed69b78ca feat: database portability — support PostgreSQL and SQLite (Closes #192)
Database Portability Tests / Unit Tests (PlatformHelper) (push) Failing after 45s
Database Portability Tests / Integration (mysql) (push) Has been skipped
Database Portability Tests / Integration (postgres) (push) Has been skipped
Database Portability Tests / Integration (sqlite) (push) Has been skipped
Database Portability Tests / Verify no MySQL-specific SQL (push) Successful in 4s
2026-04-12 13:46:22 +02:00
shahondin1624 6ca14beada feat: additive quickfilters, role filters, address columns, saved filters & fix all tests
- Make quickfilters combinable (status + rolle + birthday + unpaid fees with AND logic)
- Add Mitglieder/Erziehungsberechtigte role quickfilters
- Add PLZ and Wohnort columns from primary address for KJR reports
- Add saved filter system (localStorage-persisted, create/apply/delete)
- Backend: unified findFiltered() in MemberMapper/MemberService/MemberController
- Fix all 75 pre-existing test failures (constructor mismatches, optional geburtsdatum,
  DsgvoController body reading, FileController lagerFiles API, CalDavBackend stub)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-11 17:45:07 +02:00
shahondin1624 ea8451710f feat: add calendar sync button with CalDAV backend integration
Adds a "Kalender-Synchronisation" section to Settings that lets users
trigger a full sync of member birthdays and Juleica reminders to the
Nextcloud CalDAV backend. The calendar is created automatically if it
doesn't exist. Users can also check/enable the Calendar UI app.

- CalendarSyncService: add CalDavBackend integration (ensureCalendarExists,
  fullSyncCalDav, getCalendarStatus, enableCalendarApp)
- CalendarController: new REST endpoints (status, sync, enable-app)
- calendar.js Pinia store: frontend state management
- Settings.vue: calendar sync UI with status display and sync button
- CLAUDE.md: add workflow rule for commit+push after each feature

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-11 16:18:29 +02:00
shahondin1624 c51439179f docs: add production installation instructions to README
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
v0.2.1 v0.2.2 v0.2.3 v0.2.4 v0.2.5
2026-04-10 23:23:39 +02:00
shahondin1624 d48e2b7d9d feat: v0.2.0 — backup system, self-update with Ed25519 signing, column pickers, import fixes
Major features:
- Full backup & restore system (JSON snapshots of all 20 tables + settings)
  - Web UI, REST API, OCC CLI commands, scheduled background job
- Self-update from Gitea releases with Ed25519 signature verification
- Configurable column visibility on all data tables (persisted via localStorage)

Fixes:
- NC admin group fallback for PermissionService (IGroupManager)
- Bundle import inline error correction (editable error rows)

New files: BackupService, BackupSettingsService, BackupController, BackupJob,
SelfUpdateService, 4 OCC commands, ColumnPicker component, Backup.vue,
Ed25519 signing scripts, signature verification tests (18 tests)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
v0.2.0
2026-04-10 23:11:51 +02:00
shahondin1624 27cedd849d feat: add Juleica number and expiry date with calendar reminder (Closes #160) (#191) 2026-04-10 19:43:06 +02:00
shahondin1624 4316c5f2b5 feat: make Geburtsdatum optional for members (Closes #162) (#190) 2026-04-10 19:38:26 +02:00
shahondin1624 64ece89101 fix: imported records cannot be edited after import (Closes #161) (#189) 2026-04-10 19:33:18 +02:00
shahondin1624 b6a7854a1b security: enforce access control on CalendarSync and ContactsSync (Closes #170) 2026-04-10 18:56:16 +02:00
shahondin1624 58968331eb security: enforce CSRF protection on POST/DELETE export endpoints (Closes #171) 2026-04-10 18:50:25 +02:00
shahondin1624 af006d7250 fix: standardize frontend date formatting with shared utility (Closes #175) 2026-04-10 18:45:25 +02:00
shahondin1624 21b025af87 fix: prevent CSV injection by escaping formula characters (Closes #174) (#185) 2026-04-10 16:27:39 +02:00
shahondin1624 089a775b84 fix: add X-Content-Type-Options nosniff header to downloads (Closes #173) (#184) 2026-04-10 16:25:41 +02:00
shahondin1624 e8eefd48f1 fix: use generic error messages in ImportController 500 responses (Closes #172) (#183) 2026-04-10 16:24:01 +02:00
shahondin1624 fc73393400 fix: set restrictive permissions (0600) on temp files (Closes #169) (#182) 2026-04-10 16:21:54 +02:00
shahondin1624 9968f8c58e fix: reject ZIP entries with path traversal sequences (Closes #168) (#181) 2026-04-10 16:20:40 +02:00
shahondin1624 5f9f45f37d fix: normalize URI by stripping query params in rate limiter (Closes #167) (#180) 2026-04-10 16:19:49 +02:00