diff --git a/.env.example b/.env.example index 225fa34..8d88262 100644 --- a/.env.example +++ b/.env.example @@ -1,5 +1,5 @@ # Application Configuration -APP_NAME=ackify +APP_NAME=ackify-ce APP_DNS=your-domain.com APP_BASE_URL=https://your-domain.com APP_ORGANISATION="Your Organization Name" diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 07e0954..cff5d5b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -10,7 +10,7 @@ on: env: REGISTRY: docker.io - IMAGE_NAME: btouchard/ackify + IMAGE_NAME: btouchard/ackify-ce jobs: test: diff --git a/BUILD.md b/BUILD.md new file mode 100644 index 0000000..8ce01c1 --- /dev/null +++ b/BUILD.md @@ -0,0 +1,164 @@ +# Ackify Community Edition - Build & Deployment Guide + +## Overview + +Ackify Community Edition (CE) is the open-source version of Ackify, a document signature validation platform. This guide covers building and deploying the Community Edition. + +## Prerequisites + +- Go 1.24.5 or later +- Docker and Docker Compose (for containerized deployment) +- PostgreSQL 16+ (for database) + +## Building from Source + +### 1. Clone the Repository + +```bash +git clone https://github.com/btouchard/ackify-ce.git +cd ackify-ce +``` + +### 2. Build the Application + +```bash +# Build Community Edition +go build ./cmd/community + +# Or build with specific output name +go build -o ackify-ce ./cmd/community +``` + +### 3. Run Tests + +```bash +# Run all tests +go test ./... + +# Run tests with verbose output +go test -v ./tests/ +``` + +## Configuration + +### Environment Variables + +Copy the example environment file and modify it: + +```bash +cp .env.example .env +``` + +Required environment variables: + +- `APP_BASE_URL`: Public URL of your application +- `OAUTH_CLIENT_ID`: OAuth2 client ID +- `OAUTH_CLIENT_SECRET`: OAuth2 client secret +- `DB_DSN`: PostgreSQL connection string +- `OAUTH_COOKIE_SECRET`: Base64-encoded secret for session cookies + +### OAuth2 Providers + +Supported providers: +- `google` (default) +- `github` +- `gitlab` +- Custom (specify `OAUTH_AUTH_URL`, `OAUTH_TOKEN_URL`, `OAUTH_USERINFO_URL`) + +## Deployment Options + +### Option 1: Direct Binary + +1. Build the application +2. Set environment variables +3. Run the binary: + +```bash +./community +``` + +### Option 2: Docker Compose (Recommended) + +1. Configure environment variables in `.env` file +2. Start services: + +```bash +docker compose up -d +``` + +3. Check logs: + +```bash +docker compose logs ackify-ce +``` + +4. Stop services: + +```bash +docker compose down +``` + +### Option 3: Docker Build + +```bash +# Build Docker image +docker build -t ackify-ce:latest . + +# Run with environment file +docker run --env-file .env -p 8080:8080 ackify-ce:latest +``` + +## Database Setup + +The application requires PostgreSQL. When using Docker Compose, the database is automatically created and configured. + +For manual setup: + +1. Create a PostgreSQL database +2. The application will automatically create required tables on first run +3. Set the `DB_DSN` environment variable to your database connection string + +## Health Checks + +The application provides a health endpoint: + +```bash +curl http://localhost:8080/health +``` + +## Production Considerations + +1. **HTTPS**: Always use HTTPS in production (set `APP_BASE_URL` with https://) +2. **Secrets**: Use strong, randomly generated secrets for `OAUTH_COOKIE_SECRET` +3. **Database**: Use a dedicated PostgreSQL instance with proper backups +4. **Monitoring**: Monitor the `/health` endpoint for application status +5. **Logs**: Configure proper log aggregation and monitoring + +## API Endpoints + +- `GET /` - Homepage +- `GET /health` - Health check +- `GET /sign?doc=` - Document signing interface +- `POST /sign` - Create signature +- `GET /status?doc=` - Get document signature status (JSON) +- `GET /status.png?doc=&user=` - Signature status badge + +## Troubleshooting + +### Common Issues + +1. **Port already in use**: Change `LISTEN_ADDR` in environment variables +2. **Database connection failed**: Check `DB_DSN` and ensure PostgreSQL is running +3. **OAuth2 errors**: Verify `OAUTH_CLIENT_ID` and `OAUTH_CLIENT_SECRET` + +### Logs + +Enable debug logging by setting `LOG_LEVEL=debug` in your environment. + +## Contributing + +This is the Community Edition. Contributions are welcome! Please see the main repository for contribution guidelines. + +## License + +Community Edition is released under the Server Side Public License (SSPL). \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index 0851ccb..969cf1a 100644 --- a/Dockerfile +++ b/Dockerfile @@ -29,7 +29,7 @@ ARG BUILD_DATE="unknown" RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build \ -a -installsuffix cgo \ -ldflags="-w -s -X main.Version=${VERSION} -X main.Commit=${COMMIT} -X main.BuildDate=${BUILD_DATE}" \ - -o ackify ./cmd/ackify + -o ackify-ce ./cmd/community # ---- Runtime stage ---- FROM gcr.io/distroless/static-debian12:nonroot @@ -41,7 +41,7 @@ ARG VERSION="dev" LABEL maintainer="Benjamin TOUCHARD" LABEL version="${VERSION}" LABEL description="Ackify - Document signature validation platform" -LABEL org.opencontainers.image.source="https://github.com/btouchard/ackify" +LABEL org.opencontainers.image.source="https://github.com/btouchard/ackify-ce" LABEL org.opencontainers.image.description="Professional solution for validating and tracking document reading" LABEL org.opencontainers.image.licenses="SSPL" @@ -50,7 +50,7 @@ COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ # Set working directory and copy application files WORKDIR /app -COPY --from=builder /app/ackify /app/ackify +COPY --from=builder /app/ackify-ce /app/ackify-ce COPY --from=builder /app/web /app/web # Use non-root user (already set in distroless image) @@ -59,4 +59,4 @@ COPY --from=builder /app/web /app/web EXPOSE 8080 -ENTRYPOINT ["/app/ackify"] +ENTRYPOINT ["/app/ackify-ce"] diff --git a/LICENSE b/LICENSE index 68f94e0..001676d 100644 --- a/LICENSE +++ b/LICENSE @@ -31,7 +31,7 @@ Change Date: The earlier of the date specified in a Change License, or Change License: Apache License, Version 2.0 For information about alternative licensing arrangements for the Licensed Work, -please visit: https://github.com/btouchard/ackify +please visit: https://github.com/btouchard/ackify-ce Notice diff --git a/Makefile b/Makefile index c4cc0bc..c2282dc 100644 --- a/Makefile +++ b/Makefile @@ -1,10 +1,10 @@ -# Makefile for ackify project +# Makefile for ackify-ce project .PHONY: build test test-unit test-integration test-short coverage lint fmt vet clean help # Variables -BINARY_NAME=ackapp -BUILD_DIR=./cmd/ackapp +BINARY_NAME=ackify-ce +BUILD_DIR=./cmd/community COVERAGE_DIR=coverage # Default target @@ -108,7 +108,7 @@ generate-mocks: ## Generate mocks for interfaces # Docker targets docker-build: ## Build Docker image - docker build -t ackify:latest . + docker build -t ackify-ce:latest . docker-test: ## Run tests in Docker environment docker compose -f docker-compose.local.yml up -d postgres diff --git a/README.md b/README.md index 8c60a4a..08505df 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ Secure document reading validation service with cryptographic traceability and irrefutable proof. -[![Build](https://img.shields.io/badge/build-passing-brightgreen.svg)](https://github.com/btouchard/ackify) +[![Build](https://img.shields.io/badge/build-passing-brightgreen.svg)](https://github.com/btouchard/ackify-ce) [![Security](https://img.shields.io/badge/crypto-Ed25519-blue.svg)](https://en.wikipedia.org/wiki/EdDSA) [![Go](https://img.shields.io/badge/go-1.24.5-blue.svg)](https://golang.org/) [![License](https://img.shields.io/badge/license-SSPL-blue.svg)](LICENSE) @@ -65,8 +65,8 @@ Secure document reading validation service with cryptographic traceability and i ### With Docker (recommended) ```bash -git clone https://github.com/btouchard/ackify.git -cd ackify +git clone https://github.com/btouchard/ackify-ce.git +cd ackify-ce # Minimal configuration cp .env.example .env @@ -221,7 +221,7 @@ CREATE TABLE signatures ( version: '3.8' services: ackapp: - image: btouchard/ackify:latest + image: btouchard/ackify-ce:latest environment: APP_BASE_URL: https://ackify.company.com DB_DSN: postgres://user:pass@postgres:5432/ackdb?sslmode=require @@ -291,7 +291,7 @@ DB_DSN="postgres://user:pass@postgres:5432/ackdb?sslmode=require" go mod tidy # Build -go build ./cmd/ackify +go build ./cmd/community # Linting go fmt ./... @@ -304,10 +304,10 @@ go test -v ./... ### Docker development ```bash # Build image -docker build -t ackify:dev . +docker build -t ackify-ce:dev . # Run with local database -docker run -p 8080:8080 --env-file .env ackify:dev +docker run -p 8080:8080 --env-file .env ackify-ce:dev ``` --- @@ -315,8 +315,8 @@ docker run -p 8080:8080 --env-file .env ackify:dev ## 🀝 Support ### Help & Documentation -- πŸ› **Issues**: [GitHub Issues](https://github.com/btouchard/ackify/issues) -- πŸ’¬ **Discussions**: [GitHub Discussions](https://github.com/btouchard/ackify/discussions) +- πŸ› **Issues**: [GitHub Issues](https://github.com/btouchard/ackify-ce/issues) +- πŸ’¬ **Discussions**: [GitHub Discussions](https://github.com/btouchard/ackify-ce/discussions) ### SSPL License Free usage for internal projects. Restriction for competing commercial services. diff --git a/README_FR.md b/README_FR.md index 1099a44..99fbb31 100644 --- a/README_FR.md +++ b/README_FR.md @@ -4,7 +4,7 @@ Service sΓ©curisΓ© de validation de lecture avec traΓ§abilitΓ© cryptographique et preuves incontestables. -[![Build](https://img.shields.io/badge/build-passing-brightgreen.svg)](https://github.com/btouchard/ackify) +[![Build](https://img.shields.io/badge/build-passing-brightgreen.svg)](https://github.com/btouchard/ackify-ce) [![Security](https://img.shields.io/badge/crypto-Ed25519-blue.svg)](https://en.wikipedia.org/wiki/EdDSA) [![Go](https://img.shields.io/badge/go-1.24.5-blue.svg)](https://golang.org/) [![License](https://img.shields.io/badge/license-SSPL-blue.svg)](LICENSE) @@ -229,7 +229,7 @@ CREATE TABLE signatures ( version: '3.8' services: ackapp: - image: btouchard/ackify:latest + image: btouchard/ackify-ce:latest environment: APP_BASE_URL: https://ackify.company.com DB_DSN: postgres://user:pass@postgres:5432/ackdb?sslmode=require @@ -299,7 +299,7 @@ DB_DSN="postgres://user:pass@postgres:5432/ackdb?sslmode=require" go mod tidy # Build -go build ./cmd/ackify +go build ./cmd/community # Linting go fmt ./... @@ -312,7 +312,7 @@ go test -v ./... ### Docker development ```bash # Build image -docker build -t ackify:dev . +docker build -t ackify-ce:dev . # Run avec base locale docker run -p 8080:8080 --env-file .env ackify:dev @@ -323,8 +323,8 @@ docker run -p 8080:8080 --env-file .env ackify:dev ## 🀝 Support ### Aide & Documentation -- πŸ› **Issues** : [GitHub Issues](https://github.com/btouchard/ackify/issues) -- πŸ’¬ **Discussions** : [GitHub Discussions](https://github.com/btouchard/ackify/discussions) +- πŸ› **Issues** : [GitHub Issues](https://github.com/btouchard/ackify-ce/issues) +- πŸ’¬ **Discussions** : [GitHub Discussions](https://github.com/btouchard/ackify-ce/discussions) ### Licence SSPL Usage libre pour projets internes. Restriction pour services commerciaux concurrents. diff --git a/cmd/community/main.go b/cmd/community/main.go new file mode 100644 index 0000000..c3372e1 --- /dev/null +++ b/cmd/community/main.go @@ -0,0 +1,50 @@ +package main + +import ( + "context" + "errors" + "log" + "net/http" + "os" + "os/signal" + "syscall" + "time" + + "github.com/btouchard/ackify-ce/pkg/web" +) + +func main() { + ctx := context.Background() + + // Create server instance with multitenant disabled (Community Edition) + server, err := web.NewServer(ctx, false) + if err != nil { + log.Fatalf("Failed to create server: %v", err) + } + + // Start server in a goroutine + go func() { + log.Printf("Community Edition server starting on %s", server.GetAddr()) + if err := server.Start(); err != nil && !errors.Is(err, http.ErrServerClosed) { + log.Fatalf("Server error: %v", err) + } + }() + + // Wait for interrupt signal for graceful shutdown + quit := make(chan os.Signal, 1) + signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM) + <-quit + + log.Println("Shutting down Community Edition server...") + + // Graceful shutdown with timeout + shutdownCtx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + defer cancel() + + if err := server.Shutdown(shutdownCtx); err != nil { + log.Printf("Server forced to shutdown: %v", err) + } + + log.Println("Community Edition server exited") +} + diff --git a/docker-compose.yml b/docker-compose.yml index 534145b..4db3857 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,9 +1,9 @@ -name: ackify +name: ackify-ce services: - ackify: - image: btouchard/ackify - container_name: ackify + ackify-ce: + image: btouchard/ackify-ce + container_name: ackify-ce restart: unless-stopped environment: APP_BASE_URL: "https://${APP_DNS}" @@ -13,20 +13,20 @@ services: OAUTH_CLIENT_SECRET: "${OAUTH_CLIENT_SECRET}" OAUTH_ALLOWED_DOMAIN: "${OAUTH_ALLOWED_DOMAIN}" OAUTH_COOKIE_SECRET: "${OAUTH_COOKIE_SECRET}" - DB_DSN: "postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@ackify_db:5432/${POSTGRES_DB}?sslmode=disable" + DB_DSN: "postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@ackify-db:5432/${POSTGRES_DB}?sslmode=disable" ED25519_PRIVATE_KEY_B64: "${ED25519_PRIVATE_KEY_B64}" LISTEN_ADDR: ":8080" depends_on: - ackify_db: + ackify-db: condition: service_healthy networks: - internal ports: - "8080:8080" - ackify_db: + ackify-db: image: postgres:16-alpine - container_name: ackify_db + container_name: ackify-db restart: unless-stopped environment: POSTGRES_USER: ${POSTGRES_USER} diff --git a/go.mod b/go.mod index 2c9167c..5cc9a15 100644 --- a/go.mod +++ b/go.mod @@ -1,4 +1,4 @@ -module ackify +module github.com/btouchard/ackify-ce go 1.24.5 diff --git a/install/.env.example b/install/.env.example index 36fdd5e..649eb57 100644 --- a/install/.env.example +++ b/install/.env.example @@ -1,5 +1,5 @@ # Application Configuration -APP_NAME=ackify +APP_NAME=ackify-ce APP_DNS=your-domain.com APP_BASE_URL=https://your-domain.com APP_ORGANISATION="Your Organization Name" diff --git a/install/docker-compose.yml b/install/docker-compose.yml index dc9f340..d5352e9 100644 --- a/install/docker-compose.yml +++ b/install/docker-compose.yml @@ -1,9 +1,9 @@ -name: ackify +name: ackify-ce services: - ackify: - image: btouchard/ackify:latest - container_name: ackify + ackify-ce: + image: btouchard/ackify-ce:latest + container_name: ackify-ce restart: unless-stopped environment: APP_BASE_URL: "https://${APP_DNS}" diff --git a/install/install.sh b/install/install.sh index fed3815..87c48c9 100755 --- a/install/install.sh +++ b/install/install.sh @@ -1,15 +1,15 @@ #!/bin/bash -# Ackify Installation Script +# Ackify Community Edition (CE) Installation Script # Quick setup for Docker deployment set -e -echo "πŸ” Ackify Installation" +echo "πŸ” Ackify Community Edition (CE) Installation" echo "=========================" # Create installation directory -INSTALL_DIR="ackify-install" +INSTALL_DIR="ackify-ce" if [ -d "$INSTALL_DIR" ]; then echo "❌ Directory $INSTALL_DIR already exists. Please remove it first." exit 1 @@ -21,10 +21,10 @@ cd "$INSTALL_DIR" echo "πŸ“¦ Downloading configuration files..." # Download docker-compose.yml -curl -fsSL https://raw.githubusercontent.com/btouchard/ackify/main/install/docker-compose.yml -o docker-compose.yml +curl -fsSL https://raw.githubusercontent.com/btouchard/ackify-ce/main/install/docker-compose.yml -o docker-compose.yml # Download .env.example -curl -fsSL https://raw.githubusercontent.com/btouchard/ackify/main/install/.env.example -o .env.example +curl -fsSL https://raw.githubusercontent.com/btouchard/ackify-ce/main/install/.env.example -o .env.example echo "πŸ”§ Setting up environment..." diff --git a/internal/application/services/signature.go b/internal/application/services/signature.go index 02749b9..bc2fa6b 100644 --- a/internal/application/services/signature.go +++ b/internal/application/services/signature.go @@ -6,9 +6,9 @@ import ( "fmt" "time" - "ackify/internal/domain/models" - "ackify/pkg/crypto" - "ackify/pkg/logger" + "github.com/btouchard/ackify-ce/internal/domain/models" + "github.com/btouchard/ackify-ce/pkg/crypto" + "github.com/btouchard/ackify-ce/pkg/logger" ) type repository interface { diff --git a/internal/application/services/signature_test.go b/internal/application/services/signature_test.go index fdcf080..9458579 100644 --- a/internal/application/services/signature_test.go +++ b/internal/application/services/signature_test.go @@ -6,7 +6,7 @@ import ( "testing" "time" - "ackify/internal/domain/models" + "github.com/btouchard/ackify-ce/internal/domain/models" ) // Mock repository implementation diff --git a/internal/domain/models/signature.go b/internal/domain/models/signature.go index cf836c1..3b0d108 100644 --- a/internal/domain/models/signature.go +++ b/internal/domain/models/signature.go @@ -6,7 +6,7 @@ import ( "fmt" "time" - "ackify/pkg/services" + "github.com/btouchard/ackify-ce/pkg/services" ) // Signature represents a document signature record diff --git a/internal/infrastructure/auth/oauth.go b/internal/infrastructure/auth/oauth.go index 71683fe..17b3728 100644 --- a/internal/infrastructure/auth/oauth.go +++ b/internal/infrastructure/auth/oauth.go @@ -13,8 +13,8 @@ import ( "github.com/gorilla/sessions" "golang.org/x/oauth2" - "ackify/internal/domain/models" - "ackify/pkg/logger" + "github.com/btouchard/ackify-ce/internal/domain/models" + "github.com/btouchard/ackify-ce/pkg/logger" ) const sessionName = "ackapp_session" diff --git a/internal/infrastructure/auth/oauth_test.go b/internal/infrastructure/auth/oauth_test.go index 857145e..654c8e5 100644 --- a/internal/infrastructure/auth/oauth_test.go +++ b/internal/infrastructure/auth/oauth_test.go @@ -11,7 +11,7 @@ import ( "strings" "testing" - "ackify/internal/domain/models" + "github.com/btouchard/ackify-ce/internal/domain/models" ) func TestNewOAuthService(t *testing.T) { diff --git a/internal/infrastructure/database/repository.go b/internal/infrastructure/database/repository.go index e2318ba..2e87fa4 100644 --- a/internal/infrastructure/database/repository.go +++ b/internal/infrastructure/database/repository.go @@ -6,7 +6,7 @@ import ( "errors" "fmt" - "ackify/internal/domain/models" + "github.com/btouchard/ackify-ce/internal/domain/models" ) type SignatureRepository struct { diff --git a/internal/infrastructure/database/repository_concurrency_test.go b/internal/infrastructure/database/repository_concurrency_test.go index bec3148..9308a81 100644 --- a/internal/infrastructure/database/repository_concurrency_test.go +++ b/internal/infrastructure/database/repository_concurrency_test.go @@ -10,7 +10,7 @@ import ( "testing" "time" - "ackify/internal/domain/models" + "github.com/btouchard/ackify-ce/internal/domain/models" ) func TestRepository_Concurrency_Integration(t *testing.T) { diff --git a/internal/infrastructure/database/repository_constraints_test.go b/internal/infrastructure/database/repository_constraints_test.go index 8052b23..7a66eb5 100644 --- a/internal/infrastructure/database/repository_constraints_test.go +++ b/internal/infrastructure/database/repository_constraints_test.go @@ -10,7 +10,7 @@ import ( "testing" "time" - "ackify/internal/domain/models" + "github.com/btouchard/ackify-ce/internal/domain/models" ) func TestRepository_DatabaseConstraints_Integration(t *testing.T) { diff --git a/internal/infrastructure/database/repository_integration_test.go b/internal/infrastructure/database/repository_integration_test.go index 255d308..ed80bb7 100644 --- a/internal/infrastructure/database/repository_integration_test.go +++ b/internal/infrastructure/database/repository_integration_test.go @@ -8,7 +8,7 @@ import ( "testing" "time" - "ackify/internal/domain/models" + "github.com/btouchard/ackify-ce/internal/domain/models" ) func TestRepository_Create_Integration(t *testing.T) { diff --git a/internal/infrastructure/database/testutils.go b/internal/infrastructure/database/testutils.go index 5f94799..c1606bd 100644 --- a/internal/infrastructure/database/testutils.go +++ b/internal/infrastructure/database/testutils.go @@ -9,7 +9,7 @@ import ( "testing" "time" - "ackify/internal/domain/models" + "github.com/btouchard/ackify-ce/internal/domain/models" _ "github.com/lib/pq" ) diff --git a/internal/presentation/handlers/badge.go b/internal/presentation/handlers/badge.go index a850005..d51c34c 100644 --- a/internal/presentation/handlers/badge.go +++ b/internal/presentation/handlers/badge.go @@ -11,7 +11,7 @@ import ( "github.com/julienschmidt/httprouter" - "ackify/internal/domain/models" + "github.com/btouchard/ackify-ce/internal/domain/models" ) type checkService interface { diff --git a/internal/presentation/handlers/handlers_test.go b/internal/presentation/handlers/handlers_test.go index c565e25..2628de7 100644 --- a/internal/presentation/handlers/handlers_test.go +++ b/internal/presentation/handlers/handlers_test.go @@ -11,7 +11,7 @@ import ( "testing" "time" - "ackify/internal/domain/models" + "github.com/btouchard/ackify-ce/internal/domain/models" ) // Fake implementations for testing diff --git a/internal/presentation/handlers/handlers_utils_test.go b/internal/presentation/handlers/handlers_utils_test.go index 4281b37..200cac6 100644 --- a/internal/presentation/handlers/handlers_utils_test.go +++ b/internal/presentation/handlers/handlers_utils_test.go @@ -11,7 +11,7 @@ import ( "github.com/julienschmidt/httprouter" - "ackify/internal/domain/models" + "github.com/btouchard/ackify-ce/internal/domain/models" ) // Badge Handler Tests diff --git a/internal/presentation/handlers/interfaces.go b/internal/presentation/handlers/interfaces.go index aefed5d..3ad18ed 100644 --- a/internal/presentation/handlers/interfaces.go +++ b/internal/presentation/handlers/interfaces.go @@ -1,7 +1,7 @@ package handlers import ( - "ackify/internal/domain/models" + "github.com/btouchard/ackify-ce/internal/domain/models" "context" "net/http" ) diff --git a/internal/presentation/handlers/middleware.go b/internal/presentation/handlers/middleware.go index 9e47459..f2c9476 100644 --- a/internal/presentation/handlers/middleware.go +++ b/internal/presentation/handlers/middleware.go @@ -6,7 +6,7 @@ import ( "github.com/julienschmidt/httprouter" - "ackify/internal/domain/models" + "github.com/btouchard/ackify-ce/internal/domain/models" ) // AuthMiddleware provides authentication middleware diff --git a/internal/presentation/handlers/oembed.go b/internal/presentation/handlers/oembed.go index cbf7b0f..92278b4 100644 --- a/internal/presentation/handlers/oembed.go +++ b/internal/presentation/handlers/oembed.go @@ -11,7 +11,7 @@ import ( "github.com/julienschmidt/httprouter" - "ackify/internal/domain/models" + "github.com/btouchard/ackify-ce/internal/domain/models" ) // OEmbedHandler handles oEmbed requests diff --git a/internal/presentation/handlers/signature.go b/internal/presentation/handlers/signature.go index 407f4d5..3f96634 100644 --- a/internal/presentation/handlers/signature.go +++ b/internal/presentation/handlers/signature.go @@ -11,8 +11,8 @@ import ( "github.com/julienschmidt/httprouter" - "ackify/internal/domain/models" - "ackify/pkg/services" + "github.com/btouchard/ackify-ce/internal/domain/models" + "github.com/btouchard/ackify-ce/pkg/services" ) type signatureService interface { diff --git a/pkg/crypto/crypto_test.go b/pkg/crypto/crypto_test.go index 4851726..62edb2f 100644 --- a/pkg/crypto/crypto_test.go +++ b/pkg/crypto/crypto_test.go @@ -9,7 +9,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "ackify/internal/domain/models" + "github.com/btouchard/ackify-ce/internal/domain/models" ) // TestCryptoIntegration tests the integrations between signature generation and nonce generation diff --git a/pkg/crypto/ed25519.go b/pkg/crypto/ed25519.go index 7e2f707..5b3192b 100644 --- a/pkg/crypto/ed25519.go +++ b/pkg/crypto/ed25519.go @@ -10,7 +10,7 @@ import ( "strings" "time" - "ackify/internal/domain/models" + "github.com/btouchard/ackify-ce/internal/domain/models" ) // Ed25519Signer handles Ed25519 cryptographic operations diff --git a/pkg/crypto/ed25519_test.go b/pkg/crypto/ed25519_test.go index 02425dd..832d8e6 100644 --- a/pkg/crypto/ed25519_test.go +++ b/pkg/crypto/ed25519_test.go @@ -11,7 +11,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "ackify/internal/domain/models" + "github.com/btouchard/ackify-ce/internal/domain/models" ) func TestEd25519Signer_NewEd25519Signer(t *testing.T) { diff --git a/pkg/crypto/fixtures_test.go b/pkg/crypto/fixtures_test.go index 3fc00e6..5407666 100644 --- a/pkg/crypto/fixtures_test.go +++ b/pkg/crypto/fixtures_test.go @@ -1,6 +1,6 @@ package crypto -import "ackify/internal/domain/models" +import "github.com/btouchard/ackify-ce/internal/domain/models" // Internal test fixtures to avoid external dependencies diff --git a/cmd/ackify/main.go b/pkg/web/server.go similarity index 67% rename from cmd/ackify/main.go rename to pkg/web/server.go index 45e2bd6..10266e0 100644 --- a/cmd/ackify/main.go +++ b/pkg/web/server.go @@ -1,40 +1,37 @@ -package main +package web import ( "context" "database/sql" - "errors" "fmt" "html/template" - "log" "net/http" - "os" - "os/signal" - "syscall" - "time" "github.com/julienschmidt/httprouter" - "ackify/internal/application/services" - "ackify/internal/infrastructure/auth" - "ackify/internal/infrastructure/config" - "ackify/internal/infrastructure/database" - "ackify/internal/presentation/handlers" - "ackify/internal/presentation/templates" - "ackify/pkg/crypto" + "github.com/btouchard/ackify-ce/internal/application/services" + "github.com/btouchard/ackify-ce/internal/infrastructure/auth" + "github.com/btouchard/ackify-ce/internal/infrastructure/config" + "github.com/btouchard/ackify-ce/internal/infrastructure/database" + "github.com/btouchard/ackify-ce/internal/presentation/handlers" + "github.com/btouchard/ackify-ce/internal/presentation/templates" + "github.com/btouchard/ackify-ce/pkg/crypto" ) -func main() { - ctx := context.Background() +// Server represents the Ackify CE web server +type Server struct { + httpServer *http.Server + db *sql.DB +} - // Initialize dependencies +// NewServer creates a new Ackify CE server instance +// multitenant parameter enables enterprise features when true +func NewServer(ctx context.Context, multitenant bool) (*Server, error) { + // Initialize infrastructure cfg, db, tmpl, signer, err := initInfrastructure(ctx) if err != nil { - log.Fatalf("Failed to initialize infrastructure: %v", err) + return nil, fmt.Errorf("failed to initialize infrastructure: %w", err) } - defer func(db *sql.DB) { - _ = db.Close() - }(db) // Initialize services authService := auth.NewOAuthService(auth.Config{ @@ -63,38 +60,39 @@ func main() { healthHandler := handlers.NewHealthHandler() // Setup HTTP router - router := setupRouter(authHandlers, authMiddleware, signatureHandlers, badgeHandler, oembedHandler, healthHandler) + router := setupRouter(authHandlers, authMiddleware, signatureHandlers, badgeHandler, oembedHandler, healthHandler, multitenant) // Create HTTP server - server := &http.Server{ + httpServer := &http.Server{ Addr: cfg.Server.ListenAddr, Handler: handlers.SecureHeaders(router), } - // Start server in a goroutine - go func() { - log.Printf("Server starting on %s", cfg.Server.ListenAddr) - if err := server.ListenAndServe(); err != nil && !errors.Is(err, http.ErrServerClosed) { - log.Fatalf("Server error: %v", err) - } - }() + return &Server{ + httpServer: httpServer, + db: db, + }, nil +} - // Wait for interrupt signal for graceful shutdown - quit := make(chan os.Signal, 1) - signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM) - <-quit +// Start starts the HTTP server +func (s *Server) Start() error { + return s.httpServer.ListenAndServe() +} - log.Println("Shutting down server...") - - // Graceful shutdown with timeout - shutdownCtx, cancel := context.WithTimeout(context.Background(), 10*time.Second) - defer cancel() - - if err := server.Shutdown(shutdownCtx); err != nil { - log.Printf("Server forced to shutdown: %v", err) +// Shutdown gracefully shuts down the server +func (s *Server) Shutdown(ctx context.Context) error { + if err := s.httpServer.Shutdown(ctx); err != nil { + return err } + if s.db != nil { + return s.db.Close() + } + return nil +} - log.Println("Server exited") +// GetAddr returns the server address +func (s *Server) GetAddr() string { + return s.httpServer.Addr } // initInfrastructure initializes the basic infrastructure components @@ -136,6 +134,7 @@ func setupRouter( badgeHandler *handlers.BadgeHandler, oembedHandler *handlers.OEmbedHandler, healthHandler *handlers.HealthHandler, + multitenant bool, ) *httprouter.Router { router := httprouter.New() @@ -155,5 +154,12 @@ func setupRouter( router.POST("/sign", authMiddleware.RequireAuth(signatureHandlers.HandleSignPOST)) router.GET("/signatures", authMiddleware.RequireAuth(signatureHandlers.HandleUserSignatures)) + // Enterprise routes (only enabled if multitenant is true) + if multitenant { + // Add placeholder routes for enterprise features + // These will be overridden/extended by the EE edition + router.GET("/healthz", healthHandler.HandleHealth) // Alternative health endpoint for EE + } + return router } diff --git a/web/templates/index.html.tpl b/web/templates/index.html.tpl index f1a26fa..b217402 100644 --- a/web/templates/index.html.tpl +++ b/web/templates/index.html.tpl @@ -10,7 +10,7 @@
-

Ackify

+

Ackify CE

La solution professionnelle pour valider la lecture de vos documents