diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..dda0c5e --- /dev/null +++ b/.dockerignore @@ -0,0 +1,50 @@ +# Git files +.git +.gitignore +.gitattributes + +# IDE files +.vscode +.idea +*.swp +*.swo +*~ +.DS_Store + +# Test files and coverage +*.test +*.out +coverage.out +.coverage + +# Development files +.env +.env.local +*.log + +# Build artifacts +bin/ +dist/ +build/ + +# Dependencies +vendor/ + +# Documentation +docs/ +README.md + +# Test scripts +scripts/test.sh + +# Postman collection +IMS_Postman_Collection.json + +# Docker +Dockerfile +docker-compose.yml +.dockerignore + +# Temporary files +tmp/ +temp/ diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..d34c780 --- /dev/null +++ b/.env.example @@ -0,0 +1,8 @@ +# Database Configuration +DB_NAME=ims +DB_USER=postgres +DB_PASSWORD=your_secure_password_here +DB_PORT=5432 + +# Application Configuration +APP_PORT=3000 diff --git a/.gitignore b/.gitignore index 4c49bd7..2eea525 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1 @@ -.env +.env \ No newline at end of file diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..70ce911 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,45 @@ +# Multi-stage build for Go application +FROM golang:1.25.1-alpine AS builder + +# Install build dependencies +RUN apk add --no-cache git gcc musl-dev + +WORKDIR /app + +# Copy go mod files +COPY go.mod go.sum ./ + +# Download dependencies +RUN go mod download + +# Copy source code +COPY . . + +# Build the application +RUN CGO_ENABLED=1 GOOS=linux go build -a -installsuffix cgo -o main . + +# Final stage +FROM alpine:latest + +# Install runtime dependencies (PostgreSQL client and ca-certificates for HTTPS) +RUN apk --no-cache add ca-certificates postgresql-client + +WORKDIR /root/ + +# Copy the binary from builder +COPY --from=builder /app/main . + +# Copy migrations and web assets +COPY migrations/ ./migrations/ +COPY web/ ./web/ +COPY configs/ ./configs/ + +# Expose the application port +EXPOSE 3000 + +# Health check +HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \ + CMD wget --quiet --tries=1 --spider http://localhost:3000/health || exit 1 + +# Run the application +CMD ["./main"] diff --git a/README.md b/README.md new file mode 100644 index 0000000..77deaf5 --- /dev/null +++ b/README.md @@ -0,0 +1,205 @@ +# Inventory Management System (IMS) + +A comprehensive REST API for enterprise-grade inventory management built with Go, GORM, and PostgreSQL. This project provides complete inventory tracking, warehouse management, purchase orders, sales orders, and audit logging capabilities. + +## Features + +- **Product Management** – Create, read, update, delete products with detailed specifications +- **Warehouse Management** – Multi-warehouse support with location tracking +- **Inventory Tracking** – Real-time stock level monitoring and stock movement history +- **Purchase Orders** – Supplier order management with item-level tracking +- **Sales Orders** – Customer order management with fulfillment tracking +- **Audit Logging** – Comprehensive audit trail for compliance and accountability +- **Reporting** – Generate inventory and sales reports +- **RESTful API** – Clean, standard REST endpoints for all operations +- **Database Migrations** – Automated schema management with SQL migrations +- **Environment Configuration** – Flexible configuration via .env file + +## Prerequisites + +- Go 1.25+ ([download](https://golang.org/dl/)) +- PostgreSQL 12+ ([download](https://www.postgresql.org/download/)) +- Git + +## Installation + +1. **Clone the repository** + ```bash + git clone + cd Golang + ``` + +2. **Install dependencies** + ```bash + go mod download + ``` + +3. **Set up PostgreSQL database** + ```bash + createdb ims_db + createuser ims_user -P # You'll be prompted for a password + ``` + +## Configuration + +Create a `.env` file in the project root with the following variables: + +```env +DB_HOST=localhost +DB_PORT=5432 +DB_USER=ims_user +DB_PASSWORD=your_password_here +DB_NAME=ims_db +SERVER_PORT=8080 +``` + +## Running the Application + +Start the server: +```bash +go run main.go +``` + +The API will be available at `http://localhost:8080` + +## Project Structure + +``` +. +├── main.go # Application entry point +├── go.mod # Go module definition +├── api/ # API-related code +├── cmd/ # Command-line interface (Cobra CLI) +├── configs/ # Configuration management +├── internal/ # Private application code +│ ├── db.go # Database initialization +│ ├── models.go # Data models +│ ├── audit/ # Audit logging module +│ ├── inventory/ # Inventory management module +│ ├── orders/ # Sales orders module +│ ├── products/ # Product management module +│ ├── reports/ # Reporting module +│ ├── suppliers/ # Supplier management module +│ └── warehouses/ # Warehouse management module +├── migrations/ # SQL migration files +│ ├── 001_create_users.sql +│ └── 002_ims_schema.sql +├── pkg/ # Public/reusable packages +│ ├── utils.go # Utility functions +│ └── middleware/ # HTTP middleware +├── test/ # Test files +├── web/ # Web assets +└── docs/ # Documentation +``` + +## API Endpoints + +### Products +- `GET /products` – List all products +- `GET /products/{id}` – Get product details +- `POST /products` – Create a new product +- `PUT /products/{id}` – Update a product +- `DELETE /products/{id}` – Delete a product +- `GET /products/search` – Search products + +### Warehouses +- `GET /warehouses` – List all warehouses +- `GET /warehouses/{id}` – Get warehouse details +- `POST /warehouses` – Create a warehouse +- `PUT /warehouses/{id}` – Update a warehouse +- `DELETE /warehouses/{id}` – Delete a warehouse + +### Inventory +- `GET /inventory` – List inventory items +- `GET /inventory/{id}` – Get inventory item details +- `POST /inventory` – Add inventory +- `PUT /inventory/{id}` – Update inventory levels +- `DELETE /inventory/{id}` – Remove inventory + +### Purchase Orders +- `GET /purchase-orders` – List purchase orders +- `POST /purchase-orders` – Create purchase order +- `GET /purchase-orders/{id}` – Get order details +- `PUT /purchase-orders/{id}` – Update order +- `DELETE /purchase-orders/{id}` – Cancel order + +### Sales Orders +- `GET /orders` – List sales orders +- `POST /orders` – Create order +- `GET /orders/{id}` – Get order details +- `PUT /orders/{id}` – Update order +- `DELETE /orders/{id}` – Cancel order + +### Audit Logs +- `GET /audit-logs` – List audit logs + +For complete API documentation, see [docs/API_DOCUMENTATION.md](docs/API_DOCUMENTATION.md) or import [IMS_Postman_Collection.json](IMS_Postman_Collection.json) into Postman. + +## Database Schema + +The application uses automated migrations via GORM. Database migrations are located in the `migrations/` directory: +- `001_create_users.sql` – User table and initial setup +- `002_ims_schema.sql` – Complete IMS schema + +Migrations run automatically on application startup. + +## Development + +### Running Tests +```bash +go test ./... +``` + +Or using the provided test script: +```bash +bash scripts/test.sh +``` + +### Code Structure Best Practices + +This project follows Go conventions: +- **Package organization** – Code is organized by feature domain in `internal/` +- **Exports** – Only exported types and functions (capitalized) are part of the public API +- **Interfaces** – Used for abstraction and testability +- **Error handling** – Explicit error handling throughout + +### Adding New Features + +1. Create a new package under `internal/` for your feature +2. Define models in the appropriate package or in `internal/models.go` +3. Create handlers in `{feature}/handlers.go` +4. Register routes in `main.go` +5. Add database migrations if needed +6. Update API documentation + +## Logging + +The application includes comprehensive logging: +- Database connection status +- Migration results +- Audit trail of all data modifications +- Error logging for debugging + +Logs use Go's standard `log` package and are printed to stdout. + +## Dependencies + +Key dependencies: +- **GORM** – Go ORM for database operations +- **PostgreSQL Driver** – GORM PostgreSQL driver +- **Cobra** – CLI framework for command-line tools +- **godotenv** – Environment variable management + +See `go.mod` for complete list of dependencies. + +## License + +[Add your license information here] + +## Contributing + +[Add contribution guidelines here] + +--- + +For more information, see [docs/API_DOCUMENTATION.md](docs/API_DOCUMENTATION.md) or contact the development team. diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..9267be7 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,54 @@ +version: '3.8' + +services: + # PostgreSQL Database Service + postgres: + image: postgres:16-alpine + container_name: ims_postgres + environment: + POSTGRES_DB: ${DB_NAME} + POSTGRES_USER: ${DB_USER} + POSTGRES_PASSWORD: ${DB_PASSWORD} + ports: + - "${DB_PORT:-5432}:5432" + volumes: + - postgres_data:/var/lib/postgresql/data + - ./migrations:/docker-entrypoint-initdb.d + networks: + - ims_network + healthcheck: + test: ["CMD-SHELL", "pg_isready -U ${DB_USER:-postgres}"] + interval: 10s + timeout: 5s + retries: 5 + + # Go Application Service + app: + build: + context: . + dockerfile: Dockerfile + container_name: ims_app + environment: + DB_HOST: postgres + DB_PORT: 5432 + DB_NAME: ${DB_NAME} + DB_USER: ${DB_USER} + DB_PASSWORD: ${DB_PASSWORD} + ports: + - "${APP_PORT:-3000}:3000" + depends_on: + postgres: + condition: service_healthy + networks: + - ims_network + restart: unless-stopped + volumes: + - ./configs:/root/configs + - ./web:/root/web + +volumes: + postgres_data: + +networks: + ims_network: + driver: bridge diff --git a/docker-setup.ps1 b/docker-setup.ps1 new file mode 100644 index 0000000..131ff43 --- /dev/null +++ b/docker-setup.ps1 @@ -0,0 +1,154 @@ +#!/usr/bin/env pwsh + +# Docker Setup Script for IMS Project +# Usage: .\docker-setup.ps1 [up|down|logs|build|rebuild|clean] + +param( + [string]$Command = "up", + [switch]$Detach = $false +) + +$ErrorActionPreference = "Stop" + +function PrintHeader { + Write-Host "`n========================================" -ForegroundColor Cyan + Write-Host " IMS Docker Setup" -ForegroundColor Cyan + Write-Host "========================================`n" -ForegroundColor Cyan +} + +function CreateEnvFile { + if (-not (Test-Path ".env")) { + Write-Host "Creating .env file from .env.example..." -ForegroundColor Yellow + Copy-Item -Path ".env.example" -Destination ".env" + Write-Host ".env file created. Please review and update as needed." -ForegroundColor Green + } +} + +function BuildImages { + Write-Host "Building Docker images..." -ForegroundColor Yellow + docker-compose build --no-cache + if ($LASTEXITCODE -eq 0) { + Write-Host "Images built successfully!" -ForegroundColor Green + } else { + Write-Host "Failed to build images!" -ForegroundColor Red + exit 1 + } +} + +function StartServices { + PrintHeader + CreateEnvFile + + Write-Host "Starting services..." -ForegroundColor Yellow + + if ($Detach) { + docker-compose up -d + } else { + docker-compose up + } + + if ($LASTEXITCODE -eq 0) { + Write-Host "`nServices started successfully!" -ForegroundColor Green + Write-Host "Application running at: http://localhost:3000" -ForegroundColor Green + Write-Host "Database: postgres://postgres@localhost:5432/ims" -ForegroundColor Green + } else { + Write-Host "Failed to start services!" -ForegroundColor Red + exit 1 + } +} + +function StopServices { + Write-Host "Stopping services..." -ForegroundColor Yellow + docker-compose down + + if ($LASTEXITCODE -eq 0) { + Write-Host "Services stopped successfully!" -ForegroundColor Green + } else { + Write-Host "Failed to stop services!" -ForegroundColor Red + exit 1 + } +} + +function ViewLogs { + Write-Host "Viewing logs (Ctrl+C to exit)..." -ForegroundColor Yellow + docker-compose logs -f +} + +function CleanAll { + Write-Host "WARNING: This will delete all containers and volumes (including database data)!" -ForegroundColor Red + $confirm = Read-Host "Type 'yes' to confirm" + + if ($confirm -eq "yes") { + Write-Host "Cleaning up..." -ForegroundColor Yellow + docker-compose down -v + Write-Host "Cleanup complete!" -ForegroundColor Green + } else { + Write-Host "Cleanup cancelled." -ForegroundColor Yellow + } +} + +function RebuildAll { + Write-Host "Rebuilding images and starting services..." -ForegroundColor Yellow + docker-compose down -v + docker-compose build --no-cache + docker-compose up -d + Write-Host "Rebuild complete!" -ForegroundColor Green +} + +function PrintStatus { + Write-Host "`nService Status:" -ForegroundColor Cyan + docker-compose ps +} + +# Main script logic +switch ($Command) { + "up" { + if ($Detach) { + StartServices + PrintStatus + } else { + StartServices + } + } + "down" { + StopServices + } + "logs" { + ViewLogs + } + "build" { + BuildImages + } + "rebuild" { + RebuildAll + } + "clean" { + CleanAll + } + "status" { + PrintStatus + } + "restart" { + StopServices + Start-Sleep -Seconds 2 + StartServices + } + default { + Write-Host "Usage: .\docker-setup.ps1 [command]" -ForegroundColor Yellow + Write-Host "`nAvailable commands:" -ForegroundColor Yellow + Write-Host " up Start services (attached)" -ForegroundColor White + Write-Host " down Stop services" -ForegroundColor White + Write-Host " logs View service logs" -ForegroundColor White + Write-Host " status Show service status" -ForegroundColor White + Write-Host " build Build Docker images" -ForegroundColor White + Write-Host " rebuild Rebuild everything (removes all data)" -ForegroundColor White + Write-Host " restart Restart services" -ForegroundColor White + Write-Host " clean Delete all containers and volumes" -ForegroundColor White + Write-Host "`nOptions:" -ForegroundColor Yellow + Write-Host " -Detach Run in background (with 'up' command)" -ForegroundColor White + Write-Host "`nExamples:" -ForegroundColor Yellow + Write-Host " .\docker-setup.ps1 up" -ForegroundColor Gray + Write-Host " .\docker-setup.ps1 up -Detach" -ForegroundColor Gray + Write-Host " .\docker-setup.ps1 logs" -ForegroundColor Gray + } +} diff --git a/internal/models.go b/internal/models.go index c5bc624..727e0dd 100644 --- a/internal/models.go +++ b/internal/models.go @@ -8,7 +8,7 @@ import ( type Product struct { ID uint `gorm:"primaryKey" json:"id"` Name string `gorm:"not null" json:"name"` - SKU string `gorm:"uniqueIndex;not null" json:"sku"` + SKU string `gorm:"unique;not null" json:"sku"` Description string `json:"description"` Category string `json:"category"` Price float64 `gorm:"not null" json:"price"` @@ -72,7 +72,7 @@ type Supplier struct { // PurchaseOrder represents orders placed to suppliers type PurchaseOrder struct { ID uint `gorm:"primaryKey" json:"id"` - PONumber string `gorm:"uniqueIndex;not null" json:"po_number"` + PONumber string `gorm:"unique;not null" json:"po_number"` SupplierID uint `gorm:"not null;index" json:"supplier_id"` Status string `gorm:"not null;default:'pending'" json:"status"` // pending, received, cancelled TotalCost float64 `json:"total_cost"` @@ -97,7 +97,7 @@ type POItem struct { // Order represents sales orders type Order struct { ID uint `gorm:"primaryKey" json:"id"` - OrderNumber string `gorm:"uniqueIndex;not null" json:"order_number"` + OrderNumber string `gorm:"unique;not null" json:"order_number"` CustomerName string `gorm:"not null" json:"customer_name"` CustomerEmail string `json:"customer_email"` Status string `gorm:"not null;default:'pending'" json:"status"` // pending, processing, shipped, delivered, cancelled