From 7ed0c005c856429cdcf1eb58e52d3a32b6b78ff0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matheus=20Andr=C3=A9?= Date: Mon, 14 Sep 2026 18:16:06 -0300 Subject: [PATCH] chore: replace LocalStack with floci as local AWS emulator --- CLAUDE.md | 6 ++--- README.md | 5 +++-- docker/docker-compose.yaml | 22 +++++++++++-------- docker/scripts/init.sh | 12 +++++++--- .../src/main/resources/application.properties | 15 +++++++------ 5 files changed, 36 insertions(+), 24 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index 54f7db4..c2dbca8 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -8,7 +8,7 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co |---|---| | `timeless-api/` | Java 21 / Quarkus 3 backend + Angular 19 frontend (served via Quinoa) | | `whatsapp/` | Node.js service that bridges WhatsApp messages to the API via SQS | -| `docker/` | Local-dev docker-compose (LocalStack SQS/S3, PostgreSQL, Ollama) | +| `docker/` | Local-dev docker-compose (floci for SQS/S3, PostgreSQL, Ollama) | | `infrastructure/` | Terraform / AWS provisioning | | `site/` | Landing page | @@ -52,7 +52,7 @@ npm run prettier:write # format check + apply ### Local infrastructure ```bash -cd docker && docker-compose up -d # starts LocalStack + PostgreSQL (Ollama excluded by default) +cd docker && docker-compose up -d # starts floci (LocalStack replacement) + PostgreSQL (Ollama excluded by default) # Include the local Ollama container (opt-in via the "ollama" compose profile) cd docker && docker-compose --profile ollama up -d @@ -119,7 +119,7 @@ All Java code lives under `dev.matheuscruz` with three layers: | Profile | Activated by | Key behavior | |---|---|---| | `dev` (default) | `quarkus:dev` | Uses OpenAI, requires `OPENAI_API_KEY` in `application.properties` | -| `local` | `-Dquarkus.profile=local` | Uses Ollama at `localhost:11434`, uses LocalStack for SQS | +| `local` | `-Dquarkus.profile=local` | Uses Ollama at `localhost:11434`, uses floci (local AWS emulator) for SQS | | `test` | `@QuarkusTest` | Disables SQS devservices, disables OpenAI integration, disables scheduler | Maven profiles `openai` (active by default) and `ollama` control which LangChain4j dependency is included. Use `-Pollama` to switch. diff --git a/README.md b/README.md index c59cd1f..0638b3b 100644 --- a/README.md +++ b/README.md @@ -54,7 +54,7 @@ We love community contributions! Whether you're fixing a bug or adding a feature If you want to use Terraform and AWS see [this tutorial](RUNNING_TERRAFORM_AWS.md). -## Running locally with localstack +## Running locally with floci (local AWS emulator) > [!WARNING] > Actually, you will need two phones and a OpenAI token. Feel free to change the code to support only one number and a local LLM. @@ -69,7 +69,8 @@ If you want to use Terraform and AWS see [this tutorial](RUNNING_TERRAFORM_AWS.m docker-compose up -d ``` -This starts LocalStack and PostgreSQL only. The Ollama container is now opt-in +This starts [floci](https://github.com/floci-io/floci) (a free, open-source LocalStack +replacement that emulates SQS and S3 on port 4566) and PostgreSQL only. The Ollama container is now opt-in via the `ollama` Compose profile — include it only if you plan to run the API against a local LLM without Quarkus Dev Services: diff --git a/docker/docker-compose.yaml b/docker/docker-compose.yaml index 75b9f99..5c5abfc 100644 --- a/docker/docker-compose.yaml +++ b/docker/docker-compose.yaml @@ -1,19 +1,20 @@ version: '3.8' services: - localstack: - image: localstack/localstack:4.2.0 - container_name: localstack + floci: + # Drop-in replacement for LocalStack (https://github.com/floci-io/floci). + # The "-compat" variant bundles the AWS CLI so scripts/init.sh can seed queues and buckets. + image: floci/floci:latest-compat + container_name: floci ports: - "4566:4566" environment: - - SERVICES=sqs,s3 - - DEBUG=1 - - DATA_DIR=/var/lib/localstack/data + # keep queues/buckets across restarts (in-memory + async flush to disk every 5s) + - FLOCI_STORAGE_MODE=hybrid volumes: - - ./localstack-data:/var/lib/localstack/data + # named volume: the image owns /app/data as uid 1001, a bind mount would be root-owned + - floci-data:/app/data - ./scripts:/etc/localstack/init/ready.d - - /var/run/docker.sock:/var/run/docker.sock postgres: image: postgres:17 @@ -33,4 +34,7 @@ services: profiles: - ollama ports: - - "11434:11434" \ No newline at end of file + - "11434:11434" + +volumes: + floci-data: diff --git a/docker/scripts/init.sh b/docker/scripts/init.sh index cbb0507..d754689 100755 --- a/docker/scripts/init.sh +++ b/docker/scripts/init.sh @@ -1,6 +1,12 @@ #!/bin/bash +# Seeds the local AWS emulator (floci) with the resources the app expects. +# Runs on container start; safe to re-run because state is persisted between restarts. +set -u -awslocal sqs create-queue --queue-name incoming-message.fifo --attributes '{"FifoQueue": "True"}' -awslocal sqs create-queue --queue-name recognized-message.fifo --attributes '{"FifoQueue": "True"}' +ENDPOINT="http://localhost:4566" -awslocal s3 mb s3://timeless-local-assets +aws --endpoint-url "$ENDPOINT" sqs create-queue --queue-name incoming-message.fifo --attributes '{"FifoQueue": "True"}' +aws --endpoint-url "$ENDPOINT" sqs create-queue --queue-name recognized-message.fifo --attributes '{"FifoQueue": "True"}' + +aws --endpoint-url "$ENDPOINT" s3api head-bucket --bucket timeless-local-assets 2>/dev/null \ + || aws --endpoint-url "$ENDPOINT" s3 mb s3://timeless-local-assets diff --git a/timeless-api/src/main/resources/application.properties b/timeless-api/src/main/resources/application.properties index 1fe084e..cb25bb5 100644 --- a/timeless-api/src/main/resources/application.properties +++ b/timeless-api/src/main/resources/application.properties @@ -30,11 +30,11 @@ mp.jwt.verify.issuer=https://timelessapp.platformoon.com/issuer smallrye.jwt.new-token.issuer=https://timelessapp.platformoon.com/issuer -# dev profile - ./mvnw quarkus:dev : OpenAI plus LocalStack +# dev profile - ./mvnw quarkus:dev : OpenAI plus floci (local AWS emulator) %dev.security.sensible.secret=YS0xNi1ieXRlLXNlY3JldA== -# sqs to localstack +# sqs to floci (local AWS emulator on port 4566) %dev.mp.messaging.incoming.whatsapp-incoming.region=us-east-1 %dev.mp.messaging.incoming.whatsapp-incoming.endpoint-override=http://localhost:4566 %dev.quarkus.sqs.endpoint-override=http://localhost:4566 @@ -56,9 +56,9 @@ smallrye.jwt.new-token.issuer=https://timelessapp.platformoon.com/issuer %dev.quarkus.hibernate-orm.log.sql=true -# local profile - ./mvnw quarkus:dev -Pollama -Dquarkus.profile=local : Ollama plus LocalStack +# local profile - ./mvnw quarkus:dev -Pollama -Dquarkus.profile=local : Ollama plus floci (local AWS emulator) -# sqs to localstack +# sqs to floci (local AWS emulator on port 4566) %local.mp.messaging.incoming.whatsapp-incoming.region=us-east-1 %local.mp.messaging.incoming.whatsapp-incoming.endpoint-override=http://localhost:4566 %local.quarkus.sqs.endpoint-override=http://localhost:4566 @@ -84,15 +84,16 @@ smallrye.jwt.new-token.issuer=https://timelessapp.platformoon.com/issuer %test.whatsapp.incoming-message.queue-url=test-incoming-queue %test.whatsapp.recognized-message.queue-url=test-processed-queue -# sqs to localstack +# sqs to floci (local AWS emulator on port 4566) %test.quarkus.sqs.endpoint-override=http://127.0.0.1:4566 %test.quarkus.sqs.aws.region=us-east-1 %test.quarkus.sqs.aws.credentials.type=STATIC %test.quarkus.sqs.aws.credentials.static-provider.access-key-id=test %test.quarkus.sqs.aws.credentials.static-provider.secret-access-key=test -# jwt -%test.mp.jwt.verify.publickey=test-public-key +# jwt bundled dev keys under src/main/resources so tests can sign and verify tokens +%test.mp.jwt.verify.publickey.location=publicKey.pem +%test.smallrye.jwt.sign.key.location=privateKey.pem # disable background integrations during tests %test.quarkus.scheduler.enabled=false