feat: GPU offload, signup limit, load tests & capacity planning

- Route all AI workloads (Ollama, STT, TTS, Image Gen) to GPU server
  (192.168.178.11) via LAN instead of host.docker.internal
- Upgrade default model to gemma3:12b and max concurrent to 5
- Add daily signup limit service (MAX_DAILY_SIGNUPS env var)
- Add GET /api/v1/auth/signup-status public endpoint
- Add k6 load test suite (web-apps, auth, sync-websocket, ollama)
- Add capacity planning documentation
- Fix: add eslint-config to sveltekit-base and calendar Dockerfiles

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Till JS 2026-03-28 21:14:24 +01:00
parent 16367384c7
commit 9276d9a212
12 changed files with 683 additions and 14 deletions

View file

@ -9,6 +9,7 @@ import { Hono } from 'hono';
import type { AuthUser } from '../middleware/jwt-auth';
import type { BetterAuthInstance } from '../auth/better-auth.config';
import type { SecurityEventsService, AccountLockoutService } from '../services/security';
import type { SignupLimitService } from '../services/signup-limit';
import type { Config } from '../config';
import { sourceAppStore, passwordResetRedirectStore } from '../auth/stores';
@ -16,15 +17,37 @@ export function createAuthRoutes(
auth: BetterAuthInstance,
config: Config,
security: SecurityEventsService,
lockout: AccountLockoutService
lockout: AccountLockoutService,
signupLimit: SignupLimitService
) {
const app = new Hono<{ Variables: { user: AuthUser } }>();
// ─── Registration ────────────────────────────────────────
// ─── Signup Status (public) ─────────────────────────────
app.get('/signup-status', async (c) => {
const status = await signupLimit.getStatus();
return c.json(status);
});
app.post('/register', async (c) => {
const body = await c.req.json();
// Check daily signup limit
const limitCheck = await signupLimit.checkLimit();
if (!limitCheck.allowed) {
return c.json(
{
error: 'Registration limit reached',
message: 'Das tägliche Registrierungslimit ist erreicht. Versuche es morgen wieder.',
spotsRemaining: 0,
resetsAt: limitCheck.resetsAt,
},
429
);
}
// Store source app URL for email verification redirect
if (body.sourceAppUrl && body.email) {
sourceAppStore.set(body.email, body.sourceAppUrl);