Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions go-bracket/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# Build stage
FROM golang:1.21-alpine AS builder

WORKDIR /app

# Install dependencies
COPY go.mod go.sum ./
RUN go mod download

# Copy source code
COPY . .

# Build the application
RUN CGO_ENABLED=1 GOOS=linux go build -a -installsuffix cgo -o main ./cmd/server

# Final stage
FROM alpine:latest

RUN apk --no-cache add ca-certificates sqlite
WORKDIR /root/

# Copy the binary from builder stage
COPY --from=builder /app/main .

# Create directory for SQLite database
RUN mkdir -p /data

# Expose port
EXPOSE 8080

# Set environment variables
ENV DB_DRIVER=sqlite
ENV DB_NAME=/data/bracket.db
ENV GIN_MODE=release

# Run the application
CMD ["./main"]

208 changes: 208 additions & 0 deletions go-bracket/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,208 @@
# Go Bracket - NCAA Tournament Bracket API

A modern Go implementation of the NCAA Basketball Tournament Bracket system, featuring a REST API built with Gin and GORM.

## Features

- **RESTful API** with JWT authentication
- **Multi-database support** (PostgreSQL, SQLite)
- **Tournament bracket management** with automatic scoring
- **User registration and authentication**
- **Admin interface** for managing tournament results
- **Real-time leaderboard**
- **Docker support** for easy deployment

## Architecture

```
go-bracket/
β”œβ”€β”€ cmd/server/ # Application entry point
β”œβ”€β”€ internal/
β”‚ β”œβ”€β”€ models/ # Database models
β”‚ β”œβ”€β”€ handlers/ # HTTP handlers
β”‚ β”œβ”€β”€ middleware/ # HTTP middleware
β”‚ └── database/ # Database configuration
β”œβ”€β”€ pkg/
β”‚ β”œβ”€β”€ auth/ # Authentication utilities
β”‚ └── tournament/ # Tournament business logic
β”œβ”€β”€ configs/ # Configuration files
β”œβ”€β”€ migrations/ # Database migrations
└── docker/ # Docker configuration
```

## Quick Start

### Using Docker Compose (Recommended)

```bash
# Start with PostgreSQL
docker-compose up -d

# Or start with SQLite
docker-compose --profile sqlite up -d bracket-sqlite
```

### Manual Setup

1. **Install dependencies:**
```bash
go mod download
```

2. **Set environment variables:**
```bash
export DB_DRIVER=sqlite
export DB_NAME=bracket.db
```

3. **Run the application:**
```bash
go run cmd/server/main.go
```

## API Endpoints

### Authentication
- `POST /api/v1/auth/register` - Register new user
- `POST /api/v1/auth/login` - Login user
- `GET /api/v1/auth/profile` - Get user profile (protected)

### Tournament
- `GET /api/v1/bracket` - Get tournament bracket
- `GET /api/v1/teams` - Get all teams
- `GET /api/v1/regions` - Get all regions
- `GET /api/v1/leaderboard` - Get current leaderboard

### Player Actions (Protected)
- `GET /api/v1/bracket/player/:id` - Get player's bracket
- `POST /api/v1/bracket/pick` - Make a pick

### Admin Actions (Admin Only)
- `PUT /api/v1/admin/bracket/game/:id/result` - Update game result

## API Usage Examples

### Register a new user
```bash
curl -X POST http://localhost:8080/api/v1/auth/register \
-H "Content-Type: application/json" \
-d '{
"login": "john_doe",
"password": "password123",
"first_name": "John",
"last_name": "Doe",
"email": "john@example.com"
}'
```

### Login
```bash
curl -X POST http://localhost:8080/api/v1/auth/login \
-H "Content-Type: application/json" \
-d '{
"login": "john_doe",
"password": "password123"
}'
```

### Make a pick (requires authentication)
```bash
curl -X POST http://localhost:8080/api/v1/bracket/pick \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_JWT_TOKEN" \
-d '{
"game_id": 1,
"team_id": 5
}'
```

### Get leaderboard
```bash
curl http://localhost:8080/api/v1/leaderboard
```

## Database Models

The application uses the following core models:

- **Region**: Tournament regions (East, Midwest, South, West)
- **Team**: Tournament teams with seeding
- **Player**: User accounts with authentication
- **Game**: Tournament games with results
- **Pick**: Player predictions for games
- **Tournament**: Tournament metadata

## Configuration

Environment variables:

| Variable | Default | Description |
|----------|---------|-------------|
| `DB_DRIVER` | `sqlite` | Database driver (sqlite, postgres) |
| `DB_HOST` | `localhost` | Database host |
| `DB_PORT` | `5432` | Database port |
| `DB_USER` | `bracket` | Database user |
| `DB_PASSWORD` | `` | Database password |
| `DB_NAME` | `bracket.db` | Database name |
| `DB_SSLMODE` | `disable` | SSL mode for PostgreSQL |
| `PORT` | `8080` | Server port |

## Development

