# Go Backend Patterns - FikoYT

## 🏗️ Aggregate Pattern

**MongoDB aggregation with FikoYTMap:**
```go
func KullaniciAnalizAggregate(c *fiber.Ctx) error {
    // Complex aggregation with FikoYTMap
    pipeline := mongo.Pipeline{
        {{"$match", FikoYTMap{
            "kullanici_id": FikoYTMap{"$ne": nil},
            "tarih": FikoYTMap{"$gte": baslangic},
        }}},
        {{"$group", FikoYTMap{
            "_id": "$kullanici_id",
            "toplam": FikoYTMap{"$sum": "$tutar"},
            "islem_sayisi": FikoYTMap{"$sum": 1},
        }}},
    }
    // Convert results automatically
    var results []FikoYTMap
    cursor.All(context.Background(), &results)
}
```

## 🎯 FikoYTCtx Pattern

**Context management:**
```go
type FikoYTCtx struct {
    *fiber.Ctx
    User    *User
    Session *session.Store
    Mongo   *mongo.Client
    Redis   *redis.Client
}

// Automatic context creation
func araIsleyici() fiber.Handler {
    return func(c *fiber.Ctx) error {
        ctx := &FikoYTCtx{Ctx: c}
        c.Locals("ctx", ctx)
        return c.Next()
    }
}
```

## 📡 Request Manager Pattern

**HTTP request queue:**
```go
type RequestManager struct {
    queue chan *Request
    workers int
    timeout time.Duration
}

func (rm *RequestManager) Process(req *Request) error {
    // Queue management with retry logic
    for i := 0; i < maxRetries; i++ {
        if err := rm.execute(req); err == nil {
            return nil
        }
        time.Sleep(backoff(i))
    }
}
```

## 🔄 Pipeline Pattern

**Data processing pipeline:**
```go
type Pipeline struct {
    stages []Stage
}

func (p *Pipeline) Process(data interface{}) error {
    for _, stage := range p.stages {
        if err := stage.Execute(data); err != nil {
            return err
        }
    }
    return nil
}
```

## 📝 Repository Pattern

**Data access abstraction:**
```go
type Repository interface {
    FindOne(filter interface{}) (FikoYTMap, error)
    FindMany(filter interface{}) ([]FikoYTMap, error)
    InsertOne(document interface{}) (primitive.ObjectID, error)
    UpdateOne(filter, update interface{}) error
}

type MongoRepository struct {
    collection *mongo.Collection
}
```

## 🎪 Event Pattern

**Event-driven architecture:**
```go
type EventBus struct {
    subscribers map[string][]EventHandler
}

func (eb *EventBus) Emit(event string, data interface{}) {
    if handlers, ok := eb.subscribers[event]; ok {
        for _, handler := range handlers {
            go handler.Handle(data)
        }
    }
}
```

## 🔐 Security Pattern

**Authentication middleware:**
```go
func AuthMiddleware() fiber.Handler {
    return func(c *fiber.Ctx) error {
        token := c.Cookies("auth_token")
        if token == "" {
            return c.Status(401).JSON(fiber.Map{"error": "Unauthorized"})
        }

        claims, err := ValidateToken(token)
        if err != nil {
            return c.Status(401).JSON(fiber.Map{"error": "Invalid token"})
        }

        c.Locals("user", claims)
        return c.Next()
    }
}
```

## 🚀 Error Handling Pattern

**Centralized error handling:**
```go
type FikoYTError struct {
    Code    int
    Message string
    Details interface{}
}

func ErrorHandler() fiber.Handler {
    return func(c *fiber.Ctx) error {
        if err := c.Next(); err != nil {
            if fErr, ok := err.(*FikoYTError); ok {
                return c.Status(fErr.Code).JSON(fErr)
            }
            // Log unexpected errors
            log.Error().Err(err).Msg("Unexpected error")
            return c.Status(500).JSON(fiber.Map{
                "error": "Internal server error",
            })
        }
        return nil
    }
}
```

## 📊 CQRS Pattern

**Command Query Responsibility Segregation:**
```go
type CommandHandler interface {
    Handle(command Command) error
}

type QueryHandler interface {
    Handle(query Query) (interface{}, error)
}

// Separate models for reads and writes
type UserWriteModel struct {
    Name     string
    Email    string
    Password string
}

type UserReadModel struct {
    ID        primitive.ObjectID
    Name      string
    LastLogin time.Time
}
```

## 🎯 Factory Pattern

**Dynamic service creation:**
```go
type ServiceFactory interface {
    CreateService(serviceType string) (interface{}, error)
}

func NewServiceFactory(config Config) ServiceFactory {
    return &factory{
        mongo:    config.Mongo,
        redis:    config.Redis,
        session:  config.Session,
    }
}
```

## 🔄 Observer Pattern

**Real-time notifications:**
```go
type Observer interface {
    Notify(event Event)
}

type Subject interface {
    Subscribe(observer Observer)
    Unsubscribe(observer Observer)
    NotifyObservers(event Event)
}
```

## 🎪 Strategy Pattern

**Algorithm selection:**
```go
type CompressionStrategy interface {
    Compress(data []byte) ([]byte, error)
}

type Context struct {
    strategy CompressionStrategy
}

func (c *Context) Compress(data []byte) ([]byte, error) {
    return c.strategy.Compress(data)
}
```

## 📝 Builder Pattern

**Complex query building:**
```go
type QueryBuilder struct {
    filter    bson.M
    options   *options.FindOptions
    sort      bson.M
    limit     int64
}

func NewQueryBuilder() *QueryBuilder {
    return &QueryBuilder{
        filter: make(bson.M),
    }
}

func (qb *QueryBuilder) Filter(field string, value interface{}) *QueryBuilder {
    qb.filter[field] = value
    return qb
}

func (qb *QueryBuilder) Build() (*options.FindOptions, bson.M) {
    // Apply all options
    return qb.options, qb.filter
}
```

## 🚦 Circuit Breaker Pattern

**Resilience for external calls:**
```go
type CircuitBreaker struct {
    failures    int
    threshold   int
    timeout     time.Duration
    state       State
    lastFailure time.Time
}

func (cb *CircuitBreaker) Call(fn func() error) error {
    if cb.state == Open {
        if time.Since(cb.lastFailure) > cb.timeout {
            cb.state = HalfOpen
        } else {
            return ErrCircuitBreakerOpen
        }
    }

    err := fn()
    if err != nil {
        cb.failures++
        if cb.failures >= cb.threshold {
            cb.state = Open
        }
        return err
    }

    cb.failures = 0
    cb.state = Closed
    return nil
}
```

---
2025-11-06