feat(PROJ-29): Tenant-Quotas & Usage-Limits vollständig implementiert
- storage/quota.go: SQL-Bug gefixt (emails.size → size_bytes, email_refs JOIN)
- tenantstore/quota.go: GetUsage nutzt jetzt email_refs JOIN für korrekte Tenant-Isolation
- smtpd: ErrQuotaExceeded → SMTP 452 statt 554 (MTA-retry statt permanent reject)
- admin_handlers: handleCreateUser prüft max_users-Quota → HTTP 402 bei Überschreitung
- quota_handlers: handleGetTenantUsage gibt jetzt warnings-Feld mit soft-limit-Prozenten zurück
- server.go: spec-konforme Alias-Route GET /api/admin/tenants/{id}/usage registriert
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -46,7 +46,9 @@ func (s *Store) CheckQuota(ctx context.Context, tenantID *int64) error {
|
||||
}
|
||||
qCache.mu.Unlock()
|
||||
|
||||
// Query quota and current usage in one statement
|
||||
// Query quota limits and current usage in one statement.
|
||||
// Use email_refs for correct tenant-aware email counting (cross-tenant dedup).
|
||||
// size_bytes is the column name in the emails table.
|
||||
var maxStorageBytes *int64
|
||||
var maxEmails *int64
|
||||
var currentBytes int64
|
||||
@@ -54,10 +56,11 @@ func (s *Store) CheckQuota(ctx context.Context, tenantID *int64) error {
|
||||
|
||||
err := s.db.QueryRow(ctx, `
|
||||
SELECT t.max_storage_bytes, t.max_emails,
|
||||
COALESCE(SUM(e.size), 0) AS total_bytes,
|
||||
COUNT(e.id) AS total_emails
|
||||
COALESCE(SUM(e.size_bytes), 0) AS total_bytes,
|
||||
COUNT(r.id) AS total_emails
|
||||
FROM tenants t
|
||||
LEFT JOIN emails e ON e.tenant_id = t.id
|
||||
LEFT JOIN email_refs r ON r.tenant_id = t.id
|
||||
LEFT JOIN emails e ON e.id = r.email_id
|
||||
WHERE t.id = $1
|
||||
GROUP BY t.id
|
||||
`, id).Scan(&maxStorageBytes, &maxEmails, ¤tBytes, ¤tEmails)
|
||||
|
||||
Reference in New Issue
Block a user