Skip to content

Latest commit

Β 

History

History
513 lines (367 loc) Β· 8.95 KB

File metadata and controls

513 lines (367 loc) Β· 8.95 KB

Development

Guide for contributing and developing on Ackify.

Development Setup

Prerequisites

  • Go 1.24.5+
  • Node.js 22+ and npm
  • PostgreSQL 16+
  • Docker & Docker Compose
  • Git

Clone & Setup

# Clone
git clone https://github.com/kolapsis/ackify.git
cd ackify-ce

# Copy .env
cp .env.example .env

# Edit .env with your OAuth2 credentials
nano .env

Backend Development

Build

cd backend
go mod download
go build ./cmd/community

Run

# Start PostgreSQL with Docker
docker compose up -d ackify-db

# Apply migrations
go run ./cmd/migrate up

# Launch app
./community

API accessible at http://localhost:8080.

Tests

# Unit tests
go test -v -short ./...

# Tests with coverage
go test -coverprofile=coverage.out ./internal/... ./pkg/...

# View coverage
go tool cover -html=coverage.out

# Integration tests (PostgreSQL required)
docker compose -f ../compose.test.yml up -d
INTEGRATION_TESTS=1 go test -tags=integration -v ./internal/infrastructure/database/
docker compose -f ../compose.test.yml down

Linting

# Format
go fmt ./...

# Vet
go vet ./...

# Staticcheck (optional)
go install honnef.co/go/tools/cmd/staticcheck@latest
staticcheck ./...

Frontend Development

Setup

cd webapp
npm install

Dev Server

npm run dev

Frontend accessible at http://localhost:5173 with Hot Module Replacement.

Production Build

npm run build
# Output: webapp/dist/

Type Checking

npm run type-check

i18n Validation

npm run lint:i18n

Verifies all translations are complete.

Docker Development

Local Build

# Build complete image (frontend + backend)
docker compose -f compose.local.yml up -d --build

# Logs
docker compose -f compose.local.yml logs -f ackify-ce

# Rebuild after changes
docker compose -f compose.local.yml up -d --force-recreate ackify-ce --build

Debug

# Shell in container
docker compose exec ackify-ce sh

# PostgreSQL shell
docker compose exec ackify-db psql -U ackifyr -d ackify

Code Structure

Backend

backend/
β”œβ”€β”€ cmd/
β”‚   β”œβ”€β”€ community/        # main.go + dependency injection
β”‚   └── migrate/          # Migration tool
β”œβ”€β”€ internal/
β”‚   β”œβ”€β”€ domain/models/    # Entities (User, Signature, Document)
β”‚   β”œβ”€β”€ application/services/  # Business logic
β”‚   β”œβ”€β”€ infrastructure/
β”‚   β”‚   β”œβ”€β”€ auth/         # OAuth2
β”‚   β”‚   β”œβ”€β”€ database/     # Repositories
β”‚   β”‚   β”œβ”€β”€ email/        # SMTP
β”‚   β”‚   └── config/       # Config
β”‚   └── presentation/api/ # HTTP handlers
└── pkg/                  # Utilities

Frontend

webapp/src/
β”œβ”€β”€ components/           # Vue components
β”œβ”€β”€ pages/               # Pages (router)
β”œβ”€β”€ services/            # API client
β”œβ”€β”€ stores/              # Pinia stores
β”œβ”€β”€ router/              # Vue Router
└── locales/             # Translations

Code Conventions

Go

Naming:

  • Packages: lowercase, singular (user, signature)
  • Interfaces: suffix er or descriptive (SignatureRepository, EmailSender)
  • Constructors: New...() or ...From...()

Example:

// Service
type SignatureService struct {
    repo SignatureRepository
    crypto CryptoService
}

func NewSignatureService(repo SignatureRepository, crypto CryptoService) *SignatureService {
    return &SignatureService{repo: repo, crypto: crypto}
}

// Method
func (s *SignatureService) CreateSignature(ctx context.Context, docID, userSub string) (*models.Signature, error) {
    // ...
}

Errors:

// Wrapping
return nil, fmt.Errorf("failed to create signature: %w", err)

// Custom errors
var ErrAlreadySigned = errors.New("user has already signed this document")

TypeScript

Naming:

  • Components: PascalCase (DocumentCard.vue)
  • Composables: camelCase with use prefix (useAuth.ts)
  • Stores: camelCase with Store suffix (userStore.ts)

Example:

// Composable
export function useAuth() {
  const user = ref<User | null>(null)

  async function login() {
    // ...
  }

  return { user, login }
}

