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
34 changes: 25 additions & 9 deletions .github/workflows/backend-deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,24 +19,40 @@ jobs:

steps:
- name: Checkout
uses: actions/checkout@v4

- name: Install kubectl
uses: azure/setup-kubectl@v4
with:
version: 'v1.26.3'
id: install
uses: actions/checkout@v7.0.1

- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v4
uses: aws-actions/configure-aws-credentials@v6.3.0
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: eu-central-1

- name: Select kubectl version for EKS
id: kubectl-version
shell: bash
run: |
cluster_version=$(aws eks describe-cluster --name talebound --region eu-central-1 --query 'cluster.version' --output text)
if [[ ! "$cluster_version" =~ ^[0-9]+\.[0-9]+$ ]]; then
echo 'Unable to determine the EKS Kubernetes version' >&2
exit 1
fi
kubectl_version=$(curl --fail --silent --show-error --location --retry 3 --max-time 30 "https://dl.k8s.io/release/stable-${cluster_version}.txt")
if [[ ! "$kubectl_version" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ || "${kubectl_version%.*}" != "v${cluster_version}" ]]; then
echo 'Unable to resolve a stable kubectl patch matching EKS' >&2
exit 1
fi
echo "version=$kubectl_version" >> "$GITHUB_OUTPUT"
echo "Using kubectl $kubectl_version for EKS $cluster_version"

- name: Install kubectl
uses: azure/setup-kubectl@v5.2.0
with:
version: ${{ steps.kubectl-version.outputs.version }}

- name: Login to Amazon ECR
id: login-ecr
uses: aws-actions/amazon-ecr-login@v2
uses: aws-actions/amazon-ecr-login@v2.1.7

- name: Load secrets and save to app.env
run: aws secretsmanager get-secret-value --secret-id talebound_secrets --region eu-central-1 --query SecretString --output text | jq 'to_entries|map("\(.key)=\(.value)")|.[]' -r > app.env
Expand Down
12 changes: 10 additions & 2 deletions .github/workflows/backend-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,10 @@ jobs:

steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@v7.0.1

- name: Set up Go
uses: actions/setup-go@v5
uses: actions/setup-go@v7.0.0
with:
go-version-file: backend/go.mod
cache-dependency-path: backend/go.sum
Expand All @@ -57,3 +57,11 @@ jobs:

- name: Test
run: make test

- name: Verify dependencies
run: |
go mod verify
go mod tidy -diff

