Skip to content
Merged
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
7 changes: 6 additions & 1 deletion .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,9 @@ GOOGLE_REDIRECT_URL=http://localhost:8080/api/v1/portal/auth/google/callback

OTP_EXPIRY=1

ELASTICSEARCH_URL=http://localhost:9200
ELASTICSEARCH_URL=http://localhost:9200

REQUEST_TIMEOUT=30s
ALLOWED_ORIGINS=http://localhost:3000,http://localhost:5173
RATE_LIMIT_REQUESTS=100
RATE_LIMIT_WINDOW=1m
113 changes: 113 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
name: CI

on:
push:
branches: [master, develop]
pull_request:
branches: [master, develop]

jobs:

lint:
name: Lint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- uses: actions/setup-go@v5
with:
go-version: '1.23'
cache: true

- name: golangci-lint
uses: golangci/golangci-lint-action@v6
with:
version: latest
args: --timeout=5m

test-unit:
name: Unit Tests
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- uses: actions/setup-go@v5
with:
go-version: '1.23'
cache: true

- name: Download modules
run: go mod download

- name: Run unit tests
run: go test ./internal/... -v -race -count=1 -coverprofile=coverage.out

- name: Upload coverage
uses: actions/upload-artifact@v4
with:
name: coverage
path: coverage.out

test-integration:
name: Integration Tests
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- uses: actions/setup-go@v5
with:
go-version: '1.23'
cache: true

- name: Download modules
run: go mod download

- name: Run integration tests
run: go test ./tests/integration/... -v -race -count=1 -timeout 120s
env:
TESTCONTAINERS_RYUK_DISABLED: true

build:
name: Build
runs-on: ubuntu-latest
needs: [lint, test-unit, test-integration]
steps:
- uses: actions/checkout@v4

- uses: actions/setup-go@v5
with:
go-version: '1.23'
cache: true

- name: Build all binaries
run: make build

- name: Upload binaries
uses: actions/upload-artifact@v4
with:
name: binaries
path: bin/

docker:
name: Docker Build
runs-on: ubuntu-latest
needs: build
if: github.ref == 'refs/heads/master'
steps:
- uses: actions/checkout@v4

- name: Build Docker image
run: docker build -t librecore:${{ github.sha }} .

- name: Smoke test image
run: |
docker run --rm -d \
-e APP_ENV=production \
-e DATABASE_URL=postgres://x:x@localhost/x \
-e REDIS_URL=redis://localhost:6379 \
-e JWT_SECRET=ci-test-secret \
-p 8080:8080 \
--name librecore_smoke \
librecore:${{ github.sha }} || true
sleep 3
docker stop librecore_smoke || true
45 changes: 45 additions & 0 deletions .golangci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
run:
timeout: 5m
go: '1.23'

linters:
enable:
- errcheck
- gosimple
- govet
- ineffassign
- staticcheck
- unused
- gofmt
- misspell
- revive
- exhaustive
- godot
- noctx
- bodyclose

linters-settings:
godot:
all: false
exclude:
- '^ *@'
revive:
rules:
- name: exported
severity: warning
- name: unused-parameter
severity: warning

exhaustive:
default-signifies-exhaustive: true

issues:
exclude-rules:
- path: _test\.go
linters: [errcheck, gosimple]

- path: docs/
linters: [all]

max-issues-per-linter: 0
max-same-issues: 0
106 changes: 106 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
# Contributing to LibreCore

Thank you for considering contributing. This document covers everything
you need to get started.

---

## Development Setup

### Prerequisites
- Go 1.23+
- Docker + Docker Compose
- `golangci-lint` — `go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest`
- `swag` — `go install github.com/swaggo/swag/cmd/swag@latest`

### First-time setup
```bash
git clone https://github.com/mohammad-farrokhnia/library.git
cd library
cp .env.example .env
make docker-up
make migrate
make seed EMAIL=admin@library.com PASSWORD=secret MOBILE=09120000000 NATIONAL_CODE=1234567890
make run-api
```

---

## Git Flow

We follow trunk-based development with short-lived feature branches.

```
main ← production, protected, requires PR + review
develop ← integration branch, PRs target this
feature/* ← one branch per feature
hotfix/* ← emergency production fixes
release/* ← release stabilization
```

---

## Branch Naming

| Type | Pattern | Example |
|---|---|---|
| Feature | `feature/short-description` | `feature/book-recommendations` |
| Bug fix | `fix/what-was-broken` | `fix/borrow-transaction-race` |
| Hotfix | `hotfix/critical-issue` | `hotfix/jwt-validation` |
| Chore | `chore/what-changed` | `chore/update-go-1.24` |

---

## Commit Convention

We use [Conventional Commits](https://www.conventionalcommits.org/):

```
type(scope): short description

feat(books): add copy management endpoints
fix(auth): prevent session reuse after logout
docs(readme): update installation steps
test(borrow): add limit enforcement integration test
chore(deps): update golang-jwt to v5.2.1
refactor(cache): extract GetOrSet into generic helper
```

Types: `feat` `fix` `docs` `test` `chore` `refactor` `perf` `ci`

---

## Pull Request Process

1. Fork the repo and create your branch from `develop`
2. Write tests for any new behaviour
3. Ensure `make lint` and `make test` pass
4. Update Swagger docs if you changed any handler: `make swagger`
5. Open a PR targeting `develop` with a clear description

---

## Code Standards

- All repository methods must accept `context.Context` as the first parameter
- All errors must be `AppError` from `pkg/errors` — never raw `errors.New`
- Business rules belong in `service/`, never in `handler/` or `repository/`
- New i18n message codes must be added to all locale files (`en.go`, `fa.go`)
- Every new endpoint needs a Swagger annotation

---

## Running Tests

```bash
make test-unit # fast, no Docker
make test-integration # requires Docker
make test-coverage # generates coverage.html
```

---

## Project Structure

See the [architecture document](docs/architecture.md) for the full layered
architecture diagram and design decisions.
Loading
Loading