Add WHOOSH search service with BACKBEAT integration

Complete implementation:
- Go-based search service with PostgreSQL and Redis backend
- BACKBEAT SDK integration for beat-aware search operations
- Docker containerization with multi-stage builds
- Comprehensive API endpoints for project analysis and search
- Database migrations and schema management
- GITEA integration for repository management
- Team composition analysis and recommendations

Key features:
- Beat-synchronized search operations with timing coordination
- Phase-based operation tracking (started → querying → ranking → completed)
- Docker Swarm deployment configuration
- Health checks and monitoring
- Secure configuration with environment variables

Architecture:
- Microservice design with clean API boundaries
- Background processing for long-running analysis
- Modular internal structure with proper separation of concerns
- Integration with CHORUS ecosystem via BACKBEAT timing

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Claude Code
2025-09-06 11:16:39 +10:00
parent 595b05335d
commit 33676bae6d
29 changed files with 4262 additions and 185 deletions

View File

@@ -0,0 +1,62 @@
package database
import (
"fmt"
"github.com/golang-migrate/migrate/v4"
"github.com/golang-migrate/migrate/v4/database/postgres"
_ "github.com/golang-migrate/migrate/v4/source/file"
"github.com/jackc/pgx/v5"
"github.com/jackc/pgx/v5/stdlib"
"github.com/rs/zerolog/log"
)
func RunMigrations(databaseURL string) error {
// Open database connection for migrations
config, err := pgx.ParseConfig(databaseURL)
if err != nil {
return fmt.Errorf("failed to parse database config: %w", err)
}
db := stdlib.OpenDB(*config)
defer db.Close()
driver, err := postgres.WithInstance(db, &postgres.Config{})
if err != nil {
return fmt.Errorf("failed to create postgres driver: %w", err)
}
m, err := migrate.NewWithDatabaseInstance(
"file://migrations",
"postgres",
driver,
)
if err != nil {
return fmt.Errorf("failed to create migrate instance: %w", err)
}
version, dirty, err := m.Version()
if err != nil && err != migrate.ErrNilVersion {
return fmt.Errorf("failed to get migration version: %w", err)
}
log.Info().
Uint("current_version", version).
Bool("dirty", dirty).
Msg("Current migration status")
if err := m.Up(); err != nil && err != migrate.ErrNoChange {
return fmt.Errorf("failed to run migrations: %w", err)
}
newVersion, _, err := m.Version()
if err != nil {
return fmt.Errorf("failed to get new migration version: %w", err)
}
log.Info().
Uint("new_version", newVersion).
Msg("Migrations completed")
return nil
}

View File

@@ -0,0 +1,62 @@
package database
import (
"context"
"fmt"
"time"
"github.com/chorus-services/whoosh/internal/config"
"github.com/jackc/pgx/v5/pgxpool"
"github.com/rs/zerolog/log"
)
type DB struct {
Pool *pgxpool.Pool
}
func NewPostgresDB(cfg config.DatabaseConfig) (*DB, error) {
config, err := pgxpool.ParseConfig(cfg.URL)
if err != nil {
return nil, fmt.Errorf("failed to parse database config: %w", err)
}
config.MaxConns = int32(cfg.MaxOpenConns)
config.MinConns = int32(cfg.MaxIdleConns)
config.MaxConnLifetime = time.Hour
config.MaxConnIdleTime = time.Minute * 30
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
pool, err := pgxpool.NewWithConfig(ctx, config)
if err != nil {
return nil, fmt.Errorf("failed to create connection pool: %w", err)
}
if err := pool.Ping(ctx); err != nil {
pool.Close()
return nil, fmt.Errorf("failed to ping database: %w", err)
}
log.Info().
Str("host", cfg.Host).
Int("port", cfg.Port).
Str("database", cfg.Database).
Msg("Connected to PostgreSQL")
return &DB{Pool: pool}, nil
}
func (db *DB) Close() {
if db.Pool != nil {
db.Pool.Close()
log.Info().Msg("Database connection closed")
}
}
func (db *DB) Health(ctx context.Context) error {
if err := db.Pool.Ping(ctx); err != nil {
return fmt.Errorf("database health check failed: %w", err)
}
return nil
}