Buyer-visible gap
Protected develop@042b0c70531b229af3acbd0421a2f23098d848b3 has no canonical UI localization/catalog boundary. A default-branch code search finds no product-owned i18n / translation resource implementation, while current UI surfaces continue to embed Korean display strings directly. Draft #1729 makes the gap concrete by adding OIDC pending labels (로그인 중, 로그아웃 중) but correctly refuses to invent a browser-wide catalog or copy mutable translation source from another service.
Naruon needs one product-owned localization bounded context for KO/EN/JA/ZH/VI/ES/DE/FR. This is UI copy authority only. Ontology/concept labels remain a separate semantic-data/ontology registry and must not be merged into the UI translation store.
Domain boundary
Create an explicit UI Localization Catalog bounded context with a small application-facing port. Keep product screen/message semantics in Naruon; do not leak a generic translation framework into every component.
Suggested Ubiquitous Language:
screen_key: stable product surface identifier such as settings.identity;
message_key: stable semantic UI message within one screen;
locale_code: one of the supported BCP 47 language tags for this release;
translation_revision: immutable revision of one translated message;
resource_version: deployable/catalog version binding a coherent set of revisions;
translation_receipt: server response identity containing screen, locale and resource version.
UI translation and ontology/concept label authority are separate bounded contexts. No ontology label is copied into this catalog merely because it is rendered in a screen; the UI may reference ontology labels through their released owner contract where that is actually the semantic source of truth.
Persistence contract
Use a normalized PostgreSQL model, descriptive two-or-more-word snake_case names, and no JSON mega-catalog row. A viable 3NF shape is:
ui_message_definition(message_definition_id, screen_key, message_key, source_message, semantic_context, placeholder_schema, created_at, retired_at);
ui_translation_revision(translation_revision_id, message_definition_id, locale_code, translated_message, revision_number, review_status, created_at, supersedes_revision_id);
ui_resource_version(resource_version_id, version_code, published_at, source_commit_sha, status);
ui_resource_binding(resource_version_id, translation_revision_id).
Exact schema may change through ADR, but preserve these invariants:
(screen_key, message_key) is stable product identity; display text is not identity.
- Published resource versions are immutable. Corrections create a new revision/version rather than rewriting historical buyer evidence.
- Every published version is complete for KO/EN/JA/ZH/VI/ES/DE/FR for every active message included in that version. Missing per-key translations fail publication; they do not silently fall back at render time.
- Placeholder names/types are versioned and validated so a translation cannot drop, add or reinterpret interpolation parameters.
- User/customer values interpolated into a translation are never persisted back into the catalog, logs or metrics.
- No cross-service SQL, source copy, mutable Git-head dependency, or browser-loaded whole catalog.
API and cache boundary
Expose one bounded screen-scoped read contract, for example:
GET /api/ui-translation-resources/{screen_key}?locale={locale_code}
Response should carry at least screen_key, locale_code, resource_version, an immutable keyed message map for that screen only, and an ETag/version identity. The browser caches by (screen_key, locale_code, resource_version) and performs conditional refresh; it must not fetch the complete product catalog at login or hydrate a heavy client-side i18n runtime.
Locale selection order should be explicit and testable: persisted user preference when authorized → session/request preference → standards-compliant Accept-Language negotiation → product default locale. Once a locale is selected, missing active keys are errors, not silent per-message fallback. Unsupported locale input is normalized/rejected at the boundary; it never becomes a dynamic SQL identifier or filesystem path.
Write/publish authority is an operator/content-governance path, not a normal browser API. Runtime application code is read-only against published versions.
DDD / transaction / operability rules
- Publishing one
resource_version is the aggregate transaction boundary; do not hold a transaction open across translation generation, LLM calls, external review, or network work.
- Translation drafting/review happens before the short publication transaction.
- Use UPSERT/idempotency only for draft ingestion keyed by explicit revision identity; published rows are immutable.
- Read path must be async and indexed by screen/locale/version. Measure realistic buyer-page p95 and keep the screen-resource fetch path at ≤20 ms where the deployment environment makes that target applicable; profile query/I/O/cache rather than hiding misses with unrealistic warm-up.
- Define cache invalidation through version/ETag identity, not time-only browser expiry.
- Backups/recovery must preserve immutable published versions and provenance.
- CSAP/SOC 2 evidence should show who published which version, source/reviewer provenance, and rollback to a prior published version without editing it.
#1729 integration slice
Do not broaden #1729 into the catalog implementation. #1729 remains the bounded OIDC interaction-state owner and stays Draft until its own hosted/browser/a11y evidence is valid.
After this catalog reaches protected ancestry, ordinary/non-force adapt the Settings surface so at minimum these existing/new keys are served from the released resource rather than hard-coded Korean text:
- OIDC login / login pending;
- OIDC logout / logout pending;
- provider/action errors that are product copy rather than raw provider text;
- associated accessible labels/status text.
No #1729 workflow/review receipt transfers to the catalog owner, and catalog evidence does not substitute for rendered OIDC interaction evidence.
UI acceptance
For every supported locale KO/EN/JA/ZH/VI/ES/DE/FR, verify the exact current resource and UI composition in Storybook and real browser E2E:
- normal, loading, empty, error and permission states where the screen supports them;
- keyboard traversal, visible focus, screen-reader status/label semantics, touch target behavior;
- CJK line breaking and font fallback for KO/JA/ZH;
- Vietnamese diacritics and Latin-script fallback;
- German/French/Spanish text expansion without clipping or control overlap;
- responsive widths including mobile and intermediate breakpoints;
- no hydration warning or flash that replaces one locale with another after first paint;
- screenshots tied to exact resource version and source head.
Material UI acceptance must pass the product Delivery Gate; a DB/API implementation without rendered locale evidence is not complete.
Security / correctness RED cases
Add test-first coverage for at least:
- missing translation in one of the eight required locales blocks publication;
- placeholder schema mismatch blocks publication;
- stale/superseded revision cannot mutate a published resource;
- screen-scoped endpoint cannot enumerate or download unrelated screens/catalogs;
- unsupported/hostile locale and screen identifiers fail closed;
- ETag/version cache cannot serve a different locale or screen key;
- permission separation prevents browser/runtime credentials from publishing catalog versions;
- translated strings are rendered as text, not trusted HTML/script;
- user-provided interpolation values do not appear in catalog persistence, logs or metrics;
- rollback selects a prior immutable resource version without rewriting history.
Standards / traceability
Record exact code/API/test mappings in ADR + doctoring and cite primary standards in APA 7th style, including at least:
If machine translation or LLM-assisted drafting is introduced later, it is an offline content-production capability through the released contextual-orchestrator contract only; publication still requires deterministic placeholder/completeness validation and recorded review. Runtime page rendering must not depend on an LLM.
Completion
Close only after one canonical Naruon owner implements the catalog/API/cache/publish contract, docs/product-technical-gap-baseline.md and architecture/ADR/ERD/UML/operability/recovery docs are code-current, exact-head backend/frontend/security/coverage evidence is GREEN, all eight locale Storybook/browser/a11y cases pass, and #1729 or its verified successor consumes the released screen resource without source-copying the catalog.
Refs #1729 #1602. Keep this issue as the single product Gap until an implementation owner PR is created; do not create parallel UI-i18n writers.
Buyer-visible gap
Protected
develop@042b0c70531b229af3acbd0421a2f23098d848b3has no canonical UI localization/catalog boundary. A default-branch code search finds no product-ownedi18n/ translation resource implementation, while current UI surfaces continue to embed Korean display strings directly. Draft #1729 makes the gap concrete by adding OIDC pending labels (로그인 중,로그아웃 중) but correctly refuses to invent a browser-wide catalog or copy mutable translation source from another service.Naruon needs one product-owned localization bounded context for KO/EN/JA/ZH/VI/ES/DE/FR. This is UI copy authority only. Ontology/concept labels remain a separate semantic-data/ontology registry and must not be merged into the UI translation store.
Domain boundary
Create an explicit UI Localization Catalog bounded context with a small application-facing port. Keep product screen/message semantics in Naruon; do not leak a generic translation framework into every component.
Suggested Ubiquitous Language:
screen_key: stable product surface identifier such assettings.identity;message_key: stable semantic UI message within one screen;locale_code: one of the supported BCP 47 language tags for this release;translation_revision: immutable revision of one translated message;resource_version: deployable/catalog version binding a coherent set of revisions;translation_receipt: server response identity containing screen, locale and resource version.UI translation and ontology/concept label authority are separate bounded contexts. No ontology label is copied into this catalog merely because it is rendered in a screen; the UI may reference ontology labels through their released owner contract where that is actually the semantic source of truth.
Persistence contract
Use a normalized PostgreSQL model, descriptive two-or-more-word
snake_casenames, and no JSON mega-catalog row. A viable 3NF shape is:ui_message_definition(message_definition_id, screen_key, message_key, source_message, semantic_context, placeholder_schema, created_at, retired_at);ui_translation_revision(translation_revision_id, message_definition_id, locale_code, translated_message, revision_number, review_status, created_at, supersedes_revision_id);ui_resource_version(resource_version_id, version_code, published_at, source_commit_sha, status);ui_resource_binding(resource_version_id, translation_revision_id).Exact schema may change through ADR, but preserve these invariants:
(screen_key, message_key)is stable product identity; display text is not identity.API and cache boundary
Expose one bounded screen-scoped read contract, for example:
GET /api/ui-translation-resources/{screen_key}?locale={locale_code}Response should carry at least
screen_key,locale_code,resource_version, an immutable keyed message map for that screen only, and an ETag/version identity. The browser caches by(screen_key, locale_code, resource_version)and performs conditional refresh; it must not fetch the complete product catalog at login or hydrate a heavy client-side i18n runtime.Locale selection order should be explicit and testable: persisted user preference when authorized → session/request preference → standards-compliant
Accept-Languagenegotiation → product default locale. Once a locale is selected, missing active keys are errors, not silent per-message fallback. Unsupported locale input is normalized/rejected at the boundary; it never becomes a dynamic SQL identifier or filesystem path.Write/publish authority is an operator/content-governance path, not a normal browser API. Runtime application code is read-only against published versions.
DDD / transaction / operability rules
resource_versionis the aggregate transaction boundary; do not hold a transaction open across translation generation, LLM calls, external review, or network work.#1729 integration slice
Do not broaden #1729 into the catalog implementation. #1729 remains the bounded OIDC interaction-state owner and stays Draft until its own hosted/browser/a11y evidence is valid.
After this catalog reaches protected ancestry, ordinary/non-force adapt the Settings surface so at minimum these existing/new keys are served from the released resource rather than hard-coded Korean text:
No #1729 workflow/review receipt transfers to the catalog owner, and catalog evidence does not substitute for rendered OIDC interaction evidence.
UI acceptance
For every supported locale KO/EN/JA/ZH/VI/ES/DE/FR, verify the exact current resource and UI composition in Storybook and real browser E2E:
Material UI acceptance must pass the product Delivery Gate; a DB/API implementation without rendered locale evidence is not complete.
Security / correctness RED cases
Add test-first coverage for at least:
Standards / traceability
Record exact code/API/test mappings in ADR + doctoring and cite primary standards in APA 7th style, including at least:
Accept-Language. RFC Editor. https://doi.org/10.17487/RFC9110If machine translation or LLM-assisted drafting is introduced later, it is an offline content-production capability through the released
contextual-orchestratorcontract only; publication still requires deterministic placeholder/completeness validation and recorded review. Runtime page rendering must not depend on an LLM.Completion
Close only after one canonical Naruon owner implements the catalog/API/cache/publish contract,
docs/product-technical-gap-baseline.mdand architecture/ADR/ERD/UML/operability/recovery docs are code-current, exact-head backend/frontend/security/coverage evidence is GREEN, all eight locale Storybook/browser/a11y cases pass, and #1729 or its verified successor consumes the released screen resource without source-copying the catalog.Refs #1729 #1602. Keep this issue as the single product Gap until an implementation owner PR is created; do not create parallel UI-i18n writers.