Hermes 284313f908
Some checks are pending
Bidi Control Character Guard / bidi-control-guard (push) Waiting to run
Circular Dependency Check / Check for new circular dependencies (push) Waiting to run
Citus Migration Smoke / Combined migrations on single-node Citus (push) Waiting to run
E2E Fresh Install Tests / fresh-install-e2e (push) Waiting to run
ext-v2 guardrails / Run ext-v2 guard and ESLint (push) Waiting to run
Integration Tests / Check for relevant changes (push) Waiting to run
Integration Tests / ${{ (github.event_name == 'schedule' || github.event.inputs.suite == 'full') && 'Full integration suite' || 'Tier-1 integration subset' }} (push) Blocked by required conditions
Mobile checks / Mobile lint + typecheck (push) Waiting to run
Mobile checks / Mobile unit tests (push) Waiting to run
Mobile checks / Mobile dependency audit (report) (push) Waiting to run
Mobile checks / Mobile reproducibility checks (push) Waiting to run
Secrets guard (env backups) / Ensure no tracked env backup files (push) Waiting to run
Temporal Readiness / fast-readiness (push) Waiting to run
Temporal Readiness / docker-parity (push) Waiting to run
TypeScript Type Check / Nx affected typecheck (push) Waiting to run
Unit Tests / Skipped-test budget (push) Waiting to run
Unit Tests / Nx affected unit tests (push) Waiting to run
Unit Tests / Server unit coverage (informational) (push) Waiting to run
Validate Tenant Management Schema / Check for relevant changes (push) Waiting to run
Validate Tenant Management Schema / Validate Tenant Management Schema (push) Blocked by required conditions
EE Workflows Build Guard / ee-workflows-build-guard (push) Waiting to run
Initial import of AlgaPSA codebase from PSA server
Excluded: .git, node_modules, secrets/, compose.env, assemblyscript tgz

Source: /opt/alga-psa on psa.joliet.tech
2026-06-22 16:12:17 -05:00

14 KiB

PRD — MSP i18n Batch 2b-21b/c: Projects + Project Templates Migration

  • Slug: 2026-04-05-msp-i18n-projects-migration
  • Date: 2026-04-05
  • Status: Draft
  • Parent plan: .ai/translation/MSP_i18n_plan.md (Batches 2b-21b + 2b-21c)
  • Sibling plan: ee/docs/plans/2026-04-05-msp-i18n-tickets-migration/ (2b-21a)

Summary

Wire the existing features/projects namespace into ~60 unwired MSP components in packages/projects/src/components/ (projects proper + project-templates subdirectory). Infrastructure is already in place: features/projects.json (128 keys across 9 locales) exists, templates.* subtree is live, and ROUTE_NAMESPACES['/msp/projects'] already loads it. 5 of 65 production components are wired; ~60 remain. Consolidates what the parent plan called 2b-21b (projects) and 2b-21c (project-templates) into one effort because they share the same package, namespace, and patterns.

Problem

MSP users see hardcoded English across the entire project management module — the main projects list, project detail page, task forms, kanban board, project templates, wizard steps, and task dialogs. Only 5 of 65 production components (8%) are wired. Because ROUTE_NAMESPACES['/msp/projects'] already loads features/projects, the translation assets are downloaded but unused. Client-portal project views are 100% wired (9/9), so this is the last major gap in project-related UI.

Project templates were originally considered for a separate features/project-templates namespace, but analysis confirmed that the existing features/projects.json templates.* subtree (17 keys) is already used by wired components (TemplateStatusColumnsStep, TemplateStatusManager) and should be extended rather than split.

Goals

  1. Wire useTranslation(['features/projects', 'common']) into all unwired production MSP project components (projects proper + project-templates)
  2. Extend features/projects.json with MSP-specific keys missing from the current namespace (task form, task dependencies, project detail tabs, kanban, materials, export, template editor, template wizards, dialogs)
  3. Regenerate pseudo-locales via script; validate all 9 locales pass the validator
  4. Preserve 100% test pass rate and zero user-facing regressions
  5. Measurable: MSP projects coverage 8% → 100%, project-templates coverage 12% → 100%

