Files

14 KiB

phase, plan, type, wave, depends_on, files_modified, autonomous, requirements, must_haves
phase plan type wave depends_on files_modified autonomous requirements must_haves
07-multilanguage 01 execute 1
migrations/versions/009_multilanguage.py
packages/shared/shared/models/tenant.py
packages/shared/shared/models/auth.py
packages/shared/shared/prompts/system_prompt_builder.py
packages/portal/lib/system-prompt-builder.ts
packages/shared/shared/email.py
packages/shared/shared/api/templates.py
packages/shared/shared/api/portal.py
tests/unit/test_system_prompt_builder.py
tests/integration/test_language_preference.py
tests/integration/test_templates_i18n.py
true
I18N-03
I18N-04
I18N-05
I18N-06
truths artifacts key_links
AI Employees respond in the same language the user writes in
Agent templates have Spanish and Portuguese translations stored in DB
Invitation emails are sent in the inviting admin's language
portal_users table has a language column defaulting to 'en'
Templates API returns translated fields when locale param is provided
path provides contains
migrations/versions/009_multilanguage.py DB migration adding language to portal_users and translations JSONB to agent_templates portal_users
path provides contains
packages/shared/shared/prompts/system_prompt_builder.py Language instruction appended to all system prompts LANGUAGE_INSTRUCTION
path provides contains
packages/portal/lib/system-prompt-builder.ts TS mirror with language instruction LANGUAGE_INSTRUCTION
path provides contains
packages/shared/shared/email.py Localized invitation emails in en/es/pt language
path provides contains
packages/shared/shared/api/templates.py Locale-aware template list endpoint locale
path provides contains
tests/integration/test_language_preference.py Integration tests for PATCH language preference endpoint test_
path provides contains
tests/integration/test_templates_i18n.py Integration tests for locale-aware templates endpoint test_
from to via pattern
packages/shared/shared/prompts/system_prompt_builder.py AI Employee responses LANGUAGE_INSTRUCTION appended in build_system_prompt() LANGUAGE_INSTRUCTION
from to via pattern
packages/shared/shared/api/templates.py agent_templates.translations JSONB column merge on locale query param translations
Backend multilanguage foundation: DB migration, system prompt language instruction, localized invitation emails, and locale-aware templates API.

Purpose: Provides the backend data layer and AI language behavior that all frontend i18n depends on. Without this, there is no language column to persist, no template translations to display, and no agent language instruction. Output: Migration 009, updated system prompt builder (Python + TS), localized email sender, locale-aware templates API, unit tests, integration tests.

<execution_context> @/home/adelorenzo/.claude/get-shit-done/workflows/execute-plan.md @/home/adelorenzo/.claude/get-shit-done/templates/summary.md </execution_context>

@.planning/PROJECT.md @.planning/ROADMAP.md @.planning/STATE.md @.planning/phases/07-multilanguage/07-CONTEXT.md @.planning/phases/07-multilanguage/07-RESEARCH.md

From packages/shared/shared/models/auth.py:

class PortalUser(Base):
    __tablename__ = "portal_users"
    id: Mapped[uuid.UUID]
    email: Mapped[str]
    hashed_password: Mapped[str]
    name: Mapped[str]
    role: Mapped[str]
    created_at: Mapped[datetime]
    updated_at: Mapped[datetime]
    # NEEDS: language: Mapped[str] = mapped_column(String(10), nullable=False, server_default='en')

From packages/shared/shared/models/tenant.py (AgentTemplate):

class AgentTemplate(Base):
    __tablename__ = "agent_templates"
    # Existing columns: id, name, role, description, category, persona, system_prompt,
    # model_preference, tool_assignments, escalation_rules, is_active, sort_order, created_at
    # NEEDS: translations: Mapped[dict] = mapped_column(JSON, nullable=False, server_default='{}')

From packages/shared/shared/prompts/system_prompt_builder.py:

AI_TRANSPARENCY_CLAUSE = "When directly asked if you are an AI, always disclose that you are an AI assistant."
def build_system_prompt(name, role, persona="", tool_assignments=None, escalation_rules=None) -> str