### Running tests
```bash
go test ./...
```

### Building for production
```bash
CGO_ENABLED=1 GOOS=linux go build -a -installsuffix cgo -o bracket ./cmd/server
```

## Deployment

The application can be deployed using:

1. **Docker** - Use the provided Dockerfile
2. **Docker Compose** - For development with PostgreSQL
3. **Binary** - Compile and run the binary directly
4. **Cloud platforms** - Deploy to AWS, GCP, Azure, etc.

## Tournament Logic

The bracket system supports:

- **64-team single elimination tournament**
- **4 regions with 16 teams each**
- **6 rounds**: First Round β†’ Second Round β†’ Sweet 16 β†’ Elite 8 β†’ Final Four β†’ Championship
- **Progressive scoring**: Later rounds worth more points
- **Real-time score calculation**
- **Admin controls** for updating game results

## Security Features

- **JWT-based authentication**
- **Password hashing** with bcrypt
- **CORS support**
- **Admin role separation**
- **Input validation**

## Performance Considerations

- **Database indexing** on foreign keys
- **Efficient queries** with GORM preloading
- **Stateless design** for horizontal scaling
- **Connection pooling** for database connections

## Contributing

1. Fork the repository
2. Create a feature branch
3. Make your changes
4. Add tests
5. Submit a pull request

## License

This project maintains the same license as the original Perl implementation.

87 changes: 87 additions & 0 deletions go-bracket/cmd/server/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
package main

import (
"log"
"os"

"bracket/internal/database"
"bracket/internal/handlers"
"bracket/internal/middleware"

"github.com/gin-gonic/gin"
)

func main() {
// Initialize database
dbConfig := database.Config{
Driver: getEnv("DB_DRIVER", "sqlite"),
Host: getEnv("DB_HOST", "localhost"),
Port: getEnv("DB_PORT", "5432"),
User: getEnv("DB_USER", "bracket"),
Password: getEnv("DB_PASSWORD", ""),
DBName: getEnv("DB_NAME", "bracket.db"),
SSLMode: getEnv("DB_SSLMODE", "disable"),
}

if err := database.Initialize(dbConfig); err != nil {
log.Fatal("Failed to initialize database:", err)
}

// Initialize Gin router
r := gin.Default()

// Add middleware
r.Use(middleware.CORSMiddleware())

// Initialize handlers
authHandler := handlers.NewAuthHandler()
bracketHandler := handlers.NewBracketHandler()

// Public routes
public := r.Group("/api/v1")
{
public.POST("/auth/login", authHandler.Login)
public.POST("/auth/register", authHandler.Register)
public.GET("/bracket", bracketHandler.GetBracket)
public.GET("/teams", bracketHandler.GetTeams)
public.GET("/regions", bracketHandler.GetRegions)
public.GET("/leaderboard", bracketHandler.GetLeaderboard)
}

// Protected routes (require authentication)
protected := r.Group("/api/v1")
protected.Use(middleware.AuthMiddleware())
{
protected.GET("/auth/profile", authHandler.GetProfile)
protected.GET("/bracket/player/:player_id", bracketHandler.GetPlayerBracket)
protected.POST("/bracket/pick", bracketHandler.CreatePick)
}

// Admin routes
admin := r.Group("/api/v1/admin")
admin.Use(middleware.AuthMiddleware(), middleware.AdminMiddleware())
{
admin.PUT("/bracket/game/:game_id/result", bracketHandler.UpdateGameResult)
}

// Health check
r.GET("/health", func(c *gin.Context) {
c.JSON(200, gin.H{"status": "ok"})
})

// Start server
port := getEnv("PORT", "8080")
log.Printf("Starting server on port %s", port)
if err := r.Run(":" + port); err != nil {
log.Fatal("Failed to start server:", err)
}
}

// getEnv gets an environment variable with a default value
func getEnv(key, defaultValue string) string {
if value := os.Getenv(key); value != "" {
return value
}
return defaultValue
}

47 changes: 47 additions & 0 deletions go-bracket/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
version: '3.8'

services:
bracket-api:
build: .
ports:
- "8080:8080"
environment:
- DB_DRIVER=postgres
- DB_HOST=postgres
- DB_PORT=5432
- DB_USER=bracket
- DB_PASSWORD=bracket123
- DB_NAME=bracket
- DB_SSLMODE=disable
depends_on:
- postgres
volumes:
- ./data:/data

postgres:
image: postgres:15-alpine
environment:
- POSTGRES_USER=bracket
- POSTGRES_PASSWORD=bracket123
- POSTGRES_DB=bracket
ports:
- "5432:5432"
volumes:
- postgres_data:/var/lib/postgresql/data

# SQLite version (alternative)
bracket-sqlite:
build: .
ports:
- "8081:8080"
environment:
- DB_DRIVER=sqlite
- DB_NAME=/data/bracket.db
volumes:
- ./data:/data
profiles:
- sqlite

volumes:
postgres_data:

Loading