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

@@ -38,6 +38,7 @@ func (r *Repository) RunMigrations(ctx context.Context) error {
avatar TEXT,
role VARCHAR(50) DEFAULT 'user',
tier VARCHAR(50) DEFAULT 'free',
balance DECIMAL(12,2) DEFAULT 0,
email_verified BOOLEAN DEFAULT FALSE,
provider VARCHAR(50) DEFAULT 'local',
provider_id VARCHAR(255),
@@ -69,6 +70,8 @@ func (r *Repository) RunMigrations(ctx context.Context) error {
created_at TIMESTAMPTZ DEFAULT NOW()
)`,
`CREATE INDEX IF NOT EXISTS idx_password_reset_tokens ON password_reset_tokens(token)`,
`ALTER TABLE auth_users ADD COLUMN IF NOT EXISTS balance DECIMAL(12,2) DEFAULT 0`,
}
for _, m := range migrations {
@@ -125,18 +128,19 @@ func (r *Repository) CreateUser(ctx context.Context, email, password, name strin
func (r *Repository) GetUserByEmail(ctx context.Context, email string) (*User, error) {
query := `
SELECT id, email, password_hash, name, avatar, role, tier, email_verified,
SELECT id, email, password_hash, name, avatar, role, tier, balance, email_verified,
provider, provider_id, last_login_at, created_at, updated_at
FROM auth_users WHERE email = $1
`
user := &User{}
var lastLogin, avatar, providerID sql.NullString
var avatar, providerID sql.NullString
var lastLoginTime sql.NullTime
var balance sql.NullFloat64
err := r.db.QueryRowContext(ctx, query, email).Scan(
&user.ID, &user.Email, &user.PasswordHash, &user.Name, &avatar,
&user.Role, &user.Tier, &user.EmailVerified, &user.Provider,
&user.Role, &user.Tier, &balance, &user.EmailVerified, &user.Provider,
&providerID, &lastLoginTime, &user.CreatedAt, &user.UpdatedAt,
)
@@ -156,14 +160,16 @@ func (r *Repository) GetUserByEmail(ctx context.Context, email string) (*User, e
if lastLoginTime.Valid {
user.LastLoginAt = lastLoginTime.Time
}
_ = lastLogin
if balance.Valid {
user.Balance = balance.Float64
}
return user, nil
}
func (r *Repository) GetUserByID(ctx context.Context, id string) (*User, error) {
query := `
SELECT id, email, password_hash, name, avatar, role, tier, email_verified,
SELECT id, email, password_hash, name, avatar, role, tier, balance, email_verified,
provider, provider_id, last_login_at, created_at, updated_at
FROM auth_users WHERE id = $1
`
@@ -171,10 +177,11 @@ func (r *Repository) GetUserByID(ctx context.Context, id string) (*User, error)
user := &User{}
var avatar, providerID sql.NullString
var lastLoginTime sql.NullTime
var balance sql.NullFloat64
err := r.db.QueryRowContext(ctx, query, id).Scan(
&user.ID, &user.Email, &user.PasswordHash, &user.Name, &avatar,
&user.Role, &user.Tier, &user.EmailVerified, &user.Provider,
&user.Role, &user.Tier, &balance, &user.EmailVerified, &user.Provider,
&providerID, &lastLoginTime, &user.CreatedAt, &user.UpdatedAt,
)
@@ -194,6 +201,9 @@ func (r *Repository) GetUserByID(ctx context.Context, id string) (*User, error)
if lastLoginTime.Valid {
user.LastLoginAt = lastLoginTime.Time
}
if balance.Valid {
user.Balance = balance.Float64
}
return user, nil
}
@@ -254,6 +264,22 @@ func (r *Repository) UpdateRole(ctx context.Context, userID string, role UserRol
return err
}
func (r *Repository) UpdateBalance(ctx context.Context, userID string, amount float64) error {
_, err := r.db.ExecContext(ctx,
"UPDATE auth_users SET balance = balance + $2, updated_at = NOW() WHERE id = $1",
userID, amount,
)
return err
}
func (r *Repository) SetBalance(ctx context.Context, userID string, balance float64) error {
_, err := r.db.ExecContext(ctx,
"UPDATE auth_users SET balance = $2, updated_at = NOW() WHERE id = $1",
userID, balance,
)
return err
}
func (r *Repository) CreateRefreshToken(ctx context.Context, userID, userAgent, ip string, duration time.Duration) (*RefreshToken, error) {
token := generateSecureToken(32)

View File

@@ -12,6 +12,7 @@ type User struct {
Avatar string `json:"avatar,omitempty"`
Role string `json:"role"`
Tier string `json:"tier"`
Balance float64 `json:"balance"`
EmailVerified bool `json:"emailVerified"`
Provider string `json:"provider"`
ProviderID string `json:"providerId,omitempty"`