Add full monorepo: virtual-banker, backend, frontend, docs, scripts, deployment

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
defiQUG
2026-02-10 11:32:49 -08:00
commit b4753cef7e
81 changed files with 9255 additions and 0 deletions

68
backend/safety/filter.go Normal file
View File

@@ -0,0 +1,68 @@
package safety
import (
"context"
"strings"
)
// Filter filters content for safety
type Filter interface {
Filter(ctx context.Context, text string) (*FilterResult, error)
}
// FilterResult contains filtering results
type FilterResult struct {
Allowed bool
Blocked bool
Redacted string
Categories []string // e.g., "profanity", "pii", "abuse"
}
// ContentFilter implements content filtering
type ContentFilter struct {
blockedWords []string
}
// NewContentFilter creates a new content filter
func NewContentFilter() *ContentFilter {
return &ContentFilter{
blockedWords: []string{
// Add blocked words/phrases
},
}
}
// Filter filters content
func (f *ContentFilter) Filter(ctx context.Context, text string) (*FilterResult, error) {
lowerText := strings.ToLower(text)
var categories []string
// Check for blocked words
for _, word := range f.blockedWords {
if strings.Contains(lowerText, strings.ToLower(word)) {
categories = append(categories, "profanity")
return &FilterResult{
Allowed: false,
Blocked: true,
Redacted: f.redactPII(text),
Categories: categories,
}, nil
}
}
// TODO: Add more sophisticated filtering (ML models, etc.)
return &FilterResult{
Allowed: true,
Blocked: false,
Redacted: f.redactPII(text),
}, nil
}
// redactPII redacts personally identifiable information
func (f *ContentFilter) redactPII(text string) string {
// TODO: Implement PII detection and redaction
// For now, return as-is
return text
}

View File

@@ -0,0 +1,59 @@
package safety
import (
"context"
"fmt"
"time"
"github.com/redis/go-redis/v9"
)
// RateLimiter implements rate limiting
type RateLimiter struct {
redis *redis.Client
}
// NewRateLimiter creates a new rate limiter
func NewRateLimiter(redisClient *redis.Client) *RateLimiter {
return &RateLimiter{
redis: redisClient,
}
}
// Check checks if a request is within rate limits
func (r *RateLimiter) Check(ctx context.Context, key string, limit int, window time.Duration) (bool, error) {
// Use sliding window log algorithm
now := time.Now()
windowStart := now.Add(-window)
// Count requests in window
count, err := r.redis.ZCount(ctx, key, fmt.Sprintf("%d", windowStart.Unix()), fmt.Sprintf("%d", now.Unix())).Result()
if err != nil {
return false, err
}
if count >= int64(limit) {
return false, nil
}
// Add current request
_, err = r.redis.ZAdd(ctx, key, redis.Z{
Score: float64(now.Unix()),
Member: fmt.Sprintf("%d", now.UnixNano()),
}).Result()
if err != nil {
return false, err
}
// Expire old entries
r.redis.Expire(ctx, key, window)
return true, nil
}
// CheckUser checks rate limit for a user
func (r *RateLimiter) CheckUser(ctx context.Context, tenantID, userID string, limit int, window time.Duration) (bool, error) {
key := fmt.Sprintf("ratelimit:user:%s:%s", tenantID, userID)
return r.Check(ctx, key, limit, window)
}