Skip to content

Commit 86ed488

Browse files
committed
Remove platform key support and fix API key hierarchy documentation
1 parent 549e5fa commit 86ed488

14 files changed

Lines changed: 65 additions & 124 deletions

File tree

cloud/src/LrmCloud.Api/Services/Translation/ApiKeyHierarchyService.cs

Lines changed: 2 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,12 @@
77
namespace LrmCloud.Api.Services.Translation;
88

99
/// <summary>
10-
/// Resolves API keys and configurations using the hierarchy: Project → User → Organization → Platform.
10+
/// Resolves API keys and configurations using the hierarchy: Project → User → Organization.
1111
/// </summary>
1212
public class ApiKeyHierarchyService : IApiKeyHierarchyService
1313
{
1414
private readonly AppDbContext _db;
1515
private readonly IApiKeyEncryptionService _encryption;
16-
private readonly IConfiguration _configuration;
1716
private static readonly JsonSerializerOptions JsonOptions = new()
1817
{
1918
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
@@ -22,12 +21,10 @@ public class ApiKeyHierarchyService : IApiKeyHierarchyService
2221

2322
public ApiKeyHierarchyService(
2423
AppDbContext db,
25-
IApiKeyEncryptionService encryption,
26-
IConfiguration configuration)
24+
IApiKeyEncryptionService encryption)
2725
{
2826
_db = db;
2927
_encryption = encryption;
30-
_configuration = configuration;
3128
}
3229

3330
public async Task<(string? ApiKey, string? Source)> ResolveApiKeyAsync(
@@ -74,13 +71,6 @@ public ApiKeyHierarchyService(
7471
}
7572
}
7673

77-
// 4. Check platform-level key (from configuration)
78-
var platformKey = GetPlatformApiKey(provider);
79-
if (!string.IsNullOrEmpty(platformKey))
80-
{
81-
return (platformKey, "platform");
82-
}
83-
8474
return (null, null);
8575
}
8676

@@ -96,18 +86,8 @@ public async Task<ResolvedProviderConfigDto> ResolveProviderConfigAsync(
9686
Provider = provider
9787
};
9888

99-
// Start with platform config
10089
var mergedConfig = new Dictionary<string, object?>();
10190
var configSources = new Dictionary<string, string>();
102-
var platformConfig = GetPlatformConfig(provider);
103-
if (platformConfig != null)
104-
{
105-
foreach (var kvp in platformConfig)
106-
{
107-
mergedConfig[kvp.Key] = kvp.Value;
108-
configSources[kvp.Key] = "platform";
109-
}
110-
}
11191

11292
// Merge organization config
11393
if (organizationId.HasValue)
@@ -205,17 +185,6 @@ public async Task<ResolvedProviderConfigDto> ResolveProviderConfigAsync(
205185
}
206186
}
207187

208-
// Check platform API key if no other source found
209-
if (result.ApiKeySource == null)
210-
{
211-
var platformKey = GetPlatformApiKey(provider);
212-
if (!string.IsNullOrEmpty(platformKey))
213-
{
214-
result.ApiKeySource = "platform";
215-
result.MaskedApiKey = _encryption.Mask(platformKey);
216-
}
217-
}
218-
219188
// Determine if provider is configured
220189
var requiresApiKey = ProviderConfigHelper.RequiresApiKey(provider);
221190
result.IsConfigured = !requiresApiKey || result.ApiKeySource != null;
@@ -510,40 +479,6 @@ private ProviderConfigDto MapToDto(string provider, string level, string? encryp
510479
};
511480
}
512481

