feat: billing — usage tracking per SQS operation in PostgreSQL
- New package app/billing: Init/RecordUsage/Close with auto-migrate - Integration in actionHandler: record tenant_id, operation, msg_count, msg_bytes - Helm chart: billing section in values.yaml, secret-billing.yaml, env vars in deployment - Optional: billing disabled by default (BILLING_PG_HOST not set = no-op) - Table: sqs_usage_records with index on (tenant_id, recorded_at)
This commit is contained in:
+10
-2
@@ -1,7 +1,7 @@
|
||||
// app/admin/admin.go
|
||||
// Admin API handlers for shared-sqs management
|
||||
// Created: 2026-04-09
|
||||
// Updated: 2026-04-12 09:28 MSK — demo UI token и изоляция UI API одним tenant-ом
|
||||
// Updated: 2026-04-12 10:12 MSK — пометки о временном demo showcase режиме
|
||||
package admin
|
||||
|
||||
import (
|
||||
@@ -30,6 +30,9 @@ const (
|
||||
uiTenantContextKey uiContextKey = "ui-tenant"
|
||||
)
|
||||
|
||||
// ВАЖНО: значения ниже относятся только к временному demo/showcase режиму.
|
||||
// Перед production rollout без публичного demo-режима этот блок должен быть удалён
|
||||
// вместе с веткой authenticateUIDemoToken и связанными UI-подсказками.
|
||||
const (
|
||||
defaultUIDemoToken = "demo-ui-shared-sqs-ngcloud-2026"
|
||||
defaultUIDemoTenantID = "t-demo-shared-sqs-ngcloud"
|
||||
@@ -67,7 +70,8 @@ func NewHandler(store *tenant.TenantStore, adminToken string) *Handler {
|
||||
return &Handler{store: store, adminToken: adminToken, nubesEndpoint: nubesEndpoint}
|
||||
}
|
||||
|
||||
// uiDemoToken — возвращает публичный demo token для UI, если он не переопределён через env.
|
||||
// uiDemoToken — возвращает публичный demo token для UI.
|
||||
// Временный showcase-only путь: в production без demo user этот метод нужно удалить.
|
||||
func (h *Handler) uiDemoToken() string {
|
||||
if token := os.Getenv("SHARED_SQS_UI_DEMO_TOKEN"); token != "" {
|
||||
return token
|
||||
@@ -76,6 +80,7 @@ func (h *Handler) uiDemoToken() string {
|
||||
}
|
||||
|
||||
// uiDemoTenantID — возвращает tenant ID, к которому привязан demo token.
|
||||
// Существует только для showcase-режима, не для постоянной production auth-модели.
|
||||
func (h *Handler) uiDemoTenantID() string {
|
||||
if tenantID := os.Getenv("SHARED_SQS_UI_DEMO_TENANT_ID"); tenantID != "" {
|
||||
return tenantID
|
||||
@@ -84,6 +89,7 @@ func (h *Handler) uiDemoTenantID() string {
|
||||
}
|
||||
|
||||
// uiDemoEmail — возвращает отображаемый email для demo UI session.
|
||||
// Нужен только для публичного демо-логина и должен уйти вместе с demo path.
|
||||
func (h *Handler) uiDemoEmail() string {
|
||||
if email := os.Getenv("SHARED_SQS_UI_DEMO_EMAIL"); email != "" {
|
||||
return email
|
||||
@@ -92,6 +98,8 @@ func (h *Handler) uiDemoEmail() string {
|
||||
}
|
||||
|
||||
// authenticateUIDemoToken — маппит публичный demo token на заранее сидированный demo tenant.
|
||||
// Почему так: это быстрый showcase-вход для заказчика. Для production без demo user
|
||||
// функция должна быть удалена, чтобы в коде не осталось публичного bypass-пути.
|
||||
func (h *Handler) authenticateUIDemoToken(token string) (*tenant.Tenant, string, error) {
|
||||
demoToken := h.uiDemoToken()
|
||||
if demoToken == "" || subtle.ConstantTimeCompare([]byte(token), []byte(demoToken)) != 1 {
|
||||
|
||||
Reference in New Issue
Block a user