Files
tessera-ctl/.planning/phases/09-cert-manager-module/09-02-SUMMARY.md
T

7.2 KiB

phase, plan, subsystem, tags, requires, provides, affects, tech_stack, key_files, decisions, metrics, status
phase plan subsystem tags requires provides affects tech_stack key_files decisions metrics status
09-cert-manager-module 02 frontend
cert-manager
frontend
i18n
components
shell
cert-manager-page-shell
cert-manager-i18n
cert-manager-actions
apps/web
added patterns
useTranslations
vi.mock next-intl
client-component
conditional-render
created modified
apps/web/src/app/(portal)/modules/cert-manager/page.tsx
apps/web/src/app/(portal)/modules/cert-manager/actions.ts
apps/web/src/app/(portal)/modules/cert-manager/components/DropZone.tsx
apps/web/src/app/(portal)/modules/cert-manager/components/PasswordField.tsx
apps/web/src/app/(portal)/modules/cert-manager/components/InspectTab.tsx
apps/web/src/app/(portal)/modules/cert-manager/components/SplitTab.tsx
apps/web/src/app/(portal)/modules/cert-manager/components/MergeTab.tsx
apps/web/src/app/(portal)/modules/cert-manager/components/ConvertTab.tsx
apps/web/src/app/(portal)/modules/cert-manager/cert-manager.test.tsx
apps/web/src/messages/de.json
apps/web/src/messages/en.json
Used vi.mock('next-intl') test pattern per project convention instead of NextIntlClientProvider (matches VehicleTable.test.tsx, sidebar.test.tsx)
PasswordField renders null when show=false — no DOM reflow, satisfies T-09-02 threat mitigation
File/PEM mutual exclusion enforced in page state: selecting one clears the other
duration completed tasks_completed files_created files_modified
~6 minutes 2026-07-01 3 9 2
complete

Phase 09 Plan 02: Cert-Manager Frontend Shell Summary

One-liner: Cert-manager tab shell with DropZone, conditional PasswordField, shared input card, four tab stubs, downloadBase64/postForm client helpers, and full certManager i18n namespace in de + en.

Tasks Completed

Task Name Commit Files
1 Add certManager i18n namespace (de + en) 82a80e7 de.json, en.json
2 Build page shell, components, client helpers 42a41f7 page.tsx, actions.ts, 6 components
3 Shell render tests (GREEN) 2cb01f7 cert-manager.test.tsx

What Was Built

i18n Namespace (Task 1)

certManager namespace added to both de.json and en.json with identical key structure:

  • title, description
  • tabs.{inspect,split,merge,convert}
  • dropZone.{placeholder,formats}, paste.placeholder, password.label, or
  • actions.{inspect,split,merge,convert,download,processing}
  • emptyState.{inspect,inspectBody,split,splitBody,merge,mergeBody,convert,convertBody}
  • error.{generic,wrongPassword,unknownFormat}

German copy matches UI-SPEC Copywriting Contract exactly.

Page Shell (Task 2)

page.tsx — 'use client' component with:

  • State: activeTab, file, pemText, password
  • Layout: max-w-4xl mx-auto p-6 space-y-6 per UI-SPEC
  • Shared input card with DropZone + OR divider + PEM textarea + conditional PasswordField
  • Tab nav: 4 tabs with border-b-2 border-primary active indicator
  • Renders active tab component with { file, pemText, password } props
  • File/PEM mutual exclusion enforced

actions.ts — Client helpers:

  • API_URL const (NEXT_PUBLIC_API_URL || 'http://localhost:3001')
  • downloadBase64(filename, content, mimeType) — atob → Uint8Array → Blob → URL.createObjectURL
  • postForm(endpoint, form) — fetch with credentials: 'include', throws on !ok

DropZone.tsx — Drag-and-drop + click-to-browse, drag-over highlight (border-primary bg-primary/5), file display with clear button, resets e.target.value for re-selection.

PasswordField.tsx — input[type=password] with inline SVG eye toggle; renders null when show=false (T-09-02).

Tab stubs — InspectTab, SplitTab, MergeTab, ConvertTab render empty state strings only.

Tests (Task 3)

7 tests, all GREEN:

  • Page renders title 'Zertifikat-Manager' and description
  • All 4 tab labels rendered (Analysieren, Aufteilen, Zusammenfuehren, Konvertieren)
  • Password field NOT in DOM on initial render (T-09-02 assertion)
  • Inspect empty state on initial render
  • Split / Merge / Convert empty states when respective tabs activated

Deviations from Plan

Auto-applied conventions

1. [Convention] vi.mock('next-intl') instead of NextIntlClientProvider

  • Found during: Task 3
  • Issue: Plan specified NextIntlClientProvider, but every existing test in the project mocks next-intl directly (sidebar.test.tsx, VehicleTable.test.tsx)
  • Fix: Used vi.mock('next-intl', ...) pattern for consistency
  • Impact: Tests are simpler and match project convention; no behavior difference

2. [Convention] node_modules symlink for worktree test execution

  • Found during: Task 3
  • Issue: Worktree has no node_modules; vitest not available
  • Fix: Created temporary symlink apps/web/node_modules -> main repo node_modules to run tests; symlink is gitignored
  • Impact: Tests pass correctly; symlink does not affect production

Threat Model Compliance

Threat ID Status
T-09-02 (password in state/URL) Mitigated — PasswordField renders null when show=false; password never in URL or console
T-09-04 (unauthenticated fetch) Mitigated — postForm uses credentials:'include'; ModuleGuard enforced server-side
T-09-05 (client accept filter) Accepted — UX only, server validates

Known Stubs

Component Location Reason
InspectTab cert-manager/components/InspectTab.tsx Empty state only — API wire-up in later plan
SplitTab cert-manager/components/SplitTab.tsx Empty state only — API wire-up in later plan
MergeTab cert-manager/components/MergeTab.tsx Empty state only — API wire-up in later plan
ConvertTab cert-manager/components/ConvertTab.tsx Empty state only — API wire-up in later plan

These stubs are intentional. Plan 02 explicitly scopes to the shell; later plans fill in each tab's API logic. The stubs do not prevent the plan goal (visible shell + navigation) from being achieved.

Verification Results

Check Status Notes
pnpm --filter @tessera/web test cert-manager --run PASS 7/7 tests green
tsc --noEmit (cert-manager files) PASS No cert-manager type errors
I18N_OK node verify script PASS de.tabs keys correct, en.certManager.actions.download exists
grep -q "max-w-4xl" PASS Layout contract met
grep -q "credentials: 'include'" PASS T-09-04 mitigation present
grep -q "URL.createObjectURL" PASS downloadBase64 helper present

Self-Check: PASSED

  • apps/web/src/app/(portal)/modules/cert-manager/page.tsx — created
  • apps/web/src/app/(portal)/modules/cert-manager/actions.ts — created
  • apps/web/src/app/(portal)/modules/cert-manager/components/*.tsx (6 files) — created
  • apps/web/src/app/(portal)/modules/cert-manager/cert-manager.test.tsx — created
  • apps/web/src/messages/de.json — certManager namespace added
  • apps/web/src/messages/en.json — certManager namespace added
  • Commit 82a80e7 exists (i18n)
  • Commit 42a41f7 exists (shell + components)
  • Commit 2cb01f7 exists (tests)