513-
private string? GetPlatformApiKey(string provider)
514-
{
515-
// Check configuration for platform-level keys
516-
var configKey = $"TranslationProviders:{provider}:ApiKey";
517-
var apiKey = _configuration[configKey];
518-
519-
if (string.IsNullOrEmpty(apiKey))
520-
{
521-
// Also check environment variables with standard naming
522-
var envVarName = $"LRM_{provider.ToUpperInvariant()}_API_KEY";
523-
apiKey = Environment.GetEnvironmentVariable(envVarName);
524-
}
525-
526-
return apiKey;
527-
}
528-
529-
private Dictionary<string, object?>? GetPlatformConfig(string provider)
530-
{
531-
// Check configuration for platform-level provider config
532-
var section = _configuration.GetSection($"TranslationProviders:{provider}");
533-
if (!section.Exists()) return null;
534-
535-
var config = new Dictionary<string, object?>();
536-
foreach (var child in section.GetChildren())
537-
{
538-
if (child.Key != "ApiKey") // Don't include API key in config
539-
{
540-
config[child.Key] = child.Value;
541-
}
542-
}
543-
544-
return config.Count > 0 ? config : null;
545-
}
546-
547482
private static string GetProviderDisplayName(string provider)
548483
{
549484
return provider.ToLowerInvariant() switch

cloud/src/LrmCloud.Api/Services/Translation/CloudTranslationService.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ public async Task<List<TranslationProviderDto>> GetAvailableProvidersAsync(
6060
Description = available
6161
? $"LRM managed translation ({remaining:N0} chars remaining)"
6262
: reason ?? "LRM translation unavailable",
63-
ApiKeySource = "platform"
63+
ApiKeySource = "lrm" // LRM managed provider, not user BYOK
6464
});
6565
}
6666

@@ -332,7 +332,7 @@ await LogUsageEventAsync(
332332
response.CharactersTranslated,
333333
providerName,
334334
isLrmProvider,
335-
isLrmProvider ? "platform" : keySource);
335+
isLrmProvider ? "lrm" : keySource);
336336

337337
// Track per-provider usage for analytics (against acting user for audit trail)
338338
await TrackProviderUsageAsync(userId, request.Provider ?? "auto", response.CharactersTranslated, response.TranslatedCount);

cloud/src/LrmCloud.Api/Services/Translation/ICloudTranslationService.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ namespace LrmCloud.Api.Services.Translation;
55
/// <summary>
66
/// Service for cloud-based translation operations.
77
/// Wraps LocalizationManager.Core translation providers with cloud-specific features:
8-
/// - API key hierarchy (project → user → organization → platform)
8+
/// - API key hierarchy (project → user → organization)
99
/// - Usage tracking and limits
1010
/// - Caching
1111
/// </summary>

cloud/src/LrmCloud.Api/Services/Translation/LrmTranslationProvider.cs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -202,9 +202,10 @@ public async Task<LrmTranslationResult> TranslateAsync(
202202
result.FromCache = response.FromCache;
203203

204204
// Note: Usage tracking is handled by CloudTranslationService, not here
205-
_logger.LogDebug(
206-
"LRM translation via {Backend}: {Chars} chars (billable to user {BillableUserId})",
207-
backend, sourceText.Length, billableUserId);
205+
_logger.LogInformation(
206+
"LRM translation via {Backend}: {SourceLang} → {TargetLang}, {Chars} chars{FromCache}",
207+
backend, sourceLanguage, targetLanguage, sourceText.Length,
208+
response.FromCache ? " (cached)" : "");
208209

209210
return result; // Success - return immediately
210211
}
@@ -314,9 +315,8 @@ private List<string> GetBackendsForFailover()
314315
}
315316
};
316317

317-
// Add any platform-level API keys here if we have them
318-
// For now, we rely on free providers or self-hosted ones
319-
ApplyPlatformConfig(config, backend);
318+
// Apply backend-specific configuration from config.json
319+
ApplyBackendConfig(config, backend);
320320

321321
return TranslationProviderFactory.Create(backend, config);
322322
}
@@ -327,7 +327,7 @@ private List<string> GetBackendsForFailover()
327327
}
328328
}
329329

330-
private void ApplyPlatformConfig(ConfigurationModel config, string backend)
330+
private void ApplyBackendConfig(ConfigurationModel config, string backend)
331331
{
332332
config.Translation ??= new TranslationConfiguration();
333333
config.Translation.ApiKeys ??= new TranslationApiKeys();

cloud/src/LrmCloud.Shared/DTOs/Translation/ProviderConfigDtos.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ public class ProviderConfigBase
1010
{
1111
/// <summary>
1212
/// Optional rate limit (requests per minute).
13-
/// When null, the platform default is used.
13+
/// When null, the provider default is used.
1414
/// </summary>
1515
public int? RateLimitPerMinute { get; set; }
1616
}
@@ -176,7 +176,7 @@ public class ProviderConfigDto
176176
public string Provider { get; set; } = string.Empty;
177177

178178
/// <summary>
179-
/// Configuration level: "platform", "organization", "user", "project".
179+
/// Configuration level: "organization", "user", "project".
180180
/// </summary>
181181
public string Level { get; set; } = string.Empty;
182182

@@ -239,7 +239,7 @@ public class ResolvedProviderConfigDto
239239
public bool IsConfigured { get; set; }
240240

241241
/// <summary>
242-
/// Where the API key comes from: "platform", "organization", "user", "project".
242+
/// Where the API key comes from: "organization", "user", "project", or "lrm" for the managed provider.
243243
/// Null if no API key is configured.
244244
/// </summary>
245245
public string? ApiKeySource { get; set; }

cloud/src/LrmCloud.Shared/DTOs/Translation/TranslationProviderDto.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ public class TranslationProviderDto
4646
public string? Description { get; set; }
4747

4848
/// <summary>
49-
/// Source of the API key (if configured): "project", "user", "organization", "platform".
49+
/// Source of the API key (if configured): "project", "user", "organization", or "lrm" for the managed provider.
5050
/// </summary>
5151
public string? ApiKeySource { get; set; }
5252
}

