infra: migrate deployment to Coolify with Garage S3
Some checks failed
CI / ci (push) Failing after 19s
CI / deploy (push) Has been skipped
CI / e2e (push) Has been skipped

- Remove docker-compose files (Coolify manages services individually)
- Replace MinIO with Garage (S3-compatible, actively maintained)
- Add CI deploy job: build+push :develop image on every green Develop push
- Add Coolify webhook trigger for automatic redeployment
- Update README, .env.example, and storage references
- Rename migrate script to provider-agnostic name

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-07 15:28:43 +02:00
parent 41e58d0153
commit d519a83cc4
11 changed files with 107 additions and 272 deletions

View File

@@ -3,7 +3,7 @@ import { beforeEach, describe, expect, mock, test } from "bun:test";
// Mock the S3 client send method
const mockSend = mock(() => Promise.resolve({}));
const mockGetSignedUrl = mock(() =>
Promise.resolve("https://minio:9000/gearbox-images/test.jpg?signed=1"),
Promise.resolve("https://s3.example.com/gearbox-images/test.jpg?signed=1"),
);
// Mock modules before importing the service
@@ -36,11 +36,11 @@ mock.module("@aws-sdk/s3-request-presigner", () => ({
}));
// Set env vars before importing the service
process.env.S3_ENDPOINT = "http://localhost:9000";
process.env.S3_ACCESS_KEY = "minioadmin";
process.env.S3_SECRET_KEY = "minioadmin";
process.env.S3_ENDPOINT = "http://localhost:3900";
process.env.S3_ACCESS_KEY = "test-access-key";
process.env.S3_SECRET_KEY = "test-secret-key";
process.env.S3_BUCKET = "gearbox-images";
process.env.S3_REGION = "us-east-1";
process.env.S3_REGION = "garage";
// Import after mocking
const { uploadImage, deleteImage, getImageUrl, withImageUrl, withImageUrls } =
@@ -51,7 +51,7 @@ describe("storage.service", () => {
mockSend.mockClear();
mockGetSignedUrl.mockClear();
mockGetSignedUrl.mockResolvedValue(
"https://minio:9000/gearbox-images/test.jpg?signed=1",
"https://s3.example.com/gearbox-images/test.jpg?signed=1",
);
});
@@ -100,7 +100,7 @@ describe("storage.service", () => {
const url = await getImageUrl("test-image.jpg");
expect(mockGetSignedUrl).toHaveBeenCalledTimes(1);
expect(url).toBe("https://minio:9000/gearbox-images/test.jpg?signed=1");
expect(url).toBe("https://s3.example.com/gearbox-images/test.jpg?signed=1");
});
});
@@ -124,7 +124,7 @@ describe("storage.service", () => {
const result = await withImageUrl(record);
expect(result.imageUrl).toBe(
"https://minio:9000/gearbox-images/test.jpg?signed=1",
"https://s3.example.com/gearbox-images/test.jpg?signed=1",
);
expect(result.id).toBe(1);
expect(mockGetSignedUrl).toHaveBeenCalledTimes(1);
@@ -142,11 +142,11 @@ describe("storage.service", () => {
expect(results).toHaveLength(3);
expect(results[0].imageUrl).toBe(
"https://minio:9000/gearbox-images/test.jpg?signed=1",
"https://s3.example.com/gearbox-images/test.jpg?signed=1",
);
expect(results[1].imageUrl).toBeNull();
expect(results[2].imageUrl).toBe(
"https://minio:9000/gearbox-images/test.jpg?signed=1",
"https://s3.example.com/gearbox-images/test.jpg?signed=1",
);
// Called twice: for records[0] and records[2]
expect(mockGetSignedUrl).toHaveBeenCalledTimes(2);