// Store
export const useUserStore = defineStore('user', () => {
  const currentUser = ref<User | null>(null)

  async function fetchMe() {
    const { data } = await api.get('/users/me')
    currentUser.value = data
  }

  return { currentUser, fetchMe }
})

Adding a Feature

1. Planning

  • Define required API endpoints
  • SQL schema if needed
  • User interface

2. Backend

# 1. Create migration if needed
touch backend/migrations/XXXX_my_feature.up.sql
touch backend/migrations/XXXX_my_feature.down.sql

# 2. Create model
# backend/internal/domain/models/my_model.go

# 3. Create repository interface
# backend/internal/application/services/my_service.go

# 4. Implement repository
# backend/internal/infrastructure/database/my_repository.go

# 5. Create API handler
# backend/internal/presentation/api/myfeature/handler.go

# 6. Register routes
# backend/internal/presentation/api/router.go

3. Frontend

# 1. Create API service
# webapp/src/services/myFeatureService.ts

# 2. Create Pinia store
# webapp/src/stores/myFeatureStore.ts

# 3. Create components
# webapp/src/components/MyFeature.vue

# 4. Add translations
# webapp/src/locales/{fr,en,es,de,it}.json

# 5. Add routes if needed
# webapp/src/router/index.ts

4. Tests

# Backend
# backend/internal/presentation/api/myfeature/handler_test.go

# Test
go test -v ./internal/presentation/api/myfeature/

5. Documentation

Update:

  • /api/openapi.yaml - OpenAPI specification
  • /docs/api.md - API documentation
  • /docs/features/my-feature.md - User guide

Debugging

Backend

// Structured logs
logger.Info("signature created",
    "doc_id", docID,
    "user_sub", userSub,
    "signature_id", sig.ID,
)

// Debug via Delve (optional)
dlv debug ./cmd/community

Frontend

// Vue DevTools (Chrome/Firefox extension)
// Inspect: Components, Pinia stores, Router

// Console debug
console.log('[DEBUG] User:', user.value)

// Breakpoints via browser
debugger

SQL Migrations

Create Migration

-- XXXX_add_field.up.sql
ALTER TABLE signatures ADD COLUMN new_field TEXT;

-- XXXX_add_field.down.sql
ALTER TABLE signatures DROP COLUMN new_field;

Apply

go run ./cmd/migrate up

Rollback

go run ./cmd/migrate down

Integration Tests

Setup PostgreSQL Test

docker compose -f compose.test.yml up -d

Run Tests

INTEGRATION_TESTS=1 go test -tags=integration -v ./internal/infrastructure/database/

Cleanup

docker compose -f compose.test.yml down -v

CI/CD

GitHub Actions

Project uses .github/workflows/ci.yml:

Jobs:

  1. Lint - go fmt, go vet, eslint
  2. Test Backend - Unit + integration tests
  3. Test Frontend - Type checking + i18n validation
  4. Coverage - Upload to Codecov
  5. Build - Verify Docker image builds

Pre-commit Hooks (optional)

# Install pre-commit
pip install pre-commit

# Setup hooks
pre-commit install

# Run manually
pre-commit run --all-files

Contribution

Git Workflow

# 1. Create branch
git checkout -b feature/my-feature

# 2. Develop + commit
git add .
git commit -m "feat: add my feature"

# 3. Push
git push origin feature/my-feature

# 4. Create Pull Request on GitHub

Commit Messages

Format: type: description

Types:

  • feat - New feature
  • fix - Bug fix
  • docs - Documentation
  • refactor - Refactoring
  • test - Tests
  • chore - Maintenance

Examples:

feat: add checksum verification feature
fix: resolve OAuth callback redirect loop
docs: update API documentation for signatures
refactor: simplify signature service logic
test: add integration tests for expected signers

Code Review

Checklist:

  • βœ… Tests pass (CI green)
  • βœ… Code formatted (go fmt, eslint)
  • βœ… No committed secrets
  • βœ… Documentation updated
  • βœ… Complete translations (i18n)

Troubleshooting

Backend won't start

# Check PostgreSQL
docker compose ps ackify-db
docker compose logs ackify-db

# Check environment variables
cat .env

# Detailed logs
ACKIFY_LOG_LEVEL=debug ./community

Frontend build fails

# Clean and reinstall
rm -rf node_modules package-lock.json
npm install

# Check Node version
node --version  # Should be 22+

Tests fail

# Backend - check PostgreSQL test
docker compose -f compose.test.yml ps

# Frontend - check types
npm run type-check

Resources

Support