cloud/src/LrmCloud.Shared/Entities/UsageEvent.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ public class UsageEvent
7171
public bool IsLrmProvider { get; set; }
7272

7373
/// <summary>
74-
/// Source of the API key: "user", "organization", "project", "platform".
74+
/// Source of the API key: "user", "organization", "project", or "lrm" for the managed provider.
7575
/// </summary>
7676
[Required]
7777
[MaxLength(20)]

cloud/src/LrmCloud.Web/Components/EditProjectDialog.razor

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -368,7 +368,7 @@
368368
Remove the <strong>@_selectedProvider?.DisplayName</strong> API key override for this project?
369369
</MudText>
370370
<MudText Color="Color.Secondary" Class="mt-2">
371-
The project will fall back to organization, user, or platform-level keys.
371+
The project will fall back to organization or user-level keys.
372372
</MudText>
373373
</DialogContent>
374374
<DialogActions>
@@ -706,7 +706,7 @@
706706
"project" => "Project key",
707707
"organization" => "Organization key",
708708
"user" => "User key",
709-
"platform" => "Platform key",
709+
"lrm" => "LRM managed",
710710
_ => "Unknown"
711711
};
712712
}

cloud/src/LrmCloud.Web/Pages/Organizations/ApiKeys.razor

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,12 +41,12 @@
4141
<MudPaper Class="pa-4 mb-4">
4242
<MudText Typo="Typo.h6" Class="mb-2">Key Hierarchy</MudText>
4343
<MudText Typo="Typo.body2" Color="Color.Secondary" Class="mb-4">
44-
API keys are resolved in order: ProjectUserOrganizationPlatform.
45-
Organization keys are shared across all projects in this organization.
44+
For organization projects, API keys are resolved in order: ProjectOrganization.
45+
User's personal API keys are not used for organization projects to ensure consistent billing.
4646
</MudText>
4747

4848
<MudAlert Severity="Severity.Info" Dense="true" Class="mb-0">
49-
Keys configured here will be used by all projects in this organization unless overridden at the project or user level.
49+
Keys configured here will be used by all projects in this organization unless overridden at the project level.
5050
</MudAlert>
5151
</MudPaper>
5252

@@ -234,7 +234,7 @@
234234
Are you sure you want to remove the <strong>@_selectedProvider?.DisplayName</strong> API key?
235235
</MudText>
236236
<MudText Color="Color.Secondary" Class="mt-2">
237-
Projects in this organization will fall back to user or platform-level keys.
237+
Projects in this organization will fall back to project-level overrides if configured.
238238
</MudText>
239239
</DialogContent>
240240
<DialogActions>

cloud/src/LrmCloud.Web/Pages/Projects/Settings.razor

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -440,7 +440,7 @@ else
440440
Remove the <strong>@_selectedProvider?.DisplayName</strong> API key override for this project?
441441
</MudText>
442442
<MudText Color="Color.Secondary" Class="mt-2">
443-
The project will fall back to organization, user, or platform-level keys.
443+
The project will fall back to organization or user-level keys.
444444
</MudText>
445445
</DialogContent>
446446
<DialogActions>
@@ -806,7 +806,7 @@ else
806806
"project" => "Project key",
807807
"organization" => "Organization key",
808808
"user" => "User key",
809-
"platform" => "Platform key",
809+
"lrm" => "LRM managed",
810810
_ => "Unknown"
811811
};
812812
}

0 commit comments

Comments
 (0)