- Added MailerAttachmentPolicy for validating email attachments against server rules.
- Introduced fis.specialties.js for managing hidden maintenance actions via an admin interface.
- Created fis.specialties.scss for styling the specialties management UI.
- Added German localization for specialties management in fis.specialties_txt_de.js.
- Developed CSS for specialties management in fis.specialties.css.
- Implemented server-side stored procedure fds__admin_backupAndClearInvoiceFile for backing up and clearing invoice files.
- Created fds__invoice_file_backups table to store backup records of invoice files.
Retires Fuchs_intranet.debug_log() and every direct EXECUTE [dbo].[fds__admin_logdebug]
call in favor of a single path: ILogger. A new SQL log sink (OCORE.MultiLogger.SqlLoggerProvider,
gated by Fuchs:Logging:SqlSink:Enabled, default on) mirrors every _logger.LogWarning/-Error/
-Critical call into [dbo].[fds__debuglog] via a new fds__admin_logdebug_ext proc, at Warning+.
- Program.cs registers the sink and RequestLogScopeMiddleware (request id/path/authenticated
user, pushed after UseAuthentication) so every log line in a request — including ones written
deep inside OCORE's SQL helpers — is attributed automatically.
- FIS_SQLOptions, IntranetController.Do's catch-all, PdfPreviewAsync, and the banking-upload
handlers now log once, with an explicit EventId preserving the exact CodeReference text the
retired debug_log() calls used to write, so existing dashboards/queries over fds__debuglog
keep working unchanged.
- Fuchs_DataService/FdsMfr.cs's FdsSqlOptions had the identical double-write hazard (it's hosted
in the same process per ADR 0010) — the original 2026-09-16 log review's mfr__getSchema/
fds__getUpdateableRequests deadlock rows came from exactly this class. Fixed the same way.
- fds__debuglog gains LogLevel/Machine/Category/Account/AuthUser/IsDebug columns; the legacy
fds__admin_logdebug proc is left in place unused, not dropped.
- FdsDebug.DebugLog (Fuchs_DataService's other ~9 call sites) deliberately left on its direct
DB-write path — no ILogger call sits alongside it there, so no duplication risk today.
See ADR 0024 (supersedes 0023) and Docs/Concepts/error-logging-pipeline.md.
New tests: ErrorLoggingTests (FIS_SQLOptions), FdsSqlOptionsTests, RequestLogScopeMiddlewareTests.
694/694 pass (the 4 PdfPipelineTests failures seen under full-suite parallel runs are a
pre-existing, unrelated PdfSharp global-font-resolver test-isolation flake — they pass both
individually and in most full-suite runs).
Bumps the OCORE submodule to 3137b56 (SQL sink hardening: redaction matches short fragments
as whole identifier segments, per-entry-tolerant serialization, lazy dataSerialized, opt-in
SqlLoggerOptions.IncludeCategory, LogEntry.Category/AuthUser capture).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- Introduced a new module for managing user groups (`usrgrp`) in the administration interface.
- Implemented CRUD operations for user groups: list, create, rename, and delete.
- Added authorization checks to ensure only users with appropriate permissions can manage groups.
- Created corresponding frontend JavaScript and SCSS files for the new module.
- Updated documentation to reflect the new group management functionality and its authorization model.
- Added SQL stored procedures for group management operations.
- Established a new login script for database access, ensuring proper security practices.
The Admin status pill previously turned green whenever the mailer was
enabled in config, without proving the account/token actually work.
Add IComService.VerifyCredentialsAsync (GET /mailer/fc?fn=verify, also
passing serverid when configured so the API confirms this server
belongs to the account) and wire it into a new "email" system-status
probe, so the pill only goes green once the Mailer API itself confirms
the credentials.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Wire up two previously-unwired stored procedures for the usr module:
- fis_admin_createUserAccount gained the missing @authaccount +
intranet_admin auth gate, a duplicate-email check, and now returns
the (possibly auto-generated) password so it can be emailed to the
new user, mirroring fis_admin_resetUserPassword's pattern.
- fis_admin_delUserAccount gained the same missing auth gate plus a
guard against an admin deleting their own account.
New /do/usr/create and /do/usr/delete endpoints in
IntranetController.AdminUsers.cs, a "Neuer Benutzer" button and a
"Benutzer löschen" ribbon action in fis.usr.js, and unit tests for the
new welcome-email content (BuildWelcomeEmail).
Also restyle the user list (fis.usr.scss) from a plain bordered table
to a card-style row grid with avatar-initial badges and status pills,
matching the Admin dashboard's visual language.
Documented as ADR 0020 and in the admin-user-management concept doc.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
"Set mit Preis" / "Nur Set mit Preis" collapsed every block into an inserted
"Gesamtumfang pauschal" row, nulled/removed all lines and cleared the user-defined
set structure. Both modes now convert every still-unconverted top-level set:
the set line takes the sum of its subtree, its members render without a price
(setprice) or are removed from itm + items (setonly); lines outside a set stay
individually priced and several sets stay separate lines. Nested sets are priced
once via their top-level set. One conversion primitive (ConvertSetHeader) now
backs all three triggers; item.setprice is a no-op on an already-converted set
(a repeated delta used to reset the set price to 0). The header's price_net is
mirrored too (flat PDF path unit price), and Build treats a null total_net as
"no price" like the flat path. The editor checks for a set before offering the
modes and the menu entry stays available for sets added later.
ADR 0009 is superseded by 0019; INVOICE_SET_PRICING.md rewritten accordingly.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Lets a back-office user correct/define which invoice line belongs to
which "set" and how deep it is nested, instead of relying only on the
implicit "everything after a Set header until the next Set" grouping
fds__prepInvoice derives. Sets may contain sets; every change applies
immediately to the cached draft session and is reflected in the editor
and PDF (ADR 0006/0008).
Backend:
- InvoiceSetStructure: pure parent-link forest (assign, change level,
create, place/move-sibling, depth-first linearise + level recompute).
- InvoiceDraftSetStructureDeltas: new inv/dpatch targets set.assign,
set.level, set.create, set.move.
- InvoiceSetPricing.Build is now order-preserving and nesting-aware
(governed by the nearest converted ancestor); the set-item switch
sums a header's transitive descendants so nested conversions never
double-count.
- FuchsPdf indents nested set members per level, mirroring the editor.
Frontend:
- New fis.inv_sets.js: "Set-Struktur bearbeiten" dialog — per-block
table of all lines with drag & drop reorder (before/after/into),
▲▼ order and ◀▶ level buttons, fold/unfold per set (view-only), and
a create bar for new Set/Text lines. Posts one delta per action; the
dialog is a pure view of the server state (ADR 0006).
- _Layout.cshtml / fis_main.js: cache-bust the dynamically imported
per-module bundles (web/fis.<mdl>.<locale>.js/.css) with an asset
version derived from the newest bundle write time, so a gulp rebuild
is picked up without a stale cached module.
Docs: ADR 0016, live-draft-editing concept, INVOICE_SET_PRICING.md,
USER_GUIDE.md, ARCHITECTURE.md updated. Tests: InvoiceSetStructureTests
(new) + additions to InvoiceDraftServiceTests/InvoiceSetPricingTests.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Splits fn=admin into two independent modules: the original status
dashboard stays at fn=admin, user management moves to a new fn=usr
(IntranetController.AdminUsers.cs, fis.usr.js). Both are now reached
through a single "Administration" sidemenu dropdown (Systemüberwachung /
Benutzerverwaltung) gated by one shared fds_sys > 4 check, per ADR 0015
(supersedes 0014's "fold into one module" choice).
Also fixes the password-reset validation to check only a plain 6-char
minimum instead of silently also requiring ValidatePassword's default
2-uppercase/2-lowercase/2-digit composition, which contradicted the
"mind. 6 Zeichen" message shown to the admin.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Wires the previously-unused fis_admin_* user/group stored procs into the Admin
module (fds_sys-gated), adds a users grid with a per-row ribbon (reset
password, change email, manage group membership), and always emails a
password reset result to the user rather than showing it to the admin.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Completes the eRechnung output path: finalized invoices are emitted as a
ZUGFeRD/Factur-X EN 16931 hybrid (DATEV) or, when a Leitweg-ID is present, as
XRechnung 3.0 for B2G. Both are externally validated as ACCEPTED (0 errors) and
PDF/A-3B COMPLIANT against the ProcessWeb eInvoice service.
- ERechnungMapper: FdsInvoiceData -> EN 16931 model. Seller master data now from
Fuchs:ERechnung:Seller config (VAT id BT-31, Steuernummer BT-32, optional
Handelsregister BT-30, IBAN/BIC, contact). Adds payment terms BT-20/BT-9
(BR-CO-25), buyer VAT id, §13b reverse charge, and the service date/period
(BT-72 / BG-14) parsed from ProvisionPeriod (BR-DE-TMP-32). B2G -> XRechnung
profile with the required electronic addresses/contact.
- ERechnungValidator: client for POST /validatepdf (EN 16931 XML + PDF/A-3 in
one call). A pure "scenario not matched" with zero errors is not treated as a
hard failure; real errors optionally withhold the hybrid (FailOnError).
- ERechnungSettings: seller + validation config; wired in Program.cs; ServiceUrl
in appsettings.
- Online editor: structured German-only dialogs for the recipient address
(incl. Leitweg-ID) and the service date/period (single date or range).
- Bumps the eRechnungLib submodule to the CII rsm-namespace / PDF-A subtype fix.
Fuchs.Tests 514/514, eRechnungLib 97/97.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Created a new function `fds__getCompanyAddressJson` to return a company's postal address as a structured JSON object.
- Modified stored procedures `fds__createInvoice`, `fds__setInvoice`, and `fds__prepInvoice` to include a new parameter `@SendToAddressJson` for handling the address data.
- Updated the invoice table and user-defined types to accommodate the new `SendToAddressJson` field.
- Ensured that the address data is properly retrieved and stored in the invoice records.
- Introduced new JavaScript file `fis.admin_txt_de.js` for German translations of administration-related terms and messages.
- Created `fis.admin.css` for styling the administration interface, including layout, cards, and buttons.
- Added `fis.admin.de.js` for the main functionality of the administration module, implementing features such as system status checks and email testing.
- Minified version of the German JavaScript file created as `fis.admin.de.min.js`.
- Minified CSS file created as `fis.admin.min.css` for optimized loading.
- Introduced comprehensive unit tests for the Fuchs_DataService library, covering DATEV header formatting, CSV/XML generation, and FdsMfrClient construction.
- Implemented tests for FdsMfr.UpdateNeed parsing and FdsShared utility helpers, ensuring correct functionality and stability.
- Added tests for FdsConfig and FdsMfrClient to validate configuration resolution and client construction.
Document decisions on backend-authoritative invoice and reminder handling
- Created ADR 0008 to clarify that all invoice types and reminder stages are backend-authoritative during drafting and previewing.
- Established that all calculations and settings must be processed server-side, ensuring consistency between online editor and PDF outputs.
Define irreversible mutations for set-price modes in invoices
- Documented ADR 0009 to specify that the "Set mit Preis" and "Nur Set mit Preis" operations are irreversible mutations affecting service request blocks.
- Clarified that these operations are not display toggles but actual data changes, ensuring clear expectations for invoice handling.
Transition MFR ERP sync to in-process execution within the web app
- Created ADR 0010 to outline the migration of Fuchs_DataService from a standalone service to an in-process library within the Fuchs web application.
- Updated configuration and logging management to be handled by the host application, streamlining the sync process.
Add publish profile and periodic hosted service for job scheduling
- Introduced a publish profile for deployment to a specified folder.
- Implemented PeriodicHostedService to manage multiple independent jobs, including the MFR ERP sync, with configurable execution intervals.
Add dotnet-tools.json for EF Core CLI tools
- Included dotnet-tools.json to manage the version of dotnet-ef for Entity Framework Core migrations and commands.
Move the invoice draft editor to a backend single source of truth: an
in-memory InvoiceDraftSession (per-token, cached) holds the editable payload,
server-computed sums/VAT and validation, plus an automatic change history. The
browser posts single edits; the server recomputes and signals the editing
session over a dedicated SignalR hub (DraftPreviewHub) to re-fetch.
This reverses the previously-documented stateless editor (EVAL_live_invoice_editing,
INVOICE_LIFECYCLE §10), by explicit product decision — captured in ADR 0006 and 0007
plus the live-draft-editing concept doc.
Backend (this milestone):
- InvoiceDraftSession + ChangeHistoryEntry data holders
- InvoiceDraftCalculator: pure port of quantChange/invSumUpdate (§13b, VAT-by-rate)
and consistency checks — fully unit-tested
- IInvoiceDraftCache/InvoiceDraftCache: in-memory store with idle sliding TTL
- IInvoiceDraftService/InvoiceDraftEditService: open (payload or DB reload), patch,
build state, flush via existing RegisterInvoiceAsync (no new persistence), preview
from cache, discard (DB reload), history
- InvoiceDraftExpiryService: pre-expiry warning + eviction-with-reason
- DraftPreviewHub + IDraftNotifier/DraftNotifier: targeted draftReady/draftExpiring/
draftClosed signals per draft token
- inv/dopen|dstate|dpatch|dpreview|dsave|dhistory|ddiscard|dclose endpoints; save
reports success/failure via the existing EventService
- DI + hub mapping in Program.cs
Frontend (additive foundation): $fis.draft SignalR client for /draftpreview.
The editor DOM inversion (routing deltas, rendering from server state) is the
next, separately-verified step; existing endpoints are unaffected.
Tests: 30 new (calculator, cache, expiry, patch/history, flush); 306 total passing.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Updated FdsSqlOptions to accept an optional ILogger parameter for improved error logging.
- Modified FdsMfr and FdsMfrClient classes to pass the logger instance to FdsSqlOptions.
- Added detailed error logging in various methods to capture SQL execution issues and file handling errors.
- Improved documentation for FdsSqlOptions to clarify logging behavior.
- Updated Archive class to log compression errors, enhancing traceability of failures.
- Adjusted project configuration to suppress specific warnings related to transitive dependencies.
- Added NuGet.config to define package sources for dependency management.
- Updated submodule references for OCORE and related projects.