Non-goals

  • Creating a new features/project-templates.json namespace — templates.* lives in features/projects.json per existing pattern
  • Retranslating existing 128 keys — 7-language coverage already exists
  • Translating project/task content (names, descriptions, comments) — those are tenant data
  • Wiring test files (.test.tsx) or test helpers
  • Translating client-portal project views — already complete (9/9)
  • Extending shared features/projects for client-portal-specific needs not surfaced on MSP
  • Translating EE-only project components beyond what packages/projects exports

Users and Primary Flows

Primary user: MSP project managers, technicians, and dispatchers using non-English UI language (any of fr, es, de, nl, it, pl).

Primary flows affected:

  1. /msp/projects — list page, filters, quick-add
  2. /msp/projects/[id] — project detail, phases, tasks, kanban, materials, task forms
  3. /msp/projects/templates — template list, categories filter
  4. /msp/projects/templates/[templateId] — template editor, task builder, phase manager
  5. /msp/projects/templates/create — template creation wizard (4-5 steps)
  6. /msp/settings/project-settings — ProjectSettings, ProjectStatusSettings, TenantProjectTaskStatusSettings, TaskPrioritySettings, AddStatusDialog
  7. Quick-create dialog (global nav) — ProjectQuickAdd reused in layout/QuickCreateDialog

UX / UI Notes

  • No visual changes. Text replaced inline via t('key', 'English fallback').
  • Use multi-namespace form: useTranslation(['features/projects', 'common']) — matches existing wired components (TemplateStatusColumnsStep, TemplateStatusManager, ProjectTaskStatusSettings).
  • Common strings (Cancel, Save, Delete, Confirm) come from common namespace; scoped domain strings from features/projects.
  • Toast messages, inline validation, confirmations all translated.
  • Task form is the largest single surface (~39 strings, 2024 LOC) — split mental model by tab (details, dependencies, documents, ticket links, comments, materials).

Requirements

Functional Requirements

Sub-batch A: Projects — core detail, task form, list (15 files, ~250 strings)

High-traffic daily-use components. Ship first.

Component LOC Est. strings Key content
ProjectDetail.tsx 3,038 ~50 Project detail page tabs, phases, tasks, budget/hours, kanban controls
TaskForm.tsx 2,024 ~39 Task create/edit form, fields, validation, toast messages
PhaseTaskImportDialog.tsx 1,290 ~21 Task import dialog, CSV preview, validation errors
Projects.tsx 980 ~21 Project list, filters (status/search/deadline), empty state
TaskDocumentsSimple.tsx 856 ~21 Task documents panel, upload, attach, download
TaskTicketLinks.tsx 816 ~21 Task-ticket linking UI, create/unlink, search
TaskDependencies.tsx 668 ~21 Dependency graph, add/remove, blocking indicators
ProjectMaterialsDrawer.tsx 439 ~19 Materials list, add/edit/remove, cost labels
ProjectTaskExportDialog.tsx 283 ~18 Export format, column picker, toast messages
ProjectQuickAdd.tsx 454 ~15 Quick-add project dialog (reused in QuickCreate)
ProjectDetailsEdit.tsx 557 ~13 Project detail edit form
PrefillFromTicketDialog.tsx 419 ~10 Prefill task from ticket, field mapping
TaskListView.tsx 1,320 ~9 Task list table, columns, inline edit
TaskCard.tsx 630 ~7 Kanban task card, quick-actions menu
PhaseQuickAdd.tsx 141 ~7 Quick-add phase inline

Sub-batch B: Project Templates (15 files, ~150 strings)

Template creation, editing, wizard steps, apply flow.

