schalli
73e107414b
chore: gitignore playwright-mcp and research cache dirs
...
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com >
2026-07-02 08:58:05 +02:00
schalli
610b649bdf
chore: remove handoff and continue-here files (phase 9 complete)
...
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com >
2026-07-02 08:57:52 +02:00
schalli
2869da83c0
chore: planning artifacts + mcp.json update
...
- .mcp.json: Playwright MCP config
- 08-UAT.md: Phase 8 UAT results
- quick task summaries: 260630 user-settings, 260701 calendar domain
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com >
2026-07-02 08:57:44 +02:00
schalli
c8f3361816
fix(dashboard): noCompactor + note edit/preview toggle + widget border
...
Tessera CI/CD / Tests (push) Has been cancelled
Tessera CI/CD / Build & Publish Images (push) Has been cancelled
Tessera CI/CD / Lint & Type Check (push) Has been cancelled
- dashboard-grid: add noCompactor to prevent auto-compaction on drag
- note-widget: edit/preview toggle button (pencil icon), isEditing state,
hideToolbar in preview mode
- widget-wrapper: border-primary/20 accent border
- dashboard-store: console.error on widget add/remove/layout-save failures
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com >
2026-07-02 08:57:37 +02:00
schalli
be3680d0df
feat(user-settings): avatar delete + accent color
...
- DELETE /users/me/avatar endpoint with file cleanup
- PATCH /users/me/accent-color with hex validation (#rrggbb)
- auth.service.ts: include accentColor in user select
- AccountSettingsForm: delete-avatar button + accent color picker/save/reset
- auth-actions.ts: deleteAvatarAction + updateAccentColorAction
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com >
2026-07-02 08:57:31 +02:00
schalli
cc95395889
docs(state): mark phase 9 complete — milestone v1.0 done
...
All 9 phases complete, 40/40 plans executed, UAT 8/8 passed.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com >
2026-07-02 08:46:32 +02:00
schalli
2ddd8473dc
test(09): complete UAT — 8/8 passed (automated Playwright)
...
All cert-manager features verified:
- Module navigation & 4-tab structure
- Inspect PEM (full grid: CN, SANs, expiry, fingerprints)
- Wrong PFX password → user-friendly error
- Split fullchain.pem → per-cert downloads
- Convert PEM→DER (openssl-verified)
- Convert PEM→PFX + password field (openssl-verified)
- Merge 2 PEMs → chain.pem (2 cert blocks)
- Merge 2 certs → bundle.pfx + password (openssl-verified)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com >
2026-07-02 08:46:07 +02:00
schalli
c673faa40d
wip: phase-09 paused after UAT blocker (docker rebuild needed)
2026-07-02 08:23:17 +02:00
schalli
daff82ea76
docs(09-06): complete merge-pfx plan — final plan of phase 09
Tessera CI/CD / Tests (push) Has been cancelled
Tessera CI/CD / Build & Publish Images (push) Has been cancelled
Tessera CI/CD / Lint & Type Check (push) Has been cancelled
2026-07-02 07:55:54 +02:00
schalli
8b15a0099f
feat(09-06): MergeTab multi-file UI + PFX convert option + render tests
...
- actions.ts: mergeCertsAction(files, outputFormat, password?) builds FormData with
multiple file fields; delegates to postForm('merge', ...) (T-09-02/T-09-04)
- MergeTab.tsx: multi-file state (local), file input (multiple), output selector
(pem|pfx), Zusammenfuehren button disabled when < 2 files (data-testid for tests),
onOutputFormatChange callback to page.tsx for shared PasswordField visibility
- ConvertTab.tsx: gains pfx option + onTargetFormatChange callback (same pattern)
- page.tsx: lifts mergeOutputFormat + convertOutputFormat state; showPassword now
also true when active tab's output format is 'pfx'; passes callbacks to tabs
- cert-manager.test.tsx: 5 new tests — MergeTab disabled/enabled by file count,
shared PasswordField appears on pfx output, downloadBase64 called on success;
ConvertTab pfx option present; all 19/19 web tests green
- All production cert-manager files type-clean (pre-existing test type issues unchanged)
2026-07-02 07:52:52 +02:00
schalli
6326064ad3
feat(09-06): GREEN — implement mergeCerts + PFX-create + convertCert pfx output
...
- CertManagerService.mergeCerts: parse all files via detectFormat/parsePemChain/toForgeBuffer,
concatenate PEM chain or build PKCS12 via toPkcs12Asn1
- Open Question 1 resolved: toPkcs12Asn1(null, certs, password) works in node-forge 1.4.0
(null private key accepted — cert-only PFX without fallback needed)
- PFX output requires non-empty password → BadRequestException if missing (T-09-02)
- All forge calls in try/catch → BadRequestException; password never logged (T-09-02)
- bytesToHex→Buffer.from(hex,'hex')→base64 for binary safety (Pitfall 1 avoidance)
- convertCert gains pfx output target (reuses same null-key toPkcs12Asn1 pattern)
- FORMAT_MIME extended with pfx: 'application/x-pkcs12'
- NotImplementedException import removed (no longer used)
- 27/27 API cert-manager tests green; tsc --noEmit exits 0
2026-07-02 07:49:42 +02:00
schalli
f43e92c49f
test(09-06): RED — failing mergeCerts spec (PEM chain + password-PFX round-trip)
...
- 4 new mergeCerts tests: PEM chain 2 blocks, PFX round-trip with password,
missing PFX password → BadRequestException, garbage input → BadRequestException
- Controller enforces 2-file minimum; service tests use 1-2 files directly
- All 4 fail against NotImplementedException stub (RED confirmed)
- Prior 23 tests remain green
2026-07-02 07:47:28 +02:00
schalli
db7a85cc4c
docs(09-05): complete convert-vertical-slice plan
2026-07-02 07:41:34 +02:00
schalli
f89d6566b2
feat(09-05): implement ConvertTab + convertCertAction + render tests
...
Tessera CI/CD / Tests (push) Has been cancelled
Tessera CI/CD / Build & Publish Images (push) Has been cancelled
Tessera CI/CD / Lint & Type Check (push) Has been cancelled
- Add FileResponse interface to actions.ts
- Add convertCertAction(input, targetFormat): builds FormData with
file/pemText/password + targetFormat, calls postForm convert endpoint
- Implement ConvertTab: native select for pem/der/p7b targetFormat,
Konvertieren button with loading swap, error classification, empty state
- On success: calls downloadBase64(filename, content, mimeType)
- 3 new ConvertTab tests: format selector options, downloadBase64 invoked
on success, text-destructive error on format rejection
- All 14 web cert-manager tests green
2026-07-02 07:39:41 +02:00
schalli
59694642dd
feat(09-05): implement convertCert + wire POST /convert (GREEN)
...
- Add FileResponse interface and FORMAT_MIME map to service
- Implement convertCert: parses any input format (PEM/DER/PFX/P7B) via
same logic as parseCert; serializes to pem/der/p7b targetFormat
- DER output uses bytesToHex→Buffer.from(hex,'hex') to avoid utf-8
corruption (Pitfall 1 / T-09-06)
- P7B output: pkcs7.createSignedData + pem.encode (PEM-wrapped PKCS7)
- Wrap all forge ops in try/catch → BadRequestException (T-09-01)
- Controller: add @Body('pemText') + reject when neither file nor pemText
- Fix: re-add NotImplementedException import for mergeCerts stub
- All 23 API cert-manager tests green (including 4 new convertCert)
2026-07-02 07:37:41 +02:00
schalli
37db58b816
test(09-05): add failing convertCert spec (RED)
...
- PEM→DER round-trip identity test (re-parses DER base64 → verify CN)
- DER→PEM round-trip identity test (re-parses PEM base64 → verify CN)
- PEM→P7B: asserts mimeType + P7B contains ≥1 cert
- malformed input: expects BadRequestException
- All 4 fail against NotImplementedException stub (RED confirmed)
2026-07-02 07:35:51 +02:00
schalli
a1da5d9083
docs(09-04): complete split-slice plan
2026-07-02 07:17:46 +02:00
schalli
33b1bc3172
feat(09-04): SplitTab UI + splitCertsAction + render tests
...
- actions.ts: export SplitEntry + SplitResponse interfaces; add splitCertsAction(file) → POST /split
- SplitTab.tsx: Aufteilen button (disabled without file); per-cert download list (bg-secondary rows)
each row: subject.cn, validity.notAfter, Herunterladen button → downloadBase64
empty state / error state (text-destructive) matching InspectTab pattern
- cert-manager.test.tsx: 2 new SplitTab tests (success: 2 download buttons; error: text-destructive)
- All 11 cert-manager web tests green; production files type-clean
2026-07-02 07:16:18 +02:00
schalli
2c4ada347c
feat(09-04): GREEN — implement splitCerts + SplitResponse interface
...
Tessera CI/CD / Tests (push) Has been cancelled
Tessera CI/CD / Build & Publish Images (push) Has been cancelled
Tessera CI/CD / Lint & Type Check (push) Has been cancelled
- Export SplitEntry + SplitResponse interfaces
- splitCerts: PEM chain path via parsePemChain; P7B path via messageFromPem (PEM) or messageFromAsn1 (DER)
- Each cert entry: index, filename cert-N.pem, content base64 PEM, subject.cn, validity.notAfter
- BadRequestException on malformed input / unsupported format (T-09-01)
- POST /split already wired in controller with 5MB file limit (T-09-03, T-09-04)
- All 19 API tests green; type-check clean
2026-07-02 07:14:22 +02:00
schalli
eec66311a7
test(09-04): RED — failing splitCerts spec (fullchain PEM, P7B bundle, malformed)
...
- splitCerts fullchain PEM: expects count 2, two single-PEM-block certs with correct CN
- splitCerts P7B PEM bundle: expects at least one cert in result
- splitCerts malformed input: expects BadRequestException
- All three tests FAIL against NotImplementedException stub (RED confirmed)
- All 16 prior tests still pass
2026-07-02 07:12:37 +02:00
schalli
da676705d9
docs(09-03): complete inspect-slice plan
2026-07-01 23:57:54 +02:00
schalli
64a8e725e7
feat(09-03): InspectTab UI + inspectCertAction + render tests
...
- Added inspectCertAction to actions.ts (JSON path for pemText, multipart path for file)
- Added CertDetails interface to actions.ts (mirrors API response shape)
- Implemented InspectTab: Analysieren button, loading state, grid-cols-2 result grid
- InspectTab handles wrong-password error (t('error.wrongPassword')) and generic error
- Added 2 new InspectTab tests: success grid (subject CN + SHA-256) and error (text-destructive)
- Fixed setup.ts: explicit expect.extend(matchers) for vitest@4.x compatibility
(Rule 1: @testing-library/jest-dom/vitest not extending global expect in vitest 4)
- Fixed existing test: getByText -> getAllByText for 'Analysieren' (now appears in tab nav + button)
- 9/9 cert-manager tests pass
2026-07-01 23:55:41 +02:00
schalli
ba994635e8
feat(09-03): GREEN — implement parseCert + export CertDetails interface
...
- Implemented CertManagerService.parseCert for PEM/DER/PFX/P7B inputs
- Exported CertDetails interface (subject, issuer, validity, san, keyType, keyBits, serialNumber, signatureAlgorithm, fingerprint, pemPreview)
- PFX with wrong password → BadRequestException (T-09-02: never logged, never echoed)
- All forge operations wrapped in try/catch → BadRequestException (T-09-01)
- buildReverseOids() converts OID → human-readable algorithm name
- P7B handles both PEM-wrapped and binary DER (RESEARCH Pitfall 4)
- Controller already wired correctly from Plan 01 (fileSize 5MB, pemText, file, password)
- All 16 cert-manager tests pass (16/16)
2026-07-01 23:41:03 +02:00
schalli
7c2e506a2e
test(09-03): RED — failing parseCert spec (PEM/DER/PFX/wrong-password/malformed)
...
Tessera CI/CD / Tests (push) Has been cancelled
Tessera CI/CD / Build & Publish Images (push) Has been cancelled
Tessera CI/CD / Lint & Type Check (push) Has been cancelled
- Added parseCert describe block with 5 failing tests
- Covers PEM input, DER input, PFX+correct-password, PFX+wrong-password (BadRequestException), malformed input (BadRequestException)
- Existing 11 helper tests still pass
- Fixtures built via node-forge (RSA-1024, DER from asn1.toDer, PFX via toPkcs12Asn1)
2026-07-01 23:39:39 +02:00
schalli
b1aa1d0d2d
wip: phase 09 paused after wave 1 (2/6 plans done)
2026-07-01 23:27:53 +02:00
schalli
76d1a31583
docs(phase-09): update tracking after wave 1
2026-07-01 23:26:56 +02:00
schalli
a9cce06ca3
fix(09-02): repair i18n JSON after wave-1 merge conflict resolution
2026-07-01 23:26:55 +02:00
schalli
4fc448b1d4
merge(09-02): cert-manager web shell + i18n (resolve de/en.json conflict)
2026-07-01 23:26:12 +02:00
schalli
637f4674ca
merge(09-01): resolve app.module.ts conflict (CertManagerModule + FavoritesModule)
Tessera CI/CD / Lint & Type Check (push) Failing after 37s
Tessera CI/CD / Tests (push) Has been skipped
Tessera CI/CD / Build & Publish Images (push) Has been skipped
2026-07-01 23:25:48 +02:00
schalli
7ad4f22a75
docs(09-02): complete cert-manager frontend shell plan
2026-07-01 23:24:25 +02:00
schalli
2cb01f743d
test(09-02): add shell render tests for CertManagerPage (GREEN)
...
- 7 tests passing: title, all 4 tab labels, hidden password field, per-tab empty states
- Tests use vi.mock('next-intl') pattern per project convention (matches sidebar, VehicleTable tests)
- Validates T-09-02 threat mitigation: password field absent on initial render
2026-07-01 23:23:17 +02:00
schalli
3506d60dbe
docs(09-01): complete cert-manager API foundation plan summary
...
- SUMMARY.md with task results, deviations, stub tracking, threat scan
- Self-check: all 9 files found, 3 commits verified, 11 tests green
2026-07-01 23:22:51 +02:00
schalli
8bb5cf208d
feat(09-01): scaffold cert-manager module + shared node-forge helpers (GREEN)
...
- cert-manager.module.ts: OnModuleInit + seedCertManagerModule (CERT-06)
- cert-manager.seed.ts: slug='cert-manager', category='security-tools', isSystem=true
- cert-manager.service.ts: detectFormat, toForgeBuffer, getFingerprint, parsePemChain;
operation stubs parseCert/splitCerts/mergeCerts/convertCert throw NotImplementedException
- cert-manager.controller.ts: 4 POST routes with FileInterceptor/FilesInterceptor
(5 MB limit each), @UseModule('cert-manager') guard, BadRequestException on missing input
- dto/: ParseCertDto, MergeCertsDto, ConvertCertDto
- app.module.ts: CertManagerModule added to imports array
- All 11 Vitest tests pass; type-check clean
2026-07-01 23:21:36 +02:00
schalli
42a41f77d0
feat(09-02): build cert-manager page shell, components, and client helpers
...
- CertManagerPage: 'use client', useTranslations('certManager'), max-w-4xl layout
- Shared input card with DropZone, OR divider, PEM textarea, conditional PasswordField
- PasswordField renders null when show=false (T-09-02 threat mitigation)
- Tab nav: Analysieren / Aufteilen / Zusammenfuehren / Konvertieren
- Tab stubs: InspectTab, SplitTab, MergeTab, ConvertTab (empty state only)
- actions.ts: API_URL const, downloadBase64(atob->Blob->URL), postForm(credentials:'include')
- File/paste mutual exclusion: selecting one clears the other
- No shadcn/Radix; Tailwind utilities only; inline SVG eye icon
2026-07-01 23:20:10 +02:00
schalli
a06694f915
test(09-01): add failing spec for cert-manager seed + helpers (RED)
...
- Test: seedCertManagerModule calls seedModule with slug='cert-manager',
category='security-tools', isSystem=true
- Test: detectFormat returns pem/der/pfx/p7b based on extension + content sniff
- Test: getFingerprint returns uppercase colon-separated hex (sha1 + sha256)
- Test: parsePemChain returns array of length 2 for two concatenated PEMs
2026-07-01 23:18:08 +02:00
schalli
82a80e7634
feat(09-02): add certManager i18n namespace (de + en)
...
- Added certManager namespace to de.json with full key set (tabs, dropZone, paste, password, or, actions, emptyState, error)
- Added certManager namespace to en.json with matching key structure
- German copy matches UI-SPEC Copywriting Contract exactly
- Both files share identical key paths under certManager
2026-07-01 23:17:58 +02:00
schalli
a13a8a763f
chore(09-01): install node-forge + Vitest runner for @tessera/api
...
- Add node-forge@^1.4.0 runtime dependency (certificate crypto)
- Add @types/node-forge@^1.3.14 and vitest@^3 dev dependencies
- Create apps/api/vitest.config.ts (environment: node, passWithNoTests)
- Add test + test:watch scripts to apps/api/package.json
2026-07-01 23:17:23 +02:00
schalli
812eb06d9b
docs(09): create phase plan + resolve open questions
2026-07-01 16:28:31 +02:00
schalli
063666af3b
docs(09): create cert-manager phase plan (6 plans)
Tessera CI/CD / Lint & Type Check (push) Failing after 41s
Tessera CI/CD / Tests (push) Has been skipped
Tessera CI/CD / Build & Publish Images (push) Has been skipped
2026-07-01 16:24:31 +02:00
schalli
ad7de8de2d
docs(09): research phase 9 cert-manager module
Tessera CI/CD / Lint & Type Check (push) Failing after 43s
Tessera CI/CD / Tests (push) Has been skipped
Tessera CI/CD / Build & Publish Images (push) Has been skipped
2026-07-01 16:05:42 +02:00
schalli
6ee31a22fb
docs(09): UI design contract
2026-07-01 15:49:15 +02:00
schalli
09d5231148
docs(09): UI design contract
2026-07-01 15:47:00 +02:00
schalli
5b75b3284a
wip: phase 9 cert-manager paused at planning (UI-SPEC needed)
2026-07-01 15:43:47 +02:00
schalli
a32f5f948b
docs(09): add Phase 9 Cert Manager to roadmap + capture context
...
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com >
2026-07-01 15:39:24 +02:00
schalli
e35276243a
fix(calendar): EWS uses NTLM auth + edit form stays open after save
...
- Replace ews-javascript-api (Basic Auth only) with httpntlm for EWS connections
- testEwsConnection uses GetFolder SOAP via NTLM
- fetchViaEws uses FindItem CalendarView SOAP via NTLM
- Edit form no longer auto-closes on save — shows "Erfolgreich gespeichert" instead
- Test button in edit mode uses saved credentials via /sources/:id/test endpoint
- Add saveSuccess i18n key (de/en)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com >
2026-07-01 14:05:07 +02:00
schalli
51d8c2f14e
fix(calendar): SSRF exception for Exchange + error messages + domain in edit
...
- SSRF check skipped for Exchange type (internal EWS servers are common)
- testConnectionFromConfig catches SSRF/validation errors, returns {success:false,error} instead of throwing 403
- updateSource reads existing.type to determine effective type for SSRF check
- Panel shows saveError/editSaveError on failed add/update
- Edit form initialValues now includes domain field
- i18n: calendar.saveError key added (de+en)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com >
2026-07-01 13:41:32 +02:00
schalli
b719291bdc
fix(accent-color): restore color on reload + apply sidebar vars
...
header.tsx: accentColor was missing from setUser call on mount —
applyAccentColor(undefined) fired on every reload, removing --primary.
auth-store: also set --sidebar-accent (15% opacity) and
--sidebar-accent-foreground so active sidebar items match accent.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com >
2026-07-01 13:30:33 +02:00
schalli
42daa87e5e
feat(calendar): add domain field and test-connection button to Exchange sources
...
- Prisma: domain String? added to CalendarSource model (db push applied)
- DTOs: domain in CreateCalendarSourceDto, UpdateCalendarSourceDto, new TestCalendarSourceConfigDto
- Service: domain in SOURCE_SAFE_SELECT, addSource, updateSource; new testConnectionFromConfig method
- Controller: POST /calendar/sources/test-config (before :id routes to avoid collision)
- ExchangeProvider: domain in all source interfaces; passed as 3rd arg to EWS WebCredentials
- Frontend: domain in CalendarSource/CreateSourcePayload/UpdateSourcePayload; testSourceConfig API fn
- Form: domain field (Exchange-only), "Test connection" button with idle/loading/success/error states
- i18n: de+en keys for formFieldDomain, formFieldDomainHint, formTestConnection, formTesting, formTestSuccess, formTestFailed
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com >
2026-07-01 13:15:13 +02:00
schalli
2e0e7290ba
fix(calendar): remove setState call from render in isFormValid
...
validateUrl() calls setUrlError() — calling it during render triggers
React error #301 (cannot update component while rendering). Remove it
from the isFormValid computation; onChange/onBlur already keep urlError
in sync so !urlError is sufficient.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com >
2026-07-01 13:01:03 +02:00
schalli
f6173bbe35
docs(quick-260701-abc): fix i18n missing keys — summary and state update
...
Tessera CI/CD / Lint & Type Check (push) Successful in 45s
Tessera CI/CD / Tests (push) Has been cancelled
Tessera CI/CD / Build & Publish Images (push) Has been cancelled
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com >
2026-07-01 12:06:32 +02:00