From packages/portal/lib/system-prompt-builder.ts:

export interface SystemPromptInput { name: string; role: string; persona?: string; ... }
export function buildSystemPrompt(data: SystemPromptInput): string

From packages/shared/shared/email.py:

def send_invite_email(to_email: str, invitee_name: str, tenant_name: str, invite_url: str) -> None
# NEEDS: language: str = "en" parameter added

From packages/shared/shared/api/templates.py:

class TemplateResponse(BaseModel):
    id: str; name: str; role: str; description: str; category: str; persona: str; ...
    @classmethod
    def from_orm(cls, tmpl: AgentTemplate) -> "TemplateResponse"

@templates_router.get("/templates", response_model=list[TemplateResponse])
async def list_templates(caller, session) -> list[TemplateResponse]
# NEEDS: locale: str = Query("en") parameter, merge translations before returning

From migrations/versions/ — latest is 008_web_chat.py, so next is 009.

Task 1: DB migration 009 + ORM updates + system prompt language instruction migrations/versions/009_multilanguage.py packages/shared/shared/models/auth.py packages/shared/shared/models/tenant.py packages/shared/shared/prompts/system_prompt_builder.py packages/portal/lib/system-prompt-builder.ts tests/unit/test_system_prompt_builder.py - Test: build_system_prompt("Mara", "Support Rep") output contains LANGUAGE_INSTRUCTION string - Test: build_system_prompt with full args (persona, tools, escalation) contains LANGUAGE_INSTRUCTION - Test: build_system_prompt with minimal args (name, role only) contains LANGUAGE_INSTRUCTION - Test: LANGUAGE_INSTRUCTION appears after identity section and before AI_TRANSPARENCY_CLAUSE 1. Create migration 009_multilanguage.py: - Add `language` column (String(10), NOT NULL, server_default='en') to portal_users - Add `translations` column (JSON, NOT NULL, server_default='{}') to agent_templates - Backfill translations for all 7 existing seed templates with Spanish (es) and Portuguese (pt) translations for name, description, and persona fields. Use proper native business terminology — not literal machine translations. Each template gets a translations JSON object like: {"es": {"name": "...", "description": "...", "persona": "..."}, "pt": {"name": "...", "description": "...", "persona": "..."}} - downgrade: drop both columns
2. Update ORM models:
   - PortalUser: add `language: Mapped[str] = mapped_column(String(10), nullable=False, server_default='en')`
   - AgentTemplate: add `translations: Mapped[dict] = mapped_column(JSON, nullable=False, server_default='{}')`

3. Add LANGUAGE_INSTRUCTION to system_prompt_builder.py:
   ```python
   LANGUAGE_INSTRUCTION = (
       "Detect the language of each user message and respond in that same language. "
       "You support English, Spanish, and Portuguese."
   )
   ```
   Append to sections list BEFORE AI_TRANSPARENCY_CLAUSE (transparency clause remains last).

4. Add LANGUAGE_INSTRUCTION to system-prompt-builder.ts (TS mirror):
   ```typescript
   const LANGUAGE_INSTRUCTION = "Detect the language of each user message and respond in that same language. You support English, Spanish, and Portuguese.";
   ```
   Append before the AI transparency clause line.

5. Extend tests/unit/test_system_prompt_builder.py with TestLanguageInstruction class:
   - test_language_instruction_present_in_default_prompt
   - test_language_instruction_present_with_full_args
   - test_language_instruction_before_transparency_clause