Component LOC Est. strings Key content
TemplateEditor.tsx 2,315 ~28 Template editor, phases, tasks, save/publish
TemplateTaskForm.tsx 1,015 ~22 Template task create/edit form
wizard-steps/TemplateTasksStep.tsx 576 ~20 Wizard step 3 — tasks
ApplyTemplateDialog.tsx 396 ~20 Apply template to project dialog
ProjectTemplatesList.tsx 308 ~12 Template list page, columns, filters, delete confirm
CreateTemplateDialog.tsx 267 ~11 Create template from project dialog
TemplateTaskListView.tsx 953 ~8 Template task list view
wizard-steps/TemplateReviewStep.tsx 290 ~7 Wizard review step
wizard-steps/TemplatePhasesStep.tsx 399 ~6 Wizard phases step
CreateTemplateForm.tsx 140 ~6 Template create form body
TemplateDetail.tsx 308 ~4 Template detail sidebar
wizard-steps/TemplateClientPortalStep.tsx 45 ~2 Client portal exposure toggle
TemplateCreationWizard.tsx 360 ~1 Wizard shell
wizard-steps/TemplateBasicsStep.tsx 81 ~1 Wizard basics step
AddTemplateDialog.tsx 30 0 Re-export shim

Sub-batch C: Settings + small/utility components (30 files, ~80-100 strings)

Low-string-count cleanup pass.

Component LOC Est. strings Notes
settings/projects/TenantProjectTaskStatusSettings.tsx 642 ~11 Tenant-level status defaults
settings/projects/ProjectStatusSettings.tsx 442 ~10 Project status config
ProjectTaskStatusEditor.tsx 350 ~7 Inline status editor
CreateTaskFromTicketDialog.tsx 274 ~5 Create task from ticket
LinkTicketToTaskDialog.tsx 221 ~5 Link ticket to task
DeadlineFilter.tsx 165 ~5 Deadline filter dropdown
settings/ProjectSettings.tsx 86 ~5 Top-level project settings page
ProjectTaskStatusSelector.tsx 371 ~4 Status select dropdown
MoveTaskDialog.tsx 126 ~4 Move task to phase dialog
ProjectInfo.tsx 254 ~3 Project info card
DuplicateTaskDialog.tsx 216 ~3 Duplicate task dialog
TicketLinkedTasksBadge.tsx 160 ~3 Badge showing linked tasks
settings/projects/AddStatusDialog.tsx 111 ~2 Add status dialog
ProjectPhases.tsx 280 ~1 Phases section wrapper
TaskStatusSelect.tsx 156 ~1 Task status select
TicketSelect.tsx 136 ~1 Ticket select
TaskTypeSelector.tsx 54 ~1 Task type selector
Remaining zero-string files (~13) varies 0 Confirm zero strings: StatusColumn, TaskCommentThread, KanbanBoard, ClientPortalConfigEditor, ProjectPage, KanbanZoomControl, TaskCommentForm, DonutChart, TaskQuickAdd, TaskEdit, HoursProgressBar, ProjectActiveToggle, TaskPrioritySettings

Namespace key gaps to fill (preliminary):

Current features/projects.json covers project list and basic detail. Likely MSP gaps:

  • taskForm.* — full task create/edit form (fields, validation, placeholders)
  • taskDependencies.* — dependency UI, blocking indicators, cycle detection
  • taskDocuments.* — attach/upload/download controls (may overlap with features/documents)
  • taskTicketLinks.* — link/unlink task-ticket, search
  • projectDetail.* — tabs, budget/hours display, phase management
  • kanban.* — column headers, drag helpers, zoom control
  • materials.* — materials drawer, add/edit, costs
  • export.* — export dialog labels (reuse features/tickets export patterns if possible)
  • quickAdd.* — project quick-add dialog labels
  • dialogs.* — move/duplicate/create-from-ticket dialogs
  • import.* — task import CSV flow
  • templates.editor.* — template editor-specific strings
  • templates.wizard.* — wizard step titles, nav buttons, review summary
  • templates.apply.* — apply-template dialog
  • templates.list.* — template list page (columns, filters, delete)
  • templates.taskForm.* — template task form (may share with taskForm.*)
  • settings.statuses.* — already partially present; extend for tenant/project levels
  • filters.deadline.* — deadline filter dropdown options