- name: Check vulnerabilities
run: go run golang.org/x/vuln/cmd/govulncheck@v1.9.0 ./...
4 changes: 2 additions & 2 deletions .github/workflows/frontend.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@ jobs:
NEXT_TELEMETRY_DISABLED: '1'
STORYBOOK_DISABLE_TELEMETRY: '1'
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
- uses: actions/checkout@v7.0.1
- uses: actions/setup-node@v7.1.0
with:
node-version: '24.22.1'
- name: Install dependencies
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/worktree-dev-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ jobs:
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v7.0.1
- name: Check syntax
run: |
bash -n scripts/worktree-dev/*.sh scripts/worktree-dev/talebound-worktree-dev
Expand Down
6 changes: 3 additions & 3 deletions backend/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
# Build stage
FROM golang:1.23-alpine3.20 AS builder
FROM golang:1.27.3-alpine3.24 AS builder
WORKDIR /app
COPY . .
RUN go build -o main main.go


# Run stage
FROM alpine:3.16
FROM alpine:3.24
WORKDIR /app
COPY --from=builder /app/main .
COPY app.env .
COPY db/migration /app/db/migration

EXPOSE 8080
CMD [ "/app/main" ]
CMD [ "/app/main" ]
16 changes: 12 additions & 4 deletions backend/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
export

DB_URL=postgresql://root:secret@localhost:5432/talebound?sslmode=disable
SQLC_VERSION := 1.31.1
PROTO_SERVICES := $(shell find proto/services -mindepth 1 -maxdepth 1 -type d | sort | awk -F/ '{print "proto/services/" $$NF "/*.proto"}' | tr '\n' ' ')

network-create:
Expand Down Expand Up @@ -42,7 +43,7 @@ migratedown1:

sqlc-generate:
go run github.com/the-medo/golang-migrate-objects -mpath=$(MIGRATION_URL) -obj_path=$(MIGRATION_OBJECTS_URL) -db_source=$(DB_SOURCE) -co_filename=$(MIGRATION_CREATE_OBJECTS_FILENAME) -do_filename=$(MIGRATION_DROP_OBJECTS_FILENAME) -sumfile
docker run --rm -v "$(CURDIR):/src" -w /src kjconroy/sqlc generate
docker run --rm -v "$(CURDIR):/src" -w /src sqlc/sqlc:$(SQLC_VERSION) generate

test:
go test -v -cover -short ./...
Expand All @@ -51,8 +52,15 @@ server:
go run main.go

mock:
mockgen -package mockdb -destination db/mock/store.go github.com/the-medo/talebound-backend/db/sqlc Store
mockgen -package mockwk -destination worker/mock/distributor.go github.com/the-medo/talebound-backend/worker TaskDistributor
go run go.uber.org/mock/mockgen -package mockdb -destination db/mock/store.go github.com/the-medo/talebound-backend/db/sqlc Store
go run go.uber.org/mock/mockgen -package mockwk -destination worker/mock/distributor.go github.com/the-medo/talebound-backend/worker TaskDistributor

tools-install:
go install google.golang.org/protobuf/cmd/protoc-gen-go
go install google.golang.org/grpc/cmd/protoc-gen-go-grpc
go install github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-grpc-gateway
go install github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv2
go install github.com/rakyll/statik

db_docs:
dbdocs password --set secret --project talebound
Expand Down Expand Up @@ -100,4 +108,4 @@ new_migration:

prepare: network-create postgres redis wait-for-createdb createdb wait-for-createdb migrateup server

.PHONY: network-create rm-postgres createdb dropdb postgres migrateup migratedown sqlc-generate test mock migrateup1 migratedown1 db_docs db_schema proto_win proto_linux evans proto_without_clean redis new_migration
.PHONY: tools-install network-create rm-postgres createdb dropdb postgres migrateup migratedown sqlc-generate test mock migrateup1 migratedown1 db_docs db_schema proto_win proto_linux evans proto_without_clean redis new_migration
28 changes: 23 additions & 5 deletions backend/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@ AWS EC2 pricing - https://aws.amazon.com/ec2/pricing/on-demand/

AWS EKS pod count - https://github.com/awslabs/amazon-eks-ami/blob/master/files/eni-max-pods.txt

The manual deployment workflow reads the cluster's Kubernetes version through
`aws eks describe-cluster`, then installs the latest stable `kubectl` patch for
that same minor version. It stops before publishing an image if version lookup
fails. This updates the deployment client; it does not upgrade the EKS cluster.

## Install cert-manager
https://cert-manager.io/docs/installation/kubectl/
`kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.11.0/cert-manager.yaml`
Expand Down Expand Up @@ -38,7 +43,11 @@ https://github.com/ScoopInstaller/Scoop#readme
- add migrate to path system variables (in ~\scoop\apps\migrate\ [version])

### Running sqlc generate on "windows"
`docker run --rm -v "%cd%:/src" -w /src kjconroy/sqlc generate`
`docker run --rm -v "%cd%:/src" -w /src sqlc/sqlc:1.31.1 generate`

`make sqlc-generate` pins the same sqlc version in `Makefile`. After changing
queries or upgrading sqlc, regenerate the database code and run `make mock`
to keep store mocks aligned.

---

Expand Down Expand Up @@ -70,10 +79,19 @@ https://grpc.io/docs/languages/go/quickstart/
Latest release:
https://github.com/protocolbuffers/protobuf/releases

Use Go 1.27.3 for backend builds and development. CI reads the version from
`go.mod`; the production Dockerfile and worktree Compose image use the same
toolchain version.

From `backend/`, install generators at the versions selected by `go.mod`:

```sh
make tools-install
```
$ go install google.golang.org/protobuf/cmd/protoc-gen-go@v1.28
$ go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@v1.2
```

Ensure `$(go env GOPATH)/bin` is on `PATH` before running `make proto`.
`make mock` runs the maintained `go.uber.org/mock` generator at the module's
selected version without requiring a global `mockgen` installation.


---
Expand All @@ -84,4 +102,4 @@ $ go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@v1.2
4. **create new query files in** - `db/query`
5. **SQLC - generate sql.go file** `make sqlc-generate`
6. **run mockgen** - `make mock`
7. **run tests** - `make test`
7. **run tests** - `make test`
2 changes: 1 addition & 1 deletion backend/api/services/auth/rpc_login_user_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@ package auth
import (
"context"
"database/sql"
"github.com/golang/mock/gomock"
"github.com/stretchr/testify/require"
testutils2 "github.com/the-medo/talebound-backend/api/testutils"
mockdb "github.com/the-medo/talebound-backend/db/mock"
db "github.com/the-medo/talebound-backend/db/sqlc"
"github.com/the-medo/talebound-backend/pb"
"go.uber.org/mock/gomock"
"google.golang.org/genproto/googleapis/rpc/errdetails"
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
Expand Down
2 changes: 1 addition & 1 deletion backend/api/services/auth/rpc_verify_email_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@ package auth

import (
"context"
"github.com/golang/mock/gomock"
"github.com/stretchr/testify/require"
"github.com/the-medo/talebound-backend/api/testutils"
mockdb "github.com/the-medo/talebound-backend/db/mock"
db "github.com/the-medo/talebound-backend/db/sqlc"
"github.com/the-medo/talebound-backend/pb"
"github.com/the-medo/talebound-backend/util"
"go.uber.org/mock/gomock"
"google.golang.org/genproto/googleapis/rpc/errdetails"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
Expand Down
48 changes: 20 additions & 28 deletions backend/api/services/images/upload_image.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,15 @@ package images
import (
"bytes"
"context"
cloudflareGo "github.com/cloudflare/cloudflare-go"
"image"
_ "image/gif" // Import this to decode gif images
_ "image/jpeg" // Import this to decode jpeg images
_ "image/png" // Import this to decode png images
"net/http"

"github.com/cloudflare/cloudflare-go/v7"
cloudflareImages "github.com/cloudflare/cloudflare-go/v7/images"
"github.com/cloudflare/cloudflare-go/v7/option"
"github.com/the-medo/talebound-backend/api/servicecore"
"github.com/the-medo/talebound-backend/e"
"github.com/the-medo/talebound-backend/pb"
Expand All @@ -12,11 +20,6 @@ import (
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
"google.golang.org/protobuf/types/known/timestamppb"
"image"
_ "image/gif" // Import this to decode gif images
_ "image/jpeg" // Import this to decode jpeg images
_ "image/png" // Import this to decode png images
"io"
)

func UploadImage(service *servicecore.ServiceCore, ctx context.Context, request *pb.UploadImageRequest) (*pb.UploadImageResponse, error) {
Expand All @@ -25,11 +28,15 @@ func UploadImage(service *servicecore.ServiceCore, ctx context.Context, request
return nil, e.InvalidArgumentError(violations)
}

cloudflare, err := cloudflareGo.NewWithAPIToken(service.Config.CloudflareApiToken)
if err != nil {
return nil, status.Errorf(codes.Internal, "failed to create cloudflare client: %v", err)
if service.Config.CloudflareApiToken == "" {
return nil, status.Error(codes.Internal, "Cloudflare API token is not configured")
}

client := cloudflare.NewClient(option.WithAPIToken(service.Config.CloudflareApiToken))
return uploadImage(ctx, client.Images.V1, service.Config.CloudflareAccountId, request)
}

func uploadImage(ctx context.Context, client *cloudflareImages.V1Service, accountID string, request *pb.UploadImageRequest) (*pb.UploadImageResponse, error) {
reader := bytes.NewReader(request.GetData())

decodedImg, _, err := image.DecodeConfig(reader)
Expand All @@ -45,27 +52,12 @@ func UploadImage(service *servicecore.ServiceCore, ctx context.Context, request
return nil, err
}

readCloser := io.NopCloser(reader)

defer func(readCloser io.ReadCloser) {
err := readCloser.Close()
if err != nil {

}
}(readCloser)

uploadRequest := cloudflareGo.UploadImageParams{
File: readCloser,
Name: request.GetFilename(),
}

resourceContainer := cloudflareGo.ResourceContainer{
Level: cloudflareGo.AccountRouteLevel,
Identifier: service.Config.CloudflareAccountId,
Type: cloudflareGo.AccountType,
uploadRequest := cloudflareImages.V1NewParams{
AccountID: cloudflare.F(accountID),
File: cloudflare.FileParam(reader, request.GetFilename(), http.DetectContentType(request.GetData())),
}

img, err := cloudflare.UploadImage(ctx, &resourceContainer, uploadRequest)
img, err := client.New(ctx, uploadRequest)
if err != nil {
return nil, status.Errorf(codes.Internal, "failed to upload image: %v", err)
}
Expand Down
Loading
Loading