"Verbindung testen" only appeared after a config was already saved,
so a fresh/never-configured tenant had no way to validate connection
details at all. Now the button is always visible; POST /ldap/test-connection
accepts optional ad-hoc serverUrl/bindDn/bindPassword and falls back
field-by-field to the saved config for anything omitted (bindPassword
in particular, since the form never re-sends the masked saved password).
Verified locally: tested with typed-but-unsaved values (base DN left
blank, nothing saved) and got a real connection attempt/error back,
not a 404 "no config" response.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
CreateLdapConfigDto's optional fields (searchFilter, syncIntervalMin,
isActive, groupFilterDns) had class-field default initializers.
NestJS's ValidationPipe instantiates DTOs via plainToInstance, which
applies those defaults even when the field is absent from the request
body -- so any partial PATCH not including a given field silently
reset it to the hardcoded default instead of leaving it untouched.
Caught by testing the new groupFilterDns-only PATCH: saving the group
filter alone reset searchFilter back to "(objectClass=person)",
clobbering the configured Active Directory filter. The service layer
already has its own `?? default` fallback for create, so the DTO
initializers were redundant and unsafe. Removing them makes updateConfig's
existing "only set if dto.field !== undefined" pattern behave correctly
for every optional field, not just the ones sent together in one request.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Persists per-tenant AD group/OU DNs to restrict which directory
entries get synced. Empty array (default) preserves current
behavior — import everyone under base DN.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- LdapService uses ldapts for DIRECTORY SYNC ONLY (anti-pattern avoidance)
- LdapConfigService creates default field mappings per D-16 (displayName, mail, sAMAccountName)
- Custom field mappings can be added/removed per D-17
- Per-tenant LDAP config per D-18
- syncUsersForTenant deactivates users removed from LDAP per D-15
- LdapSyncScheduler sets tenant context explicitly per Pitfall 2
- Manual sync endpoint POST /ldap/sync per D-14
- Auto-sync cron checks syncIntervalMin per D-14
- Test connection endpoint for LDAP config validation
- OpenLDAP + phpLDAPadmin added to docker-compose.dev.yml
- LDAP search filter sanitization per T-02-16
- bindPassword never returned in API responses per T-02-17