feat: spaces redesign, model selector, auth fixes

Spaces:
- Perplexity-like UI with collaboration features
- Space detail page with threads/members tabs
- Invite members via email, role management
- New space creation with icon/color picker

Model selector:
- Added Ollama client for free Auto model
- GooSeek 1.0 via Timeweb (tariff-based)
- Frontend model dropdown in ChatInput

Auth & Infrastructure:
- Fixed auth-svc missing from Dockerfile.all
- Removed duplicate ratelimit_tiered.go (conflict)
- Added Redis to api-gateway for rate limiting
- Fixed Next.js proxy for local development

UI improvements:
- Redesigned login button in sidebar (gradient)
- Settings page with tabs (account/billing/prefs)
- Auth pages visual refresh

Made-with: Cursor
This commit is contained in:
home
2026-02-28 02:30:05 +03:00
parent a0e3748dde
commit e6b9cfc60a
33 changed files with 2940 additions and 810 deletions

View File

@@ -93,15 +93,23 @@ func main() {
providerID = "timeweb"
modelKey = "gpt-4o"
} else if providerID == "" {
providerID = "openai"
modelKey = "gpt-4o-mini"
providerID = "ollama"
modelKey = cfg.OllamaModelKey
}
baseURL := cfg.TimewebAPIBaseURL
if providerID == "ollama" {
baseURL = cfg.OllamaBaseURL
if modelKey == "" {
modelKey = cfg.OllamaModelKey
}
}
llmClient, err := llm.NewClient(llm.ProviderConfig{
ProviderID: providerID,
ModelKey: modelKey,
APIKey: getAPIKey(cfg, providerID),
BaseURL: cfg.TimewebAPIBaseURL,
BaseURL: baseURL,
AgentAccessID: cfg.TimewebAgentAccessID,
})
if err != nil {
@@ -200,6 +208,8 @@ func main() {
func getAPIKey(cfg *config.Config, providerID string) string {
switch providerID {
case "ollama":
return ""
case "timeweb":
return cfg.TimewebAPIKey
case "openai":

View File

@@ -2,6 +2,7 @@ package main
import (
"bufio"
"context"
"fmt"
"io"
"log"
@@ -15,6 +16,7 @@ import (
"github.com/gofiber/fiber/v2/middleware/logger"
"github.com/gooseek/backend/pkg/config"
"github.com/gooseek/backend/pkg/middleware"
"github.com/redis/go-redis/v9"
)
var svcURLs map[string]string
@@ -25,6 +27,19 @@ func main() {
log.Fatal("Failed to load config:", err)
}
opt, err := redis.ParseURL(cfg.RedisURL)
if err != nil {
log.Printf("Warning: failed to parse Redis URL, rate limiting will be disabled: %v", err)
}
var redisClient *redis.Client
if opt != nil {
redisClient = redis.NewClient(opt)
if _, err := redisClient.Ping(context.Background()).Result(); err != nil {
log.Printf("Warning: Redis not available, rate limiting will be disabled: %v", err)
redisClient = nil
}
}
svcURLs = map[string]string{
"auth": cfg.AuthSvcURL,
"chat": cfg.ChatSvcURL,
@@ -62,14 +77,17 @@ func main() {
AllowGuest: true,
}))
app.Use(middleware.TieredRateLimit(middleware.TieredRateLimitConfig{
Tiers: map[string]middleware.TierConfig{
"free": {Max: 60, Window: time.Minute},
"pro": {Max: 300, Window: time.Minute},
"business": {Max: 1000, Window: time.Minute},
},
DefaultTier: "free",
}))
if redisClient != nil {
app.Use(middleware.TieredRateLimit(middleware.TieredRateLimitConfig{
RedisClient: redisClient,
Tiers: map[string]middleware.TierConfig{
"free": {Max: 60, Window: time.Minute},
"pro": {Max: 300, Window: time.Minute},
"business": {Max: 1000, Window: time.Minute},
},
DefaultTier: "free",
}))
}
app.Get("/health", func(c *fiber.Ctx) error {
return c.JSON(fiber.Map{"status": "ok"})