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 |
|
|
|
|
|
|
|
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,descriptiontabs.{inspect,split,merge,convert}dropZone.{placeholder,formats},paste.placeholder,password.label,oractions.{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-6per UI-SPEC - Shared input card with DropZone + OR divider + PEM textarea + conditional PasswordField
- Tab nav: 4 tabs with
border-b-2 border-primaryactive indicator - Renders active tab component with
{ file, pemText, password }props - File/PEM mutual exclusion enforced
actions.ts — Client helpers:
API_URLconst (NEXT_PUBLIC_API_URL || 'http://localhost:3001')downloadBase64(filename, content, mimeType)— atob → Uint8Array → Blob → URL.createObjectURLpostForm(endpoint, form)— fetch withcredentials: '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_modulesto 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
82a80e7exists (i18n) - Commit
42a41f7exists (shell + components) - Commit
2cb01f7exists (tests)