Problem
The only TODO in the codebase is in src/frontend/src/routes/(public)/oauth/callback/+page.svelte (line 17):
```
// TODO: Remove this map once the backend returns error codes instead of
// English strings, and use those codes as i18n keys directly.
```
Currently, Result.Failure() produces a human-readable `detail` string in `ProblemDetails` responses. The frontend's OAuth callback has a hardcoded `ERROR_MAP` that maps English error message strings to i18n keys. If any backend error string changes, the frontend silently falls back to a generic message.
Proposed Solution
Add a machine-readable `code` extension field to `ProblemDetails` responses alongside the human-readable `detail`:
```json
{
"type": "https://tools.ietf.org/html/rfc9110#section-15.5.10",
"title": "Conflict",
"status": 409,
"detail": "This external account is already linked to another user.",
"code": "oauth_already_linked"
}
```
The frontend can then use `code` as an i18n key directly, eliminating the brittle string-matching `ERROR_MAP`.
Scope
This is a cross-cutting change:
- Extend `Result`/`Result` with an optional error code field
- Include `code` in all `ProblemDetails` responses
- Update the OAuth callback frontend to use codes instead of string matching
- Gradually migrate other frontend error handling to use codes
Breaking Changes
This is additive (new field), not breaking. Existing consumers that don't read `code` are unaffected.
Problem
The only TODO in the codebase is in
src/frontend/src/routes/(public)/oauth/callback/+page.svelte(line 17):```
// TODO: Remove this map once the backend returns error codes instead of
// English strings, and use those codes as i18n keys directly.
```
Currently,
Result.Failure()produces a human-readable `detail` string in `ProblemDetails` responses. The frontend's OAuth callback has a hardcoded `ERROR_MAP` that maps English error message strings to i18n keys. If any backend error string changes, the frontend silently falls back to a generic message.Proposed Solution
Add a machine-readable `code` extension field to `ProblemDetails` responses alongside the human-readable `detail`:
```json
{
"type": "https://tools.ietf.org/html/rfc9110#section-15.5.10",
"title": "Conflict",
"status": 409,
"detail": "This external account is already linked to another user.",
"code": "oauth_already_linked"
}
```
The frontend can then use `code` as an i18n key directly, eliminating the brittle string-matching `ERROR_MAP`.
Scope
This is a cross-cutting change:
Breaking Changes
This is additive (new field), not breaking. Existing consumers that don't read `code` are unaffected.