cd /home/adelorenzo/repos/konstruct && python -m pytest tests/unit/test_system_prompt_builder.py -x -v - Migration 009 creates language column on portal_users and translations JSONB on agent_templates with es+pt seed data - LANGUAGE_INSTRUCTION appears in all system prompts (Python and TS) - All existing + new system prompt tests pass Task 2: Localized invitation emails + locale-aware templates API + language preference endpoint + integration tests packages/shared/shared/email.py packages/shared/shared/api/templates.py packages/shared/shared/api/portal.py tests/integration/test_language_preference.py tests/integration/test_templates_i18n.py 1. Update send_invite_email() in email.py: - Add `language: str = "en"` parameter - Create localized subject lines dict: {"en": "You've been invited...", "es": "Has sido invitado...", "pt": "Voce foi convidado..."} - Create localized text_body and html_body templates for all 3 languages - Select the correct template based on language param, fallback to "en" - Update the invitations API endpoint that calls send_invite_email to pass the inviter's language (read from portal_users.language or default "en")
2. Update templates API (templates.py):
   - Add `locale: str = Query("en")` parameter to list_templates() and get_template()
   - In TemplateResponse.from_orm(), add a `locale` parameter
   - When locale != "en" and tmpl.translations has the locale key, merge translated name/description/persona over the English defaults before returning
   - Keep English as the base — translations overlay, never replace the stored English values in DB

3. Add language preference PATCH endpoint in portal.py:
   - PATCH /api/portal/users/me/language — accepts {"language": "es"} body
   - Validates language is in ["en", "es", "pt"]
   - Updates portal_users.language for the current user
   - Returns {"language": "es"} on success
   - Guard: any authenticated user (get_portal_caller)

4. Update the verify auth endpoint (/api/portal/auth/verify) to include `language` in its response so Auth.js JWT can carry it.

5. Create tests/integration/test_language_preference.py (Wave 0 — I18N-02):
   - Use the existing integration test pattern (httpx AsyncClient against the FastAPI app)
   - test_patch_language_valid: PATCH /api/portal/users/me/language with {"language": "es"} returns 200 and {"language": "es"}
   - test_patch_language_invalid: PATCH with {"language": "fr"} returns 422 or 400
   - test_patch_language_persists: PATCH to "pt", then GET /api/portal/auth/verify includes language="pt"
   - test_patch_language_unauthenticated: PATCH without auth returns 401

6. Create tests/integration/test_templates_i18n.py (Wave 0 — I18N-04):
   - Use the existing integration test pattern (httpx AsyncClient against the FastAPI app)
   - test_list_templates_default_locale: GET /api/portal/templates returns English fields (no locale param)
   - test_list_templates_spanish: GET /api/portal/templates?locale=es returns Spanish-translated name/description/persona
   - test_list_templates_portuguese: GET /api/portal/templates?locale=pt returns Portuguese-translated fields
   - test_list_templates_unsupported_locale: GET /api/portal/templates?locale=fr falls back to English
   - test_template_translations_overlay: Verify translated fields overlay English, not replace — English base fields still accessible in DB
cd /home/adelorenzo/repos/konstruct && python -m pytest tests/unit -x -q && python -m pytest tests/integration/test_language_preference.py tests/integration/test_templates_i18n.py -x -v - send_invite_email() accepts language param and sends localized emails in en/es/pt - GET /api/portal/templates?locale=es returns Spanish-translated template fields - PATCH /api/portal/users/me/language persists language preference - /api/portal/auth/verify response includes user's language field - Integration tests for language preference endpoint pass (4 tests) - Integration tests for locale-aware templates endpoint pass (5 tests) - All existing unit tests pass: `pytest tests/unit -x -q` - Integration tests pass: `pytest tests/integration/test_language_preference.py tests/integration/test_templates_i18n.py -x -v` - Migration 009 is syntactically valid (imports, upgrade/downgrade functions present) - system_prompt_builder.py contains LANGUAGE_INSTRUCTION - system-prompt-builder.ts contains LANGUAGE_INSTRUCTION - email.py send_invite_email has language parameter - templates.py list_templates has locale parameter

<success_criteria>

  • Migration 009 adds language to portal_users and translations JSONB to agent_templates
  • All 7 seed templates have es+pt translations backfilled
  • AI Employees will respond in the user's language via system prompt instruction
  • Templates API merges translations by locale
  • Language preference PATCH endpoint works
  • All unit tests pass
  • All integration tests pass (language preference + templates i18n) </success_criteria>
After completion, create `.planning/phases/07-multilanguage/07-01-SUMMARY.md`