Final gap list determined during implementation — run the lang-pack loop to surface missing keys.

Non-functional Requirements

  1. No regressions: all existing project-related tests pass after migration
  2. Lang-pack validation: after every en/features/projects.json edit, run node scripts/generate-pseudo-locales.cjs && node scripts/validate-translations.cjs and commit only when green. Single unified check covers key parity, pseudo fill patterns, Italian accent preservation, and {{variable}} preservation. Never hand-edit xx/ or yy/ pseudo-locale files.
  3. Naming convention: follow existing features/projects.json patterns (camelCase, nested under semantic groups); reuse existing keys where possible before adding new ones
  4. Fallback-safe: all t() calls use t('key', 'English fallback') signature
  5. Multi-namespace: use useTranslation(['features/projects', 'common']) array form to match existing wired components; prefer common for generic actions (save/cancel/delete)
  6. Shared with client portal: before adding a key, check if existing features/projects key covers it — client-portal uses the same namespace

Data / API / Integrations

  • No database changes
  • No API changes
  • No new npm dependencies
  • Reuses existing useTranslation from react-i18next (as used in wired components)
  • Reuses existing i18next infrastructure loaded via I18nWrapper (already in MSP layout)

Security / Permissions

No change. Translation is a pure presentation-layer concern.

Observability

N/A.

Rollout / Migration

  • No feature-flag gating needed — I18nWrapper forces English fallback when msp-i18n-enabled is off
  • Ship sub-batches A/B/C as independent PRs
  • Translations are static JSON served from server/public/locales/; no cache invalidation beyond standard Next.js static-asset rebuild
  • Each PR is independently revertable; components continue rendering English via defaultValue fallbacks even if keys are reverted

Open Questions

  1. ROUTE_NAMESPACES does not include /msp/projects/templates or /msp/projects/templates/[templateId] or /msp/projects/templates/create. The best-match fallback to /msp/projects should load features/projects transitively. Action: verify via integration test T108; if not loading, add explicit route entries.
  2. Should export dialog (ProjectTaskExportDialog) reuse features/tickets export keys or have its own features/projects.export.*? Tentative answer: own section under features/projects — avoids cross-namespace coupling, patterns may diverge.
  3. TaskDocumentsSimple — should document strings live in features/documents or features/projects.taskDocuments.*? Tentative answer: reuse features/documents where keys match (already loaded for /msp/projects via transitive namespace? — verify), add features/projects.taskDocuments.* only for project-task-specific copy.
  4. Templates wizard has 5 steps with different content — should wizard strings be flat under templates.wizard.* or nested per-step (templates.wizard.basics.*, templates.wizard.tasks.*)? Tentative answer: nested per-step, matches existing onboarding wizard patterns in msp/onboarding.json.

Acceptance Criteria (Definition of Done)

  • All ~60 unwired production MSP project + project-template components either (a) import useTranslation(['features/projects', 'common']) and wrap all user-visible strings, or (b) are confirmed zero-string (re-exports, style-only files, kanban layout components)
  • features/projects.json contains all keys referenced by MSP project components
  • node scripts/generate-pseudo-locales.cjs && node scripts/validate-translations.cjs exits 0
  • All existing project-related unit/integration tests pass
  • Visual smoke test: /msp/projects, /msp/projects/[id], /msp/projects/templates, /msp/projects/templates/[templateId], /msp/projects/templates/create, /msp/settings/project-settings render correctly in en and at least one non-English locale (de or fr); xx pseudo-locale shows pseudo-text for every visible string (no bare English leakage)
  • Global quick-create dialog (ProjectQuickAdd reused in layout/QuickCreateDialog) renders translated in non-English locale
  • Parent plan .ai/translation/MSP_i18n_plan.md updated: sub-batches 2b-21b and 2b-21c marked with final string counts