This is an automated email from the ASF dual-hosted git repository.

popduke pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/bifromq.git


The following commit(s) were added to refs/heads/main by this push:
     new 247ba20bf Chores for the first incubator release: (#191)
247ba20bf is described below

commit 247ba20bfc58a491038cf955797794c4799def8a
Author: Yonny(Yu) Hao <[email protected]>
AuthorDate: Wed Nov 26 18:04:41 2025 +0800

    Chores for the first incubator release: (#191)
    
    Co-authored-by: Gu Jiawei <[email protected]>
---
 .github/workflows/build-docker.yaml                |  93 ----
 .github/workflows/build-latest-docker.yaml         |  80 ---
 .github/workflows/github-packages-publish.yml      |  41 --
 .../workflows/main-branch-push-maven-deploy.yml    |  36 --
 .github/workflows/maven-central-publish.yml        |  54 --
 .github/workflows/release.yaml                     |  44 --
 Dockerfile                                         |  47 +-
 LICENSE-Binary                                     | 114 ++--
 README.md                                          |  59 +-
 .../src/test/resources/log4j2-test.xml             |   1 -
 .../src/test/resources/log4j2-test.xml             |   1 -
 .../src/test/resources/log4j2-test.xml             |   1 -
 .../src/test/resources/log4j2-test.xml             |   1 -
 .../src/test/resources/log4j2-test.xml             |   1 -
 .../src/test/resources/log4j2-test.xml             |   1 -
 .../basekv/store/wal/KVRangeWALSubscription.java   |  39 +-
 .../src/test/resources/log4j2-test.xml             |   1 -
 bifromq-bom/pom.xml                                | 231 +-------
 .../src/test/resources/log4j2-test.xml             |   1 -
 .../src/test/resources/log4j2-test.xml             |   1 -
 .../src/test/resources/log4j2-test.xml             |   1 -
 build/build-bifromq-starter/pom.xml                |  68 ++-
 pom.xml                                            | 593 ++++++++++++++++++---
 release/checksum-artifacts.sh                      |  36 ++
 release/docker-build.sh                            |  90 ++++
 release/release.sh                                 | 166 ++++--
 release/sign-artifacts.sh                          |  44 ++
 release/source-assembly.xml                        |  64 +++
 28 files changed, 1110 insertions(+), 799 deletions(-)

diff --git a/.github/workflows/build-docker.yaml 
b/.github/workflows/build-docker.yaml
deleted file mode 100644
index 3400bb64a..000000000
--- a/.github/workflows/build-docker.yaml
+++ /dev/null
@@ -1,93 +0,0 @@
-name: Build docker image
-on:
-  push:
-    tags:
-      - v[0-9].[0-9].[0-9]**
-  workflow_dispatch:
-
-jobs:
-  prebuild:
-    runs-on: ubuntu-latest
-    outputs:
-      NEED_BUILD_DOCKER: ${{ steps.check.outputs.NEED_BUILD_DOCKER }}
-      TAG: ${{ steps.check.outputs.TAG }}
-      VERSION: ${{ steps.check.outputs.VERSION }}
-      MARK_LATEST: ${{ steps.check.outputs.MARK_LATEST }}
-    steps:
-      - name: check tag version
-        id: check
-        run: |
-          REF=${{ github.ref }}
-          if [[ "${{github.event.created}}" == "false" ]]; then
-              NEED_BUILD_DOCKER=false
-          else
-            if [[ "$REF" =~ refs/tags/v[0-9]+.[0-9]+.[0-9]+.* ]]; then
-                NEED_BUILD_DOCKER=true
-                MARK_LATEST=false
-                TAG=${REF:10}
-                VERSION=${REF:11}
-            else
-              MARK_LATEST=false
-              echo "Expected refs of the form 
'refs/tags/v<major-version>.<minor-version>.<patch-version>' but got '$REF'"
-              NEED_BUILD_DOCKER=false
-            fi
-          fi
-          echo "MARK_LATEST=$MARK_LATEST, 
NEED_BUILD_DOCKER=$NEED_BUILD_DOCKER, TAG=$TAG, VERSION=$VERSION"
-          echo "NEED_BUILD_DOCKER=$NEED_BUILD_DOCKER" >> "$GITHUB_OUTPUT"
-          echo "TAG=$TAG" >> "$GITHUB_OUTPUT"
-          echo "VERSION=$VERSION" >> "$GITHUB_OUTPUT"
-          echo "MARK_LATEST=$MARK_LATEST" >> "$GITHUB_OUTPUT"
-  build-and-push-docker:
-    runs-on: ubuntu-latest
-    needs: prebuild
-    if: needs.prebuild.outputs.NEED_BUILD_DOCKER
-    strategy:
-      fail-fast: false
-    steps:
-      - uses: actions/checkout@v4
-        with:
-          ref: ${{ github.ref }}
-      - name: Set up JDK 17
-        uses: actions/setup-java@v4
-        with:
-          java-version: '17'
-          distribution: 'temurin'
-          cache: maven
-      - name: Build with Maven
-        run: mvn clean package -DskipTests
-      - name: Post build package
-        run: |
-          rm -rf output
-          mkdir output
-          cp target/output/bifromq-* output
-          cp Dockerfile output
-      - name: Upload build package
-        uses: actions/upload-artifact@v4
-        with:
-          name: prerelease-${{ needs.prebuild.outputs.VERSION }}
-          path: output
-      - uses: docker/setup-qemu-action@v3
-      - uses: docker/setup-buildx-action@v3
-      - name: Docker meta
-        id: meta
-        uses: docker/metadata-action@v5
-        with:
-          images: bifromq/bifromq
-          tags: |
-            type=raw,value=${{ needs.prebuild.outputs.VERSION }}
-            type=raw,value=latest,enable=${{ 
needs.prebuild.outputs.MARK_LATEST }}
-      - uses: docker/login-action@v3
-        with:
-          username: ${{secrets.DOCKER_USERNAME}}
-          password: ${{secrets.DOCKER_PASSWORD}}
-      - name: Build and push Docker images
-        uses: docker/build-push-action@v5
-        with:
-          context: output
-          push: true
-          # Path to the Dockerfile
-          file: Dockerfile
-          # List of target platforms for build
-          platforms: linux/amd64,linux/arm64
-          # List of tags s
-          tags: ${{ steps.meta.outputs.tags }}
diff --git a/.github/workflows/build-latest-docker.yaml 
b/.github/workflows/build-latest-docker.yaml
deleted file mode 100644
index e01bcad22..000000000
--- a/.github/workflows/build-latest-docker.yaml
+++ /dev/null
@@ -1,80 +0,0 @@
-name: Build latest docker image
-on:
-  workflow_dispatch:
-
-jobs:
-  prebuild:
-    runs-on: ubuntu-latest
-    outputs:
-      NEED_BUILD_DOCKER: ${{ steps.check.outputs.NEED_BUILD_DOCKER }}
-      TAG: ${{ steps.check.outputs.TAG }}
-      VERSION: ${{ steps.check.outputs.VERSION }}
-    steps:
-      - name: check tag version
-        id: check
-        run: |
-          REF=${{ github.ref }}
-          if [[ "$REF" =~ refs/tags/v[0-9]+.[0-9]+.[0-9]+.* ]]; then
-              NEED_BUILD_DOCKER=true
-              TAG=${REF:10}
-              VERSION=${REF:11}
-          else
-            echo "Expected refs of the form 
'refs/tags/v<major-version>.<minor-version>.<patch-version>' but got '$REF'"
-            NEED_BUILD_DOCKER=false
-          fi
-          echo "NEED_BUILD_DOCKER=$NEED_BUILD_DOCKER, TAG=$TAG, 
VERSION=$VERSION"
-          echo "NEED_BUILD_DOCKER=$NEED_BUILD_DOCKER" >> "$GITHUB_OUTPUT"
-          echo "VERSION=$VERSION" >> "$GITHUB_OUTPUT"
-  build-and-push-docker:
-    runs-on: ubuntu-latest
-    needs: prebuild
-    if: needs.prebuild.outputs.NEED_BUILD_DOCKER
-    strategy:
-      fail-fast: false
-    steps:
-      - uses: actions/checkout@v4
-        with:
-          ref: ${{ github.ref }}
-      - name: Set up JDK 17
-        uses: actions/setup-java@v4
-        with:
-          java-version: '17'
-          distribution: 'temurin'
-          cache: maven
-      - name: Build with Maven
-        run: mvn clean package -DskipTests
-      - name: Post build package
-        run: |
-          rm -rf output
-          mkdir output
-          cp target/output/bifromq-* output
-          cp Dockerfile output
-      - name: Upload build package
-        uses: actions/upload-artifact@v4
-        with:
-          name: prerelease-${{ needs.prebuild.outputs.VERSION }}
-          path: output
-      - uses: docker/setup-qemu-action@v3
-      - uses: docker/setup-buildx-action@v3
-      - name: Docker meta
-        id: meta
-        uses: docker/metadata-action@v5
-        with:
-          images: bifromq/bifromq
-          tags: |
-            type=raw,value=latest
-      - uses: docker/login-action@v3
-        with:
-          username: ${{secrets.DOCKER_USERNAME}}
-          password: ${{secrets.DOCKER_PASSWORD}}
-      - name: Build and push Docker images
-        uses: docker/build-push-action@v5
-        with:
-          context: output
-          push: true
-          # Path to the Dockerfile
-          file: Dockerfile
-          # List of target platforms for build
-          platforms: linux/amd64,linux/arm64
-          # List of tags s
-          tags: ${{ steps.meta.outputs.tags }}
diff --git a/.github/workflows/github-packages-publish.yml 
b/.github/workflows/github-packages-publish.yml
deleted file mode 100644
index 9297b9628..000000000
--- a/.github/workflows/github-packages-publish.yml
+++ /dev/null
@@ -1,41 +0,0 @@
-name: github-packages-publish
-
-on:
-  push:
-    tags:
-      - v[0-9].[0-9].[0-9]**
-  workflow_dispatch:
-
-jobs:
-  build:
-    runs-on: ubuntu-latest
-    permissions:
-      contents: read
-      packages: write
-
-    steps:
-      - uses: actions/checkout@v4
-      - name: Set up JDK 17
-        uses: actions/setup-java@v4
-        with:
-          java-version: '17'
-          distribution: 'temurin'
-
-      - name: Build with Maven
-        run: mvn -B package -DskipTests --file pom.xml
-
-  publish-github-packages:
-    runs-on: ubuntu-latest
-    needs: build
-    steps:
-      - uses: actions/checkout@v4
-      - name: Set up JDK 17
-        uses: actions/setup-java@v4
-        with:
-          java-version: '17'
-          distribution: 'temurin'
-
-      - name: Publish to GitHub Packages
-        run: mvn clean deploy -P github-packages-deploy -pl 
:base-cluster,:base-env-provider,:base-env-provider-spi,:base-hlc,:base-crdt-store,:base-crdt-service,:base-logger,:base-hookloader,:base-kv-store-balance-spi,:bifromq-plugin-archetype,:bifromq-plugin-context,:bifromq-plugin-main,:bifromq-plugin-auth-provider,:bifromq-plugin-event-collector,:bifromq-plugin-resource-throttler,:bifromq-plugin-sub-broker,:bifromq-plugin-setting-provider
 -am -DskipTests
-        env:
-          GITHUB_TOKEN: ${{ secrets.GH_TOKEN }}
\ No newline at end of file
diff --git a/.github/workflows/main-branch-push-maven-deploy.yml 
b/.github/workflows/main-branch-push-maven-deploy.yml
deleted file mode 100644
index 90279f0f6..000000000
--- a/.github/workflows/main-branch-push-maven-deploy.yml
+++ /dev/null
@@ -1,36 +0,0 @@
-# This workflow will build a package using Maven and then publish it to GitHub 
packages when a release is created
-# For more information see: 
https://github.com/actions/setup-java#apache-maven-with-a-settings-path
-
-name: main push maven deploy
-
-on:
-  workflow_dispatch:
-
-
-jobs:
-  publish:
-    runs-on: ubuntu-latest
-    permissions:
-      contents: read
-      packages: write
-
-    steps:
-      - uses: actions/checkout@v4
-      - name: Set up JDK 17
-        uses: actions/setup-java@v4
-        with:
-          java-version: '17'
-          distribution: 'temurin'
-
-      - name: Build with Maven
-        run: mvn -B package -DskipTests --file pom.xml
-
-      - name: Set up GitHub Packages
-        uses: actions/setup-java@v4
-        with: # running setup-java again overwrites the settings.xml
-          java-version: '17'
-          distribution: 'temurin'
-      - name: Publish to GitHub Packages
-        run: mvn clean deploy -P github-packages-deploy -pl 
:base-cluster,:base-env-provider,:base-env-provider-spi,:base-hlc,:base-crdt-store,:base-crdt-service,:base-logger,:base-hookloader,:base-kv-store-balance-spi,:bifromq-plugin-archetype,:bifromq-plugin-context,:bifromq-plugin-main,:bifromq-plugin-auth-provider,:bifromq-plugin-event-collector,:bifromq-plugin-resource-throttler,:bifromq-plugin-sub-broker,:bifromq-plugin-setting-provider
 -am -DskipTests
-        env:
-          GITHUB_TOKEN: ${{ secrets.GH_TOKEN }}
\ No newline at end of file
diff --git a/.github/workflows/maven-central-publish.yml 
b/.github/workflows/maven-central-publish.yml
deleted file mode 100644
index 6598d37c1..000000000
--- a/.github/workflows/maven-central-publish.yml
+++ /dev/null
@@ -1,54 +0,0 @@
-name: maven-central-publish
-
-on:
-  push:
-    tags:
-      - v[0-9].[0-9].[0-9]**
-  workflow_dispatch:
-
-jobs:
-  build:
-    runs-on: ubuntu-latest
-    permissions:
-      contents: read
-      packages: write
-
-    steps:
-      - uses: actions/checkout@v4
-      - name: Set up JDK 17
-        uses: actions/setup-java@v4
-        with:
-          java-version: '17'
-          distribution: 'temurin'
-
-      - name: Build with Maven
-        run: mvn -B package -DskipTests --file pom.xml
-
-  publish-maven-central:
-    runs-on: ubuntu-latest
-    needs: build
-    steps:
-      - uses: actions/checkout@v4
-      - name: Set up JDK 17
-        uses: actions/setup-java@v4
-        with:
-          java-version: '17'
-          distribution: 'temurin'
-
-      - name: Set up Maven Central
-        uses: actions/setup-java@v4
-        with:
-          java-version: '17'
-          distribution: 'temurin'
-          server-id: sonatype-nexus-repository
-          server-username: MAVEN_USERNAME
-          server-password: MAVEN_CENTRAL_TOKEN
-          gpg-private-key: ${{ secrets.MAVEN_GPG_PRIVATE_KEY }}
-          gpg-passphrase: MAVEN_GPG_PASSPHRASE
-
-      - name: Publish to Maven Central
-        run: mvn clean deploy -P maven-central-deploy -pl 
:bifromq-plugin-archetype,:bifromq-plugin-context,:bifromq-plugin-main,:bifromq-plugin-auth-provider,:bifromq-plugin-event-collector,:bifromq-plugin-resource-throttler,:bifromq-plugin-setting-provider
 -am -DskipTests
-        env:
-          MAVEN_USERNAME: ${{ secrets.MAVEN_USERNAME }}
-          MAVEN_CENTRAL_TOKEN: ${{ secrets.MAVEN_CENTRAL_TOKEN }}
-          MAVEN_GPG_PASSPHRASE: ${{ secrets.MAVEN_GPG_PASSPHRASE }}
\ No newline at end of file
diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml
deleted file mode 100644
index 855788e26..000000000
--- a/.github/workflows/release.yaml
+++ /dev/null
@@ -1,44 +0,0 @@
-name: Release assets
-permissions: write-all
-on:
-  release:
-    types: [ published ]
-
-jobs:
-  prepare:
-    runs-on: ubuntu-latest
-    outputs:
-      IS_VALID_TAG: ${{ steps.check.outputs.IS_VALID_TAG }}
-    steps:
-      - name: check tag version
-        id: check
-        run: |
-          REF=${{ github.ref }}
-          if [[ "$REF" =~ refs/tags/v[0-9]+.[0-9]+.[0-9]+.* ]]; then
-            IS_VALID_TAG=true
-          else
-              echo "Expected refs of the form 
'refs/tags/v-<major-version>.<minor-version>.<patch-version>' but got '$REF'"
-              IS_VALID_TAG=false
-          fi
-          echo "IS_VALID_TAG=$IS_VALID_TAG"
-          echo "IS_VALID_TAG=$IS_VALID_TAG" >> "$GITHUB_OUTPUT"
-  build-and-upload:
-    runs-on: ubuntu-latest
-    needs: prepare
-    if: needs.prepare.outputs.IS_VALID_TAG
-    steps:
-      - uses: actions/checkout@v4
-        with:
-          ref: ${{ github.ref }}
-      - name: Set up JDK 17
-        uses: actions/setup-java@v4
-        with:
-          java-version: '17'
-          distribution: 'temurin'
-          cache: maven
-      - name: Build with Maven
-        run: mvn clean package -DskipTests
-      - uses: AButler/[email protected]
-        with:
-          files: 
'target/output/bifromq-*-standalone.tar.gz;target/output/bifromq-*-standalone.zip'
-          repo-token: ${{ secrets.GITHUB_TOKEN }}
diff --git a/Dockerfile b/Dockerfile
index 985d21f5d..66521a20a 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -15,51 +15,42 @@
 # specific language governing permissions and limitations
 # under the License.
 
-ARG BASE_IMAGE=debian:buster-slim
+FROM 
debian@sha256:b4aa902587c2e61ce789849cb54c332b0400fe27b1ee33af4669e1f7e7c3e22f 
AS verifier
 
-FROM --platform=$TARGETPLATFORM ${BASE_IMAGE} AS builder
+ARG TARGETARCH
+ARG BIFROMQ_VERSION
 
-ARG TARGETPLATFORM
-
-# Install necessary tools for diagnostics and JDK download
-RUN apt-get update && apt-get install -y --no-install-recommends 
ca-certificates curl net-tools lsof netcat procps less \
-    && if [ "$TARGETPLATFORM" = "linux/amd64" ]; then \
-        export JDK_ARCH=x64; \
-    else \
-        export JDK_ARCH=aarch64; \
-    fi \
-    && echo "JDK_ARCH is set to ${JDK_ARCH}" \
-    && curl --retry 5 -S -L -O 
https://download.java.net/java/GA/jdk17.0.2/dfd4a8d0985749f896bed50d7138ee7f/8/GPL/openjdk-17.0.2_linux-${JDK_ARCH}_bin.tar.gz
 \
-    && tar -zxvf openjdk-17.0.2_linux-${JDK_ARCH}_bin.tar.gz \
-    && rm -rf openjdk-17.0.2_linux-${JDK_ARCH}_bin.tar.gz \
+RUN apt-get update \
+    && apt-get install -y --no-install-recommends ca-certificates tar \
     && rm -rf /var/lib/apt/lists/*
 
-COPY bifromq-*-standalone.tar.gz /
+COPY apache-bifromq-${BIFROMQ_VERSION}.tar.gz /tmp/release/
+COPY apache-bifromq-${BIFROMQ_VERSION}.tar.gz.sha512 /tmp/release/
+
+RUN cd /tmp/release \
+    && echo "$(awk '{print $1}' apache-bifromq-*.tar.gz.sha512)  
apache-bifromq-${BIFROMQ_VERSION}.tar.gz" | sha512sum -c - \
+    && mkdir /bifromq \
+    && tar -zxvf apache-bifromq-*.tar.gz --strip-components 1 -C /bifromq
 
-RUN mkdir /bifromq && tar -zxvf /bifromq-*-standalone.tar.gz 
--strip-components 1 -C /bifromq \
-    && rm -rf /bifromq-*-standalone.tar.gz
+FROM 
debian@sha256:b4aa902587c2e61ce789849cb54c332b0400fe27b1ee33af4669e1f7e7c3e22f
 
-FROM --platform=$TARGETPLATFORM ${BASE_IMAGE}
+ARG TARGETARCH
 
 RUN groupadd -r -g 1000 bifromq \
     && useradd -r -m -u 1000 -g bifromq bifromq \
     && apt-get update \
-    && apt-get install -y --no-install-recommends net-tools lsof netcat procps 
less \
+    && apt-get install -y --no-install-recommends ca-certificates net-tools 
lsof netcat-openbsd procps less openjdk-17-jre-headless \
     && rm -rf /var/lib/apt/lists/*
 
-COPY --chown=bifromq:bifromq --from=builder /jdk-17.0.2 /usr/share/jdk-17.0.2
-COPY --chown=bifromq:bifromq --from=builder /bifromq /home/bifromq/
+ENV JAVA_HOME=/usr/lib/jvm/java-17-openjdk-$TARGETARCH
+ENV PATH=$JAVA_HOME/bin:$PATH
 
-ENV JAVA_HOME /usr/share/jdk-17.0.2
-ENV PATH /usr/share/jdk-17.0.2/bin:$PATH
+COPY --chown=bifromq:bifromq --from=verifier /bifromq /home/bifromq/
 
 WORKDIR /home/bifromq
 
 USER bifromq
 
-# Set common command aliases
-RUN echo "alias ll='ls -al'" >> ~/.bashrc
-
 EXPOSE 1883 1884 80 443
 
-CMD ["./bin/standalone.sh", "start", "-fg"]
\ No newline at end of file
+CMD ["./bin/standalone.sh", "start", "-fg"]
diff --git a/LICENSE-Binary b/LICENSE-Binary
index 95b83eae0..62928ea9a 100644
--- a/LICENSE-Binary
+++ b/LICENSE-Binary
@@ -210,11 +210,11 @@ Apache License, Version 2.0
 - com.fasterxml.jackson.core:jackson-core:2.18.1
 - com.fasterxml.jackson.core:jackson-databind:2.18.1
 - com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:2.18.1
-- com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.18.2
-- com.fasterxml.jackson.jakarta.rs:jackson-jakarta-rs-base:2.18.2
-- com.fasterxml.jackson.jakarta.rs:jackson-jakarta-rs-json-provider:2.18.2
-- 
com.fasterxml.jackson.module:jackson-module-jakarta-xmlbind-annotations:2.18.2
-- com.github.ben-manes.caffeine:caffeine:3.2.1
+- com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.18.1
+- com.fasterxml.jackson.jakarta.rs:jackson-jakarta-rs-base:2.18.1
+- com.fasterxml.jackson.jakarta.rs:jackson-jakarta-rs-json-provider:2.18.1
+- 
com.fasterxml.jackson.module:jackson-module-jakarta-xmlbind-annotations:2.18.1
+- com.github.ben-manes.caffeine:caffeine:3.2.3
 - com.google.guava:failureaccess:1.0.2
 - com.google.guava:guava:33.2.1-jre
 - com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava
@@ -222,62 +222,63 @@ Apache License, Version 2.0
 - com.google.j2objc:j2objc-annotations:2.8
 - com.google.j2objc:j2objc-annotations:3.0.0
 - commons-cli:commons-cli:1.5.0
-- io.grpc:grpc-api:1.72.0
-- io.grpc:grpc-context:1.72.0
-- io.grpc:grpc-core:1.72.0
-- io.grpc:grpc-grpclb:1.72.0
-- io.grpc:grpc-inprocess:1.72.0
-- io.grpc:grpc-netty:1.72.0
-- io.grpc:grpc-protobuf:1.72.0
-- io.grpc:grpc-protobuf-lite:1.72.0
-- io.grpc:grpc-stub:1.72.0
-- io.grpc:grpc-util:1.72.0
+- org.apache.commons:commons-collections4:4.4
+- io.grpc:grpc-api:1.77.0
+- io.grpc:grpc-context:1.77.0
+- io.grpc:grpc-core:1.77.0
+- io.grpc:grpc-grpclb:1.77.0
+- io.grpc:grpc-inprocess:1.77.0
+- io.grpc:grpc-netty:1.77.0
+- io.grpc:grpc-protobuf:1.77.0
+- io.grpc:grpc-protobuf-lite:1.77.0
+- io.grpc:grpc-stub:1.77.0
+- io.grpc:grpc-util:1.77.0
 - io.micrometer:micrometer-commons:1.11.12
 - io.micrometer:micrometer-core:1.11.12
 - io.micrometer:micrometer-observation:1.11.12
 - io.micrometer:micrometer-registry-prometheus:1.11.12
-- io.netty:netty-all:4.1.121.Final
-- io.netty:netty-buffer:4.1.121.Final
-- io.netty:netty-codec:4.1.121.Final
-- io.netty:netty-codec-dns:4.1.121.Final
-- io.netty:netty-codec-haproxy:4.1.121.Final
-- io.netty:netty-codec-http:4.1.121.Final
-- io.netty:netty-codec-http2:4.1.121.Final
-- io.netty:netty-codec-memcache:4.1.121.Final
-- io.netty:netty-codec-mqtt:4.1.121.Final
-- io.netty:netty-codec-redis:4.1.121.Final
-- io.netty:netty-codec-smtp:4.1.121.Final
-- io.netty:netty-codec-socks:4.1.121.Final
-- io.netty:netty-codec-stomp:4.1.121.Final
-- io.netty:netty-codec-xml:4.1.121.Final
-- io.netty:netty-common:4.1.121.Final
-- io.netty:netty-handler:4.1.121.Final
-- io.netty:netty-handler-proxy:4.1.121.Final
-- io.netty:netty-handler-ssl-ocsp:4.1.121.Final
-- io.netty:netty-resolver:4.1.121.Final
-- io.netty:netty-resolver-dns:4.1.121.Final
-- io.netty:netty-resolver-dns-classes-macos:4.1.121.Final
-- io.netty:netty-resolver-dns-native-macos:4.1.121.Final
-- io.netty:netty-transport:4.1.121.Final
-- io.netty:netty-transport-classes-epoll:4.1.121.Final
-- io.netty:netty-transport-classes-kqueue:4.1.121.Final
-- io.netty:netty-transport-native-epoll:4.1.121.Final
-- io.netty:netty-transport-native-kqueue:4.1.121.Final
-- io.netty:netty-transport-native-unix-common:4.1.121.Final
-- io.netty:netty-transport-rxtx:4.1.121.Final
-- io.netty:netty-transport-sctp:4.1.121.Final
-- io.netty:netty-transport-udt:4.1.121.Final
+- io.netty:netty-all:4.1.127.Final
+- io.netty:netty-buffer:4.1.127.Final
+- io.netty:netty-codec:4.1.127.Final
+- io.netty:netty-codec-dns:4.1.127.Final
+- io.netty:netty-codec-haproxy:4.1.127.Final
+- io.netty:netty-codec-http:4.1.127.Final
+- io.netty:netty-codec-http2:4.1.127.Final
+- io.netty:netty-codec-memcache:4.1.127.Final
+- io.netty:netty-codec-mqtt:4.1.127.Final
+- io.netty:netty-codec-redis:4.1.127.Final
+- io.netty:netty-codec-smtp:4.1.127.Final
+- io.netty:netty-codec-socks:4.1.127.Final
+- io.netty:netty-codec-stomp:4.1.127.Final
+- io.netty:netty-codec-xml:4.1.127.Final
+- io.netty:netty-common:4.1.127.Final
+- io.netty:netty-handler:4.1.127.Final
+- io.netty:netty-handler-proxy:4.1.127.Final
+- io.netty:netty-handler-ssl-ocsp:4.1.127.Final
+- io.netty:netty-resolver:4.1.127.Final
+- io.netty:netty-resolver-dns:4.1.127.Final
+- io.netty:netty-resolver-dns-classes-macos:4.1.127.Final
+- io.netty:netty-resolver-dns-native-macos:4.1.127.Final
+- io.netty:netty-transport:4.1.127.Final
+- io.netty:netty-transport-classes-epoll:4.1.127.Final
+- io.netty:netty-transport-classes-kqueue:4.1.127.Final
+- io.netty:netty-transport-native-epoll:4.1.127.Final
+- io.netty:netty-transport-native-kqueue:4.1.127.Final
+- io.netty:netty-transport-native-unix-common:4.1.127.Final
+- io.netty:netty-transport-rxtx:4.1.127.Final
+- io.netty:netty-transport-sctp:4.1.127.Final
+- io.netty:netty-transport-udt:4.1.127.Final
 - io.prometheus:simpleclient:0.16.0
 - io.prometheus:simpleclient_common:0.16.0
 - io.prometheus:simpleclient_tracer_common:0.16.0
 - io.prometheus:simpleclient_tracer_otel:0.16.0
 - io.prometheus:simpleclient_tracer_otel_agent:0.16.0
-- io.reactivex.rxjava3:rxjava:3.1.10
-- io.swagger.core.v3:swagger-annotations-jakarta:2.2.30
-- io.swagger.core.v3:swagger-core-jakarta:2.2.30
-- io.swagger.core.v3:swagger-integration-jakarta:2.2.30
-- io.swagger.core.v3:swagger-jaxrs2-jakarta:2.2.30
-- io.swagger.core.v3:swagger-models-jakarta:2.2.30
+- io.reactivex.rxjava3:rxjava:3.1.12
+- io.swagger.core.v3:swagger-annotations-jakarta:2.2.40
+- io.swagger.core.v3:swagger-core-jakarta:2.2.40
+- io.swagger.core.v3:swagger-integration-jakarta:2.2.40
+- io.swagger.core.v3:swagger-jaxrs2-jakarta:2.2.40
+- io.swagger.core.v3:swagger-models-jakarta:2.2.40
 - jakarta.inject:jakarta.inject-api:2.0.1
 - jakarta.validation:jakarta.validation-api:3.0.2
 - net.bytebuddy:byte-buddy:1.14.15
@@ -309,17 +310,18 @@ MIT License (see: licenses/mit.txt)
 - org.pcollections:pcollections:4.0.2
 - org.checkerframework:checker-qual:3.42.0
 - org.codehaus.mojo:animal-sniffer-annotations:1.24
+- org.slf4j:slf4j-api:2.0.17
 
 MIT-0 (see: licenses/mit-0.txt)
 - org.reactivestreams:reactive-streams:1.0.4
 
 Bouncy Castle Licence (see: licenses/bouncy-castle.txt)
-- org.bouncycastle:bcpkix-jdk18on:1.78.1
-- org.bouncycastle:bcprov-jdk18on:1.78.1
-- org.bouncycastle:bcutil-jdk18on:1.78.1
+- org.bouncycastle:bcpkix-jdk18on:1.79
+- org.bouncycastle:bcprov-jdk18on:1.79
+- org.bouncycastle:bcutil-jdk18on:1.79
 
 EPL-2.0 / GPL-2.0-with-classpath-exception (see: licenses/epl-2.0.txt)
 - jakarta.ws.rs:jakarta.ws.rs-api:4.0.0
 
 Eclipse Distribution License - v 1.0 (see: licenses/edl-1.0.txt)
-- jakarta.xml.bind:jakarta.xml.bind-api:3.0.1
\ No newline at end of file
+- jakarta.xml.bind:jakarta.xml.bind-api:3.0.1
diff --git a/README.md b/README.md
index e9a53c387..044db69de 100644
--- a/README.md
+++ b/README.md
@@ -3,7 +3,7 @@
 [![GitHub 
Release](https://img.shields.io/github/release/bifromqio/bifromq?color=brightgreen&label=Release)](https://github.com/bifromqio/bifromq/releases)
 <a href="https://discord.gg/Pfs3QRadRB";><img 
src="https://img.shields.io/discord/1115542029531885599?logo=discord&logoColor=white";
 alt="BifroMQ Discord server" /></a>
 
-BifroMQ is a high-performance, distributed MQTT broker that natively supports 
multi-tenancy. It is designed to enable the building of large-scale IoT device 
connectivity and messaging systems.
+Apache BifroMQ is a high-performance, distributed MQTT broker that natively 
supports multi-tenancy. It is designed to enable the building of large-scale 
IoT device connectivity and messaging systems.
 
 ## Features
 
@@ -29,16 +29,16 @@ GitHub 
[repository](https://github.com/apache/bifromq-sites).
 ### Docker
 
 ```
-docker run -d -m <MEM_LIMIT> -e MEM_LIMIT='<MEM_LIMIT_IN_BYTES>' --name 
bifromq -p 1883:1883 bifromq/bifromq:latest
+docker run -d -m <MEM_LIMIT> -e MEM_LIMIT='<MEM_LIMIT_IN_BYTES>' --name 
bifromq -p 1883:1883 apache/bifromq:${TAG}
 ```
 
 Substitute `<MEM_LIMIT>` and `<MEM_LIMIT_IN_BYTES>` with the actual memory 
allocation for the Docker process, for
-example, `2G` for `<MEM_LIMIT>` and `2147483648` for `<MEM_LIMIT_IN_BYTES>`. 
If not specified, BifroMQ defaults to using
+example, `2G` for `<MEM_LIMIT>` and `2147483648` for `<MEM_LIMIT_IN_BYTES>`. 
If not specified, Apache BifroMQ defaults to using
 the hosting server's physical memory for determining JVM parameters. This can 
result in the Docker process being
 terminated by the host's Out-of-Memory (OOM) Killer. Refer to 
[here](https://bifromq.apache.org/docs/installation/docker/)
 for more information.
 
-You can build a BifroMQ cluster using Docker Compose on a single host for 
development and testing. Suppose you want to create a cluster with three nodes: 
node1, 
+You can build an Apache BifroMQ cluster using Docker Compose on a single host 
for development and testing. Suppose you want to create a cluster with three 
nodes: node1, 
 node2, and node3. The directory structure should be as follows:
 ```
 |- docker-compose.yml
@@ -58,7 +58,7 @@ The `docker-compose.yml` file defines the services for the 
three nodes:
 ```yml
 services:
   bifromq-node1:
-    image: bifromq/bifromq:latest
+    image: apache/bifromq:${TAG}
     container_name: bifromq-node1
     volumes:
       - ./node1/standalone.yml:/home/bifromq/conf/standalone.yml
@@ -70,7 +70,7 @@ services:
       - bifromq-net
 
   bifromq-node2:
-    image: bifromq/bifromq:latest
+    image: apache/bifromq:${TAG}
     container_name: bifromq-node2
     volumes:
       - ./node2/standalone.yml:/home/bifromq/conf/standalone.yml
@@ -82,7 +82,7 @@ services:
       - bifromq-net
 
   bifromq-node3:
-    image: bifromq/bifromq:latest
+    image: apache/bifromq:${TAG}
     container_name: bifromq-node3
     volumes:
       - ./node3/standalone.yml:/home/bifromq/conf/standalone.yml
@@ -107,8 +107,9 @@ docker compose up -d
 
 * JDK 17+
 * Maven 3.5.0+
+* (Optional for native TLS) OpenSSL available on the host; if absent, TLS 
falls back to JDK implementation.
 
-#### Get source & Build
+#### Get Source & Build
 
 Clone the repository to your local workspace:
 
@@ -122,13 +123,24 @@ Navigate to the project root folder and execute the 
following commands to build
 ```
 cd bifromq
 mvn wrapper:wrapper
-./mvnw -U clean package
+./mvnw -U clean verify -DskipTests -Pbuild-release
 ```
 
-The build output consists of several archive files located under 
`/target/output`
+The build output consists of several archive files with `sha512` checksum 
located under `/target/output`
 
-* `bifromq-<VERSION>.tar.gz`
-* `bifromq-<VERSION>-windows.zip`
+* `apache-bifromq-<VERSION>-src.tar.gz` 
+* `apache-bifromq-<VERSION>.tar.gz`
+* `apache-bifromq-<VERSION>-windows.zip`
+
+#### Native TLS options
+
+* Default binary bundles `netty-tcnative-classes` only; if system OpenSSL is 
unavailable, TLS falls back to JDK TLS automatically.
+* To build with system OpenSSL (requires OpenSSL installed on the host):
+  * `mvn -Pbuild-release -Pwith-tcnative 
-Dtcnative.classifier=<your_platform_classifier> clean verify -DskipTests`
+    * Example classifiers: `linux-x86_64`, `linux-aarch_64`, `osx-aarch_64`, 
`osx-x86_64`, `windows-x86_64`.
+* To build with BoringSSL static bundle
+  * `mvn -Pbuild-release -Pwith-boringssl-static 
-Dtcnative.classifier=<your_platform_classifier> clean verify -DskipTests`
+    * Example classifiers: `linux-x86_64`, `linux-aarch_64`, `osx-aarch_64`, 
`osx-x86_64`, `windows-x86_64`.
 
 #### Running the tests
 
@@ -140,9 +152,20 @@ Note: The tests may take some time to finish
 mvn test
 ```
 
+#### Build the Docker Image
+With the binary `apache-bifromq-<version>.tar.gz` and its `.sha512` under 
`target/output`, build the Docker image using the helper script:
+```shell
+./release/docker-build.sh target/output/apache-bifromq-<version>.tar.gz
+```
+Optional: override the tag or target architecture:
+```shell
+./release/docker-build.sh -t apache-bifromq:<version> 
target/output/apache-bifromq-<version>.tar.gz
+./release/docker-build.sh -a arm64 
target/output/apache-bifromq-<version>.tar.gz
+```
+
 ### Quick Start
 
-To quickly set up a BifroMQ server, extract the `bifromq-<VERSION>.tar.gz` 
file into a directory. You will see the
+To quickly set up an Apache BifroMQ server, extract the 
`apache-bifromq-<VERSION>.tar.gz` file into a directory. You will see the
 following directory structure:
 
 ```
@@ -169,7 +192,7 @@ in a self-explanatory manner. By default, the standalone 
server stores persisten
 
 ### Plugin Development
 
-To jump start your BifroMQ plugin development, execute the following Maven 
command:
+To jump start your Apache BifroMQ plugin development, execute the following 
Maven command:
 
 ```
 mvn archetype:generate \
@@ -187,7 +210,7 @@ mvn archetype:generate \
 
 Replace `<YOUR_GROUP_ID>`, `<YOUR_ARTIFACT_ID>`, `<YOUR_PROJECT_VERSION>`, 
`<YOUR_PLUGIN_CLASS_NAME>`,
 and `< YOUR_PLUGIN_CONTEXT_CLASS_NAME>` with your specific details. This 
command generates a ready-to-build multi-module
-project structured for BifroMQ plugin development.
+project structured for Apache BifroMQ plugin development.
 
 Important Note: The archetype version should be 3.2.0 or higher as the 
archetype is compatible starting from version
 3.2.0. Ensure that <BIFROMQ_VERSION> is set accordingly.
@@ -202,7 +225,7 @@ The standard cluster deployment mode is suitable for small 
to medium-sized produ
 reliability and scalability. It comprises several fully functional standalone 
nodes working together as a logical MQTT
 broker
 instance, ensuring high availability. You can also scale up the concurrent 
mqtt connection workload by adding more
-nodes, while some types of messaging related workload are not horizontal 
scalable in this mode.
+nodes, while some types of messaging related workload are not horizontally 
scalable in this mode.
 
 #### Independent Workload Cluster
 
@@ -212,7 +235,7 @@ of workload. These sub-clusters work together coherently to 
form a logical MQTT
 
 ## User Community
 
-We welcome you to connect with the BifroMQ community:
+We welcome you to connect with the Apache BifroMQ community:
 
 * **[Mailing 
Lists](https://bifromq.apache.org/community/#about-the-mailing-list)** – Stay 
informed, discuss development topics, and collaborate with other contributors 
via our public mailing lists.
 * **[Discord server](https://discord.gg/Pfs3QRadRB)** – Join us to chat, share 
ideas, and get real-time updates on ongoing work.
@@ -220,4 +243,4 @@ We welcome you to connect with the BifroMQ community:
 ## ASF Incubator disclaimer
 
 Apache BifroMQ&trade; is an effort undergoing incubation at The Apache 
Software Foundation (ASF), sponsored by the Apache Incubator. Incubation is 
required of all newly accepted projects until a further review indicates that 
the infrastructure, communications, and decision making process have stabilized 
in a manner consistent with other successful ASF projects. While incubation 
status is not necessarily a reflection of the completeness or stability of the 
code, it does indicate that the  [...]
- 
\ No newline at end of file
+ 
diff --git 
a/base-kv/base-kv-local-engine-memory/src/test/resources/log4j2-test.xml 
b/base-kv/base-kv-local-engine-memory/src/test/resources/log4j2-test.xml
index 1404c8668..532173fcc 100644
--- a/base-kv/base-kv-local-engine-memory/src/test/resources/log4j2-test.xml
+++ b/base-kv/base-kv-local-engine-memory/src/test/resources/log4j2-test.xml
@@ -29,7 +29,6 @@
         </Console>
     </Appenders>
     <Loggers>
-        <Logger name="org.apache.bifromq" level="DEBUG"/>
         <Root level="INFO">
             <AppenderRef ref="CONSOLE"/>
         </Root>
diff --git 
a/base-kv/base-kv-local-engine-rocksdb/src/test/resources/log4j2-test.xml 
b/base-kv/base-kv-local-engine-rocksdb/src/test/resources/log4j2-test.xml
index 1404c8668..532173fcc 100644
--- a/base-kv/base-kv-local-engine-rocksdb/src/test/resources/log4j2-test.xml
+++ b/base-kv/base-kv-local-engine-rocksdb/src/test/resources/log4j2-test.xml
@@ -29,7 +29,6 @@
         </Console>
     </Appenders>
     <Loggers>
-        <Logger name="org.apache.bifromq" level="DEBUG"/>
         <Root level="INFO">
             <AppenderRef ref="CONSOLE"/>
         </Root>
diff --git 
a/base-kv/base-kv-local-engine-spi/src/test/resources/log4j2-test.xml 
b/base-kv/base-kv-local-engine-spi/src/test/resources/log4j2-test.xml
index 7b038d5b4..40b2f5ce5 100644
--- a/base-kv/base-kv-local-engine-spi/src/test/resources/log4j2-test.xml
+++ b/base-kv/base-kv-local-engine-spi/src/test/resources/log4j2-test.xml
@@ -29,7 +29,6 @@
         </Console>
     </Appenders>
     <Loggers>
-        <Logger name="org.apache.bifromq" level="DEBUG"/>
         <Root level="INFO">
             <AppenderRef ref="CONSOLE"/>
         </Root>
diff --git a/base-kv/base-kv-raft/src/test/resources/log4j2-test.xml 
b/base-kv/base-kv-raft/src/test/resources/log4j2-test.xml
index f1e262ce0..40b2f5ce5 100644
--- a/base-kv/base-kv-raft/src/test/resources/log4j2-test.xml
+++ b/base-kv/base-kv-raft/src/test/resources/log4j2-test.xml
@@ -29,7 +29,6 @@
         </Console>
     </Appenders>
     <Loggers>
-        <Logger name="org.apache.bifromq.basekv.raft" level="INFO"/>
         <Root level="INFO">
             <AppenderRef ref="CONSOLE"/>
         </Root>
diff --git 
a/base-kv/base-kv-store-balance-controller/src/test/resources/log4j2-test.xml 
b/base-kv/base-kv-store-balance-controller/src/test/resources/log4j2-test.xml
index 471024f42..40b2f5ce5 100644
--- 
a/base-kv/base-kv-store-balance-controller/src/test/resources/log4j2-test.xml
+++ 
b/base-kv/base-kv-store-balance-controller/src/test/resources/log4j2-test.xml
@@ -29,7 +29,6 @@
         </Console>
     </Appenders>
     <Loggers>
-        <Logger name="org.apache.bifromq.basekv" level="DEBUG"/>
         <Root level="INFO">
             <AppenderRef ref="CONSOLE"/>
         </Root>
diff --git a/base-kv/base-kv-store-client/src/test/resources/log4j2-test.xml 
b/base-kv/base-kv-store-client/src/test/resources/log4j2-test.xml
index 7b038d5b4..40b2f5ce5 100644
--- a/base-kv/base-kv-store-client/src/test/resources/log4j2-test.xml
+++ b/base-kv/base-kv-store-client/src/test/resources/log4j2-test.xml
@@ -29,7 +29,6 @@
         </Console>
     </Appenders>
     <Loggers>
-        <Logger name="org.apache.bifromq" level="DEBUG"/>
         <Root level="INFO">
             <AppenderRef ref="CONSOLE"/>
         </Root>
diff --git 
a/base-kv/base-kv-store-server/src/main/java/org/apache/bifromq/basekv/store/wal/KVRangeWALSubscription.java
 
b/base-kv/base-kv-store-server/src/main/java/org/apache/bifromq/basekv/store/wal/KVRangeWALSubscription.java
index 87aaa12c0..4c89443ca 100644
--- 
a/base-kv/base-kv-store-server/src/main/java/org/apache/bifromq/basekv/store/wal/KVRangeWALSubscription.java
+++ 
b/base-kv/base-kv-store-server/src/main/java/org/apache/bifromq/basekv/store/wal/KVRangeWALSubscription.java
@@ -48,6 +48,7 @@ class KVRangeWALSubscription implements 
IKVRangeWALSubscription {
     private final IKVRangeWALSubscriber subscriber;
     private final CompositeDisposable disposables = new CompositeDisposable();
     private final AtomicBoolean fetching = new AtomicBoolean();
+    private final AtomicBoolean restoring = new AtomicBoolean();
     private final AtomicBoolean stopped = new AtomicBoolean();
     private final CompletableFuture<Void> stopSign = new CompletableFuture<>();
     private final AtomicLong lastFetchedIdx = new AtomicLong();
@@ -72,22 +73,32 @@ class KVRangeWALSubscription implements 
IKVRangeWALSubscription {
         this.lastFetchedIdx.set(lastFetchedIndex);
         this.subscriber.onSubscribe(this);
         disposables.add(wal.snapshotRestoreTask()
-            .subscribe(task -> fetchRunner.add(() -> {
+            .subscribe(task -> {
                 // snapshot restore work is preemptive
                 applyRunner.cancelAll();
-                applyRunner.add(restore(task))
-                    .handle((snap, e) -> fetchRunner.add(() -> {
-                        if (e != null) {
-                            log.error("Failed to restore from snapshot\n{}", 
task.snapshot, e);
-                            return;
-                        }
-                        log.debug("Snapshot installed\n{}", snap);
-                        lastFetchedIdx.set(snap.getLastAppliedIndex());
-                        pendingApplies.clear();
-                    }));
-            })));
+                fetchRunner.cancelAll();
+                fetching.set(false);
+                restoring.set(true);
+                fetchRunner.add(() -> {
+                    applyRunner.cancelAll();
+                    return applyRunner.add(restore(task));
+                }).handle((snap, e) -> fetchRunner.add(() -> {
+                    if (e != null) {
+                        log.error("Failed to restore from snapshot\n{}", 
task.snapshot, e);
+                        return;
+                    }
+                    log.debug("Snapshot installed\n{}", snap);
+                    lastFetchedIdx.set(snap.getLastAppliedIndex());
+                    pendingApplies.clear();
+                    restoring.set(false);
+                    scheduleFetchWAL();
+                }));
+            }));
         disposables.add(commitIndex
             .subscribe(c -> fetchRunner.add(() -> {
+                if (restoring.get()) {
+                    return;
+                }
                 Map.Entry<Long, Boolean> prevCommitIdx = 
pendingApplies.floorEntry(c.index);
                 if (prevCommitIdx != null && prevCommitIdx.getValue() == 
c.isLeader) {
                     pendingApplies.remove(prevCommitIdx.getKey());
@@ -121,6 +132,10 @@ class KVRangeWALSubscription implements 
IKVRangeWALSubscription {
     }
 
     private CompletableFuture<Void> fetchWAL() {
+        if (restoring.get()) {
+            fetching.set(false);
+            return CompletableFuture.completedFuture(null);
+        }
         NavigableMap<Long, Boolean> toFetch = shouldFetch();
         if (!toFetch.isEmpty()) {
             return wal.retrieveCommitted(lastFetchedIdx.get() + 1, 
maxFetchBytes)
diff --git a/base-kv/base-kv-store-server/src/test/resources/log4j2-test.xml 
b/base-kv/base-kv-store-server/src/test/resources/log4j2-test.xml
index 471024f42..40b2f5ce5 100644
--- a/base-kv/base-kv-store-server/src/test/resources/log4j2-test.xml
+++ b/base-kv/base-kv-store-server/src/test/resources/log4j2-test.xml
@@ -29,7 +29,6 @@
         </Console>
     </Appenders>
     <Loggers>
-        <Logger name="org.apache.bifromq.basekv" level="DEBUG"/>
         <Root level="INFO">
             <AppenderRef ref="CONSOLE"/>
         </Root>
diff --git a/bifromq-bom/pom.xml b/bifromq-bom/pom.xml
index 398052b5e..fa5d02bb6 100644
--- a/bifromq-bom/pom.xml
+++ b/bifromq-bom/pom.xml
@@ -23,14 +23,19 @@
          xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
http://maven.apache.org/xsd/maven-4.0.0.xsd";>
     <modelVersion>4.0.0</modelVersion>
 
-    <groupId>org.apache.bifromq</groupId>
+    <parent>
+        <groupId>org.apache.bifromq</groupId>
+        <artifactId>bifromq-parent</artifactId>
+        <version>${revision}</version>
+    </parent>
+
     <artifactId>bifromq-bom</artifactId>
-    <version>4.0.0-SNAPSHOT</version>
     <packaging>pom</packaging>
+    <description>Apache BifroMQ BOM for integration and secondary development 
dependencies.</description>
 
     <dependencyManagement>
         <dependencies>
-            <!-- bifromq modules -->
+            <!-- base modules -->
             <dependency>
                 <groupId>org.apache.bifromq</groupId>
                 <artifactId>base-env-provider</artifactId>
@@ -176,197 +181,17 @@
                 <artifactId>base-util</artifactId>
                 <version>${project.version}</version>
             </dependency>
-            <!-- common type -->
-            <dependency>
-                <groupId>org.apache.bifromq</groupId>
-                <artifactId>bifromq-util</artifactId>
-                <version>${project.version}</version>
-            </dependency>
-            <dependency>
-                <groupId>org.apache.bifromq</groupId>
-                <artifactId>bifromq-common-type</artifactId>
-                <version>${project.version}</version>
-            </dependency>
-            <dependency>
-                <groupId>org.apache.bifromq</groupId>
-                <artifactId>bifromq-metrics</artifactId>
-                <version>${project.version}</version>
-            </dependency>
-            <dependency>
-                <groupId>org.apache.bifromq</groupId>
-                <artifactId>bifromq-sysprops</artifactId>
-                <version>${project.version}</version>
-            </dependency>
-            <!-- plugin APIs and helpers-->
-            <dependency>
-                <groupId>org.apache.bifromq</groupId>
-                <artifactId>bifromq-plugin-auth-provider</artifactId>
-                <version>${project.version}</version>
-            </dependency>
-            <dependency>
-                <groupId>org.apache.bifromq</groupId>
-                <artifactId>bifromq-plugin-auth-provider-helper</artifactId>
-                <version>${project.version}</version>
-            </dependency>
-            <dependency>
-                <groupId>org.apache.bifromq</groupId>
-                <artifactId>bifromq-plugin-client-balancer</artifactId>
-                <version>${project.version}</version>
-            </dependency>
-            <dependency>
-                <groupId>org.apache.bifromq</groupId>
-                <artifactId>bifromq-plugin-client-balancer-helper</artifactId>
-                <version>${project.version}</version>
-            </dependency>
-            <dependency>
-                <groupId>org.apache.bifromq</groupId>
-                <artifactId>bifromq-plugin-event-collector</artifactId>
-                <version>${project.version}</version>
-            </dependency>
-            <dependency>
-                <groupId>org.apache.bifromq</groupId>
-                <artifactId>bifromq-plugin-event-collector-helper</artifactId>
-                <version>${project.version}</version>
-            </dependency>
-            <dependency>
-                <groupId>org.apache.bifromq</groupId>
-                <artifactId>bifromq-plugin-resource-throttler</artifactId>
-                <version>${project.version}</version>
-            </dependency>
-            <dependency>
-                <groupId>org.apache.bifromq</groupId>
-                
<artifactId>bifromq-plugin-resource-throttler-helper</artifactId>
-                <version>${project.version}</version>
-            </dependency>
-            <dependency>
-                <groupId>org.apache.bifromq</groupId>
-                <artifactId>bifromq-plugin-setting-provider</artifactId>
-                <version>${project.version}</version>
-            </dependency>
-            <dependency>
-                <groupId>org.apache.bifromq</groupId>
-                <artifactId>bifromq-plugin-setting-provider-helper</artifactId>
-                <version>${project.version}</version>
-            </dependency>
-            <dependency>
-                <groupId>org.apache.bifromq</groupId>
-                <artifactId>bifromq-plugin-sub-broker</artifactId>
-                <version>${project.version}</version>
-            </dependency>
-            <dependency>
-                <groupId>org.apache.bifromq</groupId>
-                <artifactId>bifromq-plugin-sub-broker-helper</artifactId>
-                <version>${project.version}</version>
-            </dependency>
-            <dependency>
-                <groupId>org.apache.bifromq</groupId>
-                <artifactId>bifromq-plugin-manager</artifactId>
-                <version>${project.version}</version>
-            </dependency>
-            <dependency>
-                <groupId>org.apache.bifromq</groupId>
-                <artifactId>bifromq-plugin-context</artifactId>
-                <version>${project.version}</version>
-            </dependency>
-            <dependency>
-                <groupId>org.apache.bifromq</groupId>
-                <artifactId>bifromq-plugin-main</artifactId>
-                <version>${project.version}</version>
-            </dependency>
-            <dependency>
-                <groupId>org.apache.bifromq</groupId>
-                <artifactId>bifromq-plugin-archetype</artifactId>
-                <version>${project.version}</version>
-            </dependency>
-            <!-- deliverer -->
-            <dependency>
-                <groupId>org.apache.bifromq</groupId>
-                <artifactId>bifromq-deliverer</artifactId>
-                <version>${project.version}</version>
-            </dependency>
-            <!-- retain -->
-            <dependency>
-                <groupId>org.apache.bifromq</groupId>
-                <artifactId>bifromq-retain-client</artifactId>
-                <version>${project.version}</version>
-            </dependency>
-            <dependency>
-                <groupId>org.apache.bifromq</groupId>
-                <artifactId>bifromq-retain-coproc-proto</artifactId>
-                <version>${project.version}</version>
-            </dependency>
-            <dependency>
-                <groupId>org.apache.bifromq</groupId>
-                <artifactId>bifromq-retain-rpc-definition</artifactId>
-                <version>${project.version}</version>
-            </dependency>
-            <dependency>
-                <groupId>org.apache.bifromq</groupId>
-                <artifactId>bifromq-retain-gc</artifactId>
-                <version>${project.version}</version>
-            </dependency>
+            <!-- spi modules -->
             <dependency>
                 <groupId>org.apache.bifromq</groupId>
                 <artifactId>bifromq-retain-store-spi</artifactId>
                 <version>${project.version}</version>
             </dependency>
-            <dependency>
-                <groupId>org.apache.bifromq</groupId>
-                <artifactId>bifromq-retain-store-schema</artifactId>
-                <version>${project.version}</version>
-            </dependency>
-            <dependency>
-                <groupId>org.apache.bifromq</groupId>
-                <artifactId>bifromq-retain-store</artifactId>
-                <version>${project.version}</version>
-            </dependency>
-            <dependency>
-                <groupId>org.apache.bifromq</groupId>
-                <artifactId>bifromq-retain-server</artifactId>
-                <version>${project.version}</version>
-            </dependency>
-            <!-- inbox -->
-            <dependency>
-                <groupId>org.apache.bifromq</groupId>
-                <artifactId>bifromq-inbox-client</artifactId>
-                <version>${project.version}</version>
-            </dependency>
-            <dependency>
-                <groupId>org.apache.bifromq</groupId>
-                <artifactId>bifromq-inbox-coproc-proto</artifactId>
-                <version>${project.version}</version>
-            </dependency>
-            <dependency>
-                <groupId>org.apache.bifromq</groupId>
-                <artifactId>bifromq-inbox-rpc-definition</artifactId>
-                <version>${project.version}</version>
-            </dependency>
             <dependency>
                 <groupId>org.apache.bifromq</groupId>
                 <artifactId>bifromq-inbox-store-spi</artifactId>
                 <version>${project.version}</version>
             </dependency>
-            <dependency>
-                <groupId>org.apache.bifromq</groupId>
-                <artifactId>bifromq-inbox-store</artifactId>
-                <version>${project.version}</version>
-            </dependency>
-            <dependency>
-                <groupId>org.apache.bifromq</groupId>
-                <artifactId>bifromq-inbox-store-schema</artifactId>
-                <version>${project.version}</version>
-            </dependency>
-            <dependency>
-                <groupId>org.apache.bifromq</groupId>
-                <artifactId>bifromq-inbox-server</artifactId>
-                <version>${project.version}</version>
-            </dependency>
-            <!-- dist -->
-            <dependency>
-                <groupId>org.apache.bifromq</groupId>
-                <artifactId>bifromq-dist-client</artifactId>
-                <version>${project.version}</version>
-            </dependency>
             <dependency>
                 <groupId>org.apache.bifromq</groupId>
                 <artifactId>bifromq-dist-worker-spi</artifactId>
@@ -374,22 +199,23 @@
             </dependency>
             <dependency>
                 <groupId>org.apache.bifromq</groupId>
-                <artifactId>bifromq-dist-worker</artifactId>
+                <artifactId>bifromq-mqtt-server-spi</artifactId>
                 <version>${project.version}</version>
             </dependency>
+            <!-- spi dependencies -->
             <dependency>
                 <groupId>org.apache.bifromq</groupId>
-                <artifactId>bifromq-dist-server</artifactId>
+                <artifactId>bifromq-common-type</artifactId>
                 <version>${project.version}</version>
             </dependency>
             <dependency>
                 <groupId>org.apache.bifromq</groupId>
-                <artifactId>bifromq-dist-rpc-definition</artifactId>
+                <artifactId>bifromq-retain-store-schema</artifactId>
                 <version>${project.version}</version>
             </dependency>
             <dependency>
                 <groupId>org.apache.bifromq</groupId>
-                <artifactId>bifromq-dist-coproc-proto</artifactId>
+                <artifactId>bifromq-inbox-store-schema</artifactId>
                 <version>${project.version}</version>
             </dependency>
             <dependency>
@@ -397,53 +223,40 @@
                 <artifactId>bifromq-dist-worker-schema</artifactId>
                 <version>${project.version}</version>
             </dependency>
-            <!-- session dict -->
+            <!-- plugin modules -->
             <dependency>
                 <groupId>org.apache.bifromq</groupId>
-                <artifactId>bifromq-session-dict-client</artifactId>
-                <version>${project.version}</version>
-            </dependency>
-            <dependency>
-                <groupId>org.apache.bifromq</groupId>
-                <artifactId>bifromq-session-dict-server</artifactId>
-                <version>${project.version}</version>
-            </dependency>
-            <dependency>
-                <groupId>org.apache.bifromq</groupId>
-                <artifactId>bifromq-session-dict-rpc-definition</artifactId>
+                <artifactId>bifromq-plugin-auth-provider</artifactId>
                 <version>${project.version}</version>
             </dependency>
-            <!-- mqtt broker -->
             <dependency>
                 <groupId>org.apache.bifromq</groupId>
-                <artifactId>bifromq-mqtt-broker-client</artifactId>
+                <artifactId>bifromq-plugin-client-balancer</artifactId>
                 <version>${project.version}</version>
             </dependency>
             <dependency>
                 <groupId>org.apache.bifromq</groupId>
-                <artifactId>bifromq-mqtt-server-spi</artifactId>
+                <artifactId>bifromq-plugin-event-collector</artifactId>
                 <version>${project.version}</version>
             </dependency>
             <dependency>
                 <groupId>org.apache.bifromq</groupId>
-                <artifactId>bifromq-mqtt-broker-rpc-definition</artifactId>
+                <artifactId>bifromq-plugin-resource-throttler</artifactId>
                 <version>${project.version}</version>
             </dependency>
             <dependency>
                 <groupId>org.apache.bifromq</groupId>
-                <artifactId>bifromq-mqtt-server</artifactId>
+                <artifactId>bifromq-plugin-setting-provider</artifactId>
                 <version>${project.version}</version>
             </dependency>
-            <!--API Server-->
             <dependency>
                 <groupId>org.apache.bifromq</groupId>
-                <artifactId>bifromq-apiserver</artifactId>
+                <artifactId>bifromq-plugin-context</artifactId>
                 <version>${project.version}</version>
             </dependency>
-            <!--demo-->
             <dependency>
                 <groupId>org.apache.bifromq</groupId>
-                <artifactId>build-plugin-demo</artifactId>
+                <artifactId>bifromq-plugin-main</artifactId>
                 <version>${project.version}</version>
             </dependency>
         </dependencies>
diff --git 
a/bifromq-dist/bifromq-dist-coproc-proto/src/test/resources/log4j2-test.xml 
b/bifromq-dist/bifromq-dist-coproc-proto/src/test/resources/log4j2-test.xml
index ed768f5eb..40b2f5ce5 100644
--- a/bifromq-dist/bifromq-dist-coproc-proto/src/test/resources/log4j2-test.xml
+++ b/bifromq-dist/bifromq-dist-coproc-proto/src/test/resources/log4j2-test.xml
@@ -29,7 +29,6 @@
         </Console>
     </Appenders>
     <Loggers>
-        <Logger name="org.apache.bifromq.inbox" level="DEBUG"/>
         <Root level="INFO">
             <AppenderRef ref="CONSOLE"/>
         </Root>
diff --git 
a/bifromq-dist/bifromq-dist-worker/src/test/resources/log4j2-test.xml 
b/bifromq-dist/bifromq-dist-worker/src/test/resources/log4j2-test.xml
index e626d3b7a..40b2f5ce5 100644
--- a/bifromq-dist/bifromq-dist-worker/src/test/resources/log4j2-test.xml
+++ b/bifromq-dist/bifromq-dist-worker/src/test/resources/log4j2-test.xml
@@ -29,7 +29,6 @@
         </Console>
     </Appenders>
     <Loggers>
-        <Logger name="org.apache.bifromq.dist" level="DEBUG"/>
         <Root level="INFO">
             <AppenderRef ref="CONSOLE"/>
         </Root>
diff --git 
a/bifromq-inbox/bifromq-inbox-server/src/test/resources/log4j2-test.xml 
b/bifromq-inbox/bifromq-inbox-server/src/test/resources/log4j2-test.xml
index ed768f5eb..40b2f5ce5 100644
--- a/bifromq-inbox/bifromq-inbox-server/src/test/resources/log4j2-test.xml
+++ b/bifromq-inbox/bifromq-inbox-server/src/test/resources/log4j2-test.xml
@@ -29,7 +29,6 @@
         </Console>
     </Appenders>
     <Loggers>
-        <Logger name="org.apache.bifromq.inbox" level="DEBUG"/>
         <Root level="INFO">
             <AppenderRef ref="CONSOLE"/>
         </Root>
diff --git a/build/build-bifromq-starter/pom.xml 
b/build/build-bifromq-starter/pom.xml
index 3535b6b2d..86b8e6468 100644
--- a/build/build-bifromq-starter/pom.xml
+++ b/build/build-bifromq-starter/pom.xml
@@ -91,7 +91,7 @@
         </dependency>
         <dependency>
             <groupId>io.netty</groupId>
-            <artifactId>netty-tcnative-boringssl-static</artifactId>
+            <artifactId>netty-tcnative-classes</artifactId>
             <scope>runtime</scope>
         </dependency>
         <!-- bifromq modules -->
@@ -189,7 +189,7 @@
         </dependency>
     </dependencies>
     <build>
-        <finalName>bifromq-${project.parent.version}</finalName>
+        <finalName>apache-bifromq-${project.parent.version}</finalName>
         <plugins>
             <plugin>
                 <groupId>org.apache.maven.plugins</groupId>
@@ -206,7 +206,7 @@
                                 <descriptor>assembly/assembly.xml</descriptor>
                             </descriptors>
                             <appendAssemblyId>false</appendAssemblyId>
-                            
<finalName>bifromq-${project.parent.version}</finalName>
+                            
<finalName>apache-bifromq-${project.parent.version}</finalName>
                             <tarLongFileMode>posix</tarLongFileMode>
                             
<outputDirectory>${build.output.dir}</outputDirectory>
                         </configuration>
@@ -222,7 +222,7 @@
                                 
<descriptor>assembly/assembly-windows.xml</descriptor>
                             </descriptors>
                             <appendAssemblyId>false</appendAssemblyId>
-                            
<finalName>bifromq-${project.parent.version}-windows</finalName>
+                            
<finalName>apache-bifromq-${project.parent.version}-windows</finalName>
                             <tarLongFileMode>posix</tarLongFileMode>
                             
<outputDirectory>${build.output.dir}</outputDirectory>
                         </configuration>
@@ -231,4 +231,64 @@
             </plugin>
         </plugins>
     </build>
+    <profiles>
+        <profile>
+            <id>with-tcnative</id>
+            <properties>
+                
<tcnative.classifier>${os.detected.classifier}</tcnative.classifier>
+            </properties>
+            <dependencies>
+                <dependency>
+                    <groupId>io.netty</groupId>
+                    <artifactId>netty-tcnative</artifactId>
+                    <version>${tcnative.version}</version>
+                    <classifier>${tcnative.classifier}</classifier>
+                    <scope>runtime</scope>
+                </dependency>
+            </dependencies>
+        </profile>
+        <profile>
+            <id>with-boringssl-static</id>
+            <properties>
+                
<tcnative.classifier>${os.detected.classifier}</tcnative.classifier>
+            </properties>
+            <dependencies>
+                <dependency>
+                    <groupId>io.netty</groupId>
+                    <artifactId>netty-tcnative-boringssl-static</artifactId>
+                    <version>${tcnative.version}</version>
+                    <classifier>${tcnative.classifier}</classifier>
+                    <scope>runtime</scope>
+                </dependency>
+            </dependencies>
+        </profile>
+        <profile>
+            <id>build-release</id>
+            <build>
+                <plugins>
+                    <plugin>
+                        <groupId>org.apache.maven.plugins</groupId>
+                        <artifactId>maven-antrun-plugin</artifactId>
+                        <executions>
+                            <execution>
+                                <id>checksum-release-artifacts</id>
+                                <phase>verify</phase>
+                                <goals>
+                                    <goal>run</goal>
+                                </goals>
+                                <configuration>
+                                    <target>
+                                        <exec executable="bash" 
failonerror="true">
+                                            <arg 
value="${maven.multiModuleProjectDirectory}/release/checksum-artifacts.sh"/>
+                                            <arg value="${build.output.dir}"/>
+                                        </exec>
+                                    </target>
+                                </configuration>
+                            </execution>
+                        </executions>
+                    </plugin>
+                </plugins>
+            </build>
+        </profile>
+    </profiles>
 </project>
diff --git a/pom.xml b/pom.xml
index 70db48ca3..cda00861a 100644
--- a/pom.xml
+++ b/pom.xml
@@ -24,7 +24,7 @@
     <parent>
         <groupId>org.apache</groupId>
         <artifactId>apache</artifactId>
-        <version>29</version>
+        <version>35</version>
         <relativePath/>
     </parent>
 
@@ -104,58 +104,47 @@
     </mailingLists>
 
     <properties>
-        <revision>4.0.0-SNAPSHOT</revision>
+        <revision>4.0.0-incubating</revision>
         <apache.commons.cli.version>1.5.0</apache.commons.cli.version>
         
<apache.commons.collections.version>4.4</apache.commons.collections.version>
         <bouncycastle.version>1.79</bouncycastle.version>
-        <caffeine.version>3.2.2</caffeine.version>
+        <caffeine.version>3.2.3</caffeine.version>
         <guice.version>7.0.0</guice.version>
-        <grpc.version>1.72.0</grpc.version>
+        <grpc.version>1.77.0</grpc.version>
         <guava.version>33.2.1-jre</guava.version>
         <jackson.version>2.18.1</jackson.version>
         <jakarta.ws.rs-api.version>4.0.0</jakarta.ws.rs-api.version>
         <lombok.version>1.18.34</lombok.version>
         <log4j.version>2.24.3</log4j.version>
         <micrometer.version>1.11.12</micrometer.version>
-        <netty.version>4.1.121.Final</netty.version>
+        <netty.version>4.1.127.Final</netty.version>
+        <tcnative.version>2.0.73.Final</tcnative.version>
         <pcollections.version>4.0.2</pcollections.version>
         <pf4j.version>3.13.0</pf4j.version>
         <protobuf-java.version>4.30.2</protobuf-java.version>
         <reflections.verion>0.10.2</reflections.verion>
         <rocksdb.version>9.7.3</rocksdb.version>
-        <rxjava3.version>3.1.10</rxjava3.version>
-        <slf4j.version>2.0.16</slf4j.version>
-        <swagger.version>2.2.30</swagger.version>
+        <rxjava3.version>3.1.12</rxjava3.version>
+        <slf4j.version>2.0.17</slf4j.version>
+        <swagger.version>2.2.40</swagger.version>
 
         <!-- test dependencies-->
-        <awaitility.version>4.2.2</awaitility.version>
+        <awaitility.version>4.3.0</awaitility.version>
         <paho.mqtt.version>1.2.5</paho.mqtt.version>
         <mockito.version>5.12.0</mockito.version>
         <testng.version>7.10.2</testng.version>
         <jmh.version>1.37</jmh.version>
 
-        <!-- maven.plugin.version-->
+        <!-- plugin.version-->
         <maven.flatten.plugin.version>1.7.1</maven.flatten.plugin.version>
-        <maven.compiler.plugin.version>3.14.0</maven.compiler.plugin.version>
         <maven.archetype.plugin.version>3.3.1</maven.archetype.plugin.version>
-        <maven.jar.plugin.version>3.4.2</maven.jar.plugin.version>
-        <maven.javadoc.plugin.version>3.11.2</maven.javadoc.plugin.version>
-        <maven.release.plugin.version>3.1.1</maven.release.plugin.version>
-        <maven.resources.plugin.version>3.3.1</maven.resources.plugin.version>
-        <maven.source.plugin.version>3.3.1</maven.source.plugin.version>
-        
<maven.dependency.plugin.version>3.8.1</maven.dependency.plugin.version>
-        <maven.assembly.plugin.version>3.7.1</maven.assembly.plugin.version>
-        <maven.surefire.plugin.version>3.5.2</maven.surefire.plugin.version>
         <maven.jacoco.plugin.version>0.8.12</maven.jacoco.plugin.version>
-        
<maven.checkstyle.plugin.version>3.6.0</maven.checkstyle.plugin.version>
-        <maven.wrapper.plugin.version>3.3.2</maven.wrapper.plugin.version>
-        <maven.gpg.plugin.version>3.2.7</maven.gpg.plugin.version>
-        
<nexus.staging.maven.plugin.version>1.6.13</nexus.staging.maven.plugin.version>
         <protobuf.plugin.version>0.6.1</protobuf.plugin.version>
         <os.plugin.version>1.6.2</os.plugin.version>
         <checkstyle.version>10.11.0</checkstyle.version>
 
         <!-- build properties -->
+        <argLine/> <!-- to be overridden in CI -->
         <maven.compiler.release>17</maven.compiler.release>
         <source.encoding>UTF-8</source.encoding>
         <release.version>${project.version}</release.version>
@@ -166,13 +155,429 @@
 
     <dependencyManagement>
         <dependencies>
-            <!-- bom modules -->
+            <!-- bifromq modules -->
+            <!-- base-env -->
             <dependency>
                 <groupId>org.apache.bifromq</groupId>
-                <artifactId>bifromq-bom</artifactId>
+                <artifactId>base-env-provider</artifactId>
+                <version>${project.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.bifromq</groupId>
+                <artifactId>base-env-provider-spi</artifactId>
+                <version>${project.version}</version>
+            </dependency>
+            <!-- base-hlc -->
+            <dependency>
+                <groupId>org.apache.bifromq</groupId>
+                <artifactId>base-hlc</artifactId>
+                <version>${project.version}</version>
+            </dependency>
+            <!-- base-logger -->
+            <dependency>
+                <groupId>org.apache.bifromq</groupId>
+                <artifactId>base-logger</artifactId>
+                <version>${project.version}</version>
+            </dependency>
+            <!-- base-rpc -->
+            <dependency>
+                <groupId>org.apache.bifromq</groupId>
+                <artifactId>base-rpc-grpc-inproc</artifactId>
+                <version>${project.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.bifromq</groupId>
+                <artifactId>base-rpc-common</artifactId>
+                <version>${project.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.bifromq</groupId>
+                <artifactId>base-rpc-client</artifactId>
+                <version>${project.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.bifromq</groupId>
+                <artifactId>base-rpc-server</artifactId>
+                <version>${project.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.bifromq</groupId>
+                <artifactId>base-rpc-traffic-governor</artifactId>
+                <version>${project.version}</version>
+            </dependency>
+            <!-- base-cluster -->
+            <dependency>
+                <groupId>org.apache.bifromq</groupId>
+                <artifactId>base-cluster</artifactId>
+                <version>${project.version}</version>
+            </dependency>
+            <!-- base-crdt -->
+            <dependency>
+                <groupId>org.apache.bifromq</groupId>
+                <artifactId>base-crdt-store</artifactId>
+                <version>${project.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.bifromq</groupId>
+                <artifactId>base-crdt-service</artifactId>
+                <version>${project.version}</version>
+            </dependency>
+            <!-- base-scheduler -->
+            <dependency>
+                <groupId>org.apache.bifromq</groupId>
+                <artifactId>base-scheduler</artifactId>
+                <version>${project.version}</version>
+            </dependency>
+            <!-- base-hookloader -->
+            <dependency>
+                <groupId>org.apache.bifromq</groupId>
+                <artifactId>base-hookloader</artifactId>
+                <version>${project.version}</version>
+            </dependency>
+            <!-- base-kv -->
+            <dependency>
+                <groupId>org.apache.bifromq</groupId>
+                <artifactId>base-kv-type-proto</artifactId>
+                <version>${project.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.bifromq</groupId>
+                <artifactId>base-kv-raft-type</artifactId>
+                <version>${project.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.bifromq</groupId>
+                <artifactId>base-kv-raft</artifactId>
+                <version>${project.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.bifromq</groupId>
+                <artifactId>base-kv-local-engine-spi</artifactId>
+                <version>${project.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.bifromq</groupId>
+                <artifactId>base-kv-local-engine-rocksdb</artifactId>
+                <version>${project.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.bifromq</groupId>
+                <artifactId>base-kv-local-engine-memory</artifactId>
+                <version>${project.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.bifromq</groupId>
+                <artifactId>base-kv-meta-service</artifactId>
+                <version>${project.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.bifromq</groupId>
+                <artifactId>base-kv-store-rpc-definition</artifactId>
+                <version>${project.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.bifromq</groupId>
+                <artifactId>base-kv-store-client</artifactId>
+                <version>${project.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.bifromq</groupId>
+                <artifactId>base-kv-store-coproc-api</artifactId>
+                <version>${project.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.bifromq</groupId>
+                <artifactId>base-kv-split-hinter-spi</artifactId>
+                <version>${project.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.bifromq</groupId>
+                <artifactId>base-kv-store-server</artifactId>
+                <version>${project.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.bifromq</groupId>
+                <artifactId>base-kv-store-balance-spi</artifactId>
+                <version>${project.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.bifromq</groupId>
+                <artifactId>base-kv-store-balance-controller</artifactId>
+                <version>${project.version}</version>
+            </dependency>
+            <!-- base-util -->
+            <dependency>
+                <groupId>org.apache.bifromq</groupId>
+                <artifactId>base-util</artifactId>
+                <version>${project.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.bifromq</groupId>
+                <artifactId>bifromq-util</artifactId>
+                <version>${project.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.bifromq</groupId>
+                <artifactId>bifromq-common-type</artifactId>
+                <version>${project.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.bifromq</groupId>
+                <artifactId>bifromq-metrics</artifactId>
+                <version>${project.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.bifromq</groupId>
+                <artifactId>bifromq-sysprops</artifactId>
+                <version>${project.version}</version>
+            </dependency>
+            <!-- bifromq-plugins -->
+            <dependency>
+                <groupId>org.apache.bifromq</groupId>
+                <artifactId>bifromq-plugin-auth-provider</artifactId>
+                <version>${project.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.bifromq</groupId>
+                <artifactId>bifromq-plugin-auth-provider-helper</artifactId>
+                <version>${project.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.bifromq</groupId>
+                <artifactId>bifromq-plugin-client-balancer</artifactId>
+                <version>${project.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.bifromq</groupId>
+                <artifactId>bifromq-plugin-client-balancer-helper</artifactId>
+                <version>${project.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.bifromq</groupId>
+                <artifactId>bifromq-plugin-event-collector</artifactId>
+                <version>${project.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.bifromq</groupId>
+                <artifactId>bifromq-plugin-event-collector-helper</artifactId>
+                <version>${project.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.bifromq</groupId>
+                <artifactId>bifromq-plugin-resource-throttler</artifactId>
+                <version>${project.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.bifromq</groupId>
+                
<artifactId>bifromq-plugin-resource-throttler-helper</artifactId>
+                <version>${project.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.bifromq</groupId>
+                <artifactId>bifromq-plugin-setting-provider</artifactId>
+                <version>${project.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.bifromq</groupId>
+                <artifactId>bifromq-plugin-setting-provider-helper</artifactId>
+                <version>${project.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.bifromq</groupId>
+                <artifactId>bifromq-plugin-sub-broker</artifactId>
+                <version>${project.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.bifromq</groupId>
+                <artifactId>bifromq-plugin-sub-broker-helper</artifactId>
+                <version>${project.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.bifromq</groupId>
+                <artifactId>bifromq-plugin-manager</artifactId>
+                <version>${project.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.bifromq</groupId>
+                <artifactId>bifromq-plugin-context</artifactId>
+                <version>${project.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.bifromq</groupId>
+                <artifactId>bifromq-plugin-main</artifactId>
+                <version>${project.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.bifromq</groupId>
+                <artifactId>bifromq-plugin-archetype</artifactId>
+                <version>${project.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.bifromq</groupId>
+                <artifactId>bifromq-deliverer</artifactId>
+                <version>${project.version}</version>
+            </dependency>
+            <!-- bifromq-retain -->
+            <dependency>
+                <groupId>org.apache.bifromq</groupId>
+                <artifactId>bifromq-retain-client</artifactId>
+                <version>${project.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.bifromq</groupId>
+                <artifactId>bifromq-retain-coproc-proto</artifactId>
+                <version>${project.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.bifromq</groupId>
+                <artifactId>bifromq-retain-rpc-definition</artifactId>
+                <version>${project.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.bifromq</groupId>
+                <artifactId>bifromq-retain-gc</artifactId>
+                <version>${project.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.bifromq</groupId>
+                <artifactId>bifromq-retain-store-spi</artifactId>
+                <version>${project.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.bifromq</groupId>
+                <artifactId>bifromq-retain-store-schema</artifactId>
+                <version>${project.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.bifromq</groupId>
+                <artifactId>bifromq-retain-store</artifactId>
+                <version>${project.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.bifromq</groupId>
+                <artifactId>bifromq-retain-server</artifactId>
+                <version>${project.version}</version>
+            </dependency>
+            <!-- bifromq-inbox -->
+            <dependency>
+                <groupId>org.apache.bifromq</groupId>
+                <artifactId>bifromq-inbox-client</artifactId>
+                <version>${project.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.bifromq</groupId>
+                <artifactId>bifromq-inbox-coproc-proto</artifactId>
+                <version>${project.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.bifromq</groupId>
+                <artifactId>bifromq-inbox-rpc-definition</artifactId>
+                <version>${project.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.bifromq</groupId>
+                <artifactId>bifromq-inbox-store-spi</artifactId>
+                <version>${project.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.bifromq</groupId>
+                <artifactId>bifromq-inbox-store</artifactId>
+                <version>${project.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.bifromq</groupId>
+                <artifactId>bifromq-inbox-store-schema</artifactId>
+                <version>${project.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.bifromq</groupId>
+                <artifactId>bifromq-inbox-server</artifactId>
+                <version>${project.version}</version>
+            </dependency>
+            <!-- bifromq-dist -->
+            <dependency>
+                <groupId>org.apache.bifromq</groupId>
+                <artifactId>bifromq-dist-client</artifactId>
+                <version>${project.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.bifromq</groupId>
+                <artifactId>bifromq-dist-worker-spi</artifactId>
+                <version>${project.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.bifromq</groupId>
+                <artifactId>bifromq-dist-worker</artifactId>
+                <version>${project.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.bifromq</groupId>
+                <artifactId>bifromq-dist-server</artifactId>
+                <version>${project.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.bifromq</groupId>
+                <artifactId>bifromq-dist-rpc-definition</artifactId>
+                <version>${project.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.bifromq</groupId>
+                <artifactId>bifromq-dist-coproc-proto</artifactId>
+                <version>${project.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.bifromq</groupId>
+                <artifactId>bifromq-dist-worker-schema</artifactId>
+                <version>${project.version}</version>
+            </dependency>
+            <!-- bifromq-session-dict -->
+            <dependency>
+                <groupId>org.apache.bifromq</groupId>
+                <artifactId>bifromq-session-dict-client</artifactId>
+                <version>${project.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.bifromq</groupId>
+                <artifactId>bifromq-session-dict-server</artifactId>
+                <version>${project.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.bifromq</groupId>
+                <artifactId>bifromq-session-dict-rpc-definition</artifactId>
+                <version>${project.version}</version>
+            </dependency>
+            <!-- bifromq-mqtt -->
+            <dependency>
+                <groupId>org.apache.bifromq</groupId>
+                <artifactId>bifromq-mqtt-broker-client</artifactId>
+                <version>${project.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.bifromq</groupId>
+                <artifactId>bifromq-mqtt-server-spi</artifactId>
+                <version>${project.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.bifromq</groupId>
+                <artifactId>bifromq-mqtt-broker-rpc-definition</artifactId>
+                <version>${project.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.bifromq</groupId>
+                <artifactId>bifromq-mqtt-server</artifactId>
+                <version>${project.version}</version>
+            </dependency>
+            <!-- bifromq-api -->
+            <dependency>
+                <groupId>org.apache.bifromq</groupId>
+                <artifactId>bifromq-apiserver</artifactId>
+                <version>${project.version}</version>
+            </dependency>
+            <!-- bifromq-demo -->
+            <dependency>
+                <groupId>org.apache.bifromq</groupId>
+                <artifactId>build-plugin-demo</artifactId>
                 <version>${project.version}</version>
-                <scope>import</scope>
-                <type>pom</type>
             </dependency>
             <!-- 3rd party modules -->
             <dependency>
@@ -431,7 +836,6 @@
                 <plugin>
                     <groupId>org.apache.maven.plugins</groupId>
                     <artifactId>maven-compiler-plugin</artifactId>
-                    <version>${maven.compiler.plugin.version}</version>
                     <configuration>
                         <release>${maven.compiler.release}</release>
                         <encoding>${source.encoding}</encoding>
@@ -457,12 +861,10 @@
                 <plugin>
                     <groupId>org.apache.maven.plugins</groupId>
                     <artifactId>maven-jar-plugin</artifactId>
-                    <version>${maven.jar.plugin.version}</version>
                 </plugin>
                 <plugin>
                     <groupId>org.apache.maven.plugins</groupId>
                     <artifactId>maven-javadoc-plugin</artifactId>
-                    <version>${maven.javadoc.plugin.version}</version>
                     <configuration>
                         <release>${maven.compiler.release}</release>
                         <!--  keep only errors and warnings  -->
@@ -499,12 +901,10 @@
                 <plugin>
                     <groupId>org.apache.maven.plugins</groupId>
                     <artifactId>maven-release-plugin</artifactId>
-                    <version>${maven.release.plugin.version}</version>
                 </plugin>
                 <plugin>
                     <groupId>org.apache.maven.plugins</groupId>
                     <artifactId>maven-resources-plugin</artifactId>
-                    <version>${maven.resources.plugin.version}</version>
                     <configuration>
                         <encoding>${source.encoding}</encoding>
                     </configuration>
@@ -512,43 +912,22 @@
                 <plugin>
                     <groupId>org.apache.maven.plugins</groupId>
                     <artifactId>maven-source-plugin</artifactId>
-                    <version>${maven.source.plugin.version}</version>
-                    <configuration>
-                        <attach>true</attach>
-                        <archive>
-                            <manifest>
-                                
<addDefaultImplementationEntries>true</addDefaultImplementationEntries>
-                                
<addDefaultSpecificationEntries>true</addDefaultSpecificationEntries>
-                            </manifest>
-                        </archive>
-                    </configuration>
-                    <executions>
-                        <execution>
-                            <id>maven-source-plugin</id>
-                            <phase>compile</phase>
-                            <goals>
-                                <goal>jar</goal>
-                            </goals>
-                        </execution>
-                    </executions>
                 </plugin>
                 <plugin>
                     <groupId>org.apache.maven.plugins</groupId>
                     <artifactId>maven-dependency-plugin</artifactId>
-                    <version>${maven.dependency.plugin.version}</version>
                 </plugin>
                 <plugin>
                     <groupId>org.apache.maven.plugins</groupId>
                     <artifactId>maven-assembly-plugin</artifactId>
-                    <version>${maven.assembly.plugin.version}</version>
                 </plugin>
                 <plugin>
                     <groupId>org.apache.maven.plugins</groupId>
                     <artifactId>maven-surefire-plugin</artifactId>
-                    <version>${maven.surefire.plugin.version}</version>
+                    <version>${version.maven-surefire}</version>
                     <configuration>
                         <argLine>
-                            ${argLine} -XX:+EnableDynamicAgentLoading 
-Djdk.instrument.traceUsage=false
+                            @{argLine} -XX:+EnableDynamicAgentLoading 
-Djdk.instrument.traceUsage=false
                         </argLine>
                         <excludes>
                             <exclude>**/benchmark/**</exclude>
@@ -565,7 +944,6 @@
                 <plugin>
                     <groupId>org.apache.maven.plugins</groupId>
                     <artifactId>maven-checkstyle-plugin</artifactId>
-                    <version>${maven.checkstyle.plugin.version}</version>
                     <dependencies>
                         <dependency>
                             <groupId>com.puppycrawl.tools</groupId>
@@ -594,7 +972,6 @@
                 <plugin>
                     <groupId>org.apache.maven.plugins</groupId>
                     <artifactId>maven-wrapper-plugin</artifactId>
-                    <version>${maven.wrapper.plugin.version}</version>
                 </plugin>
                 <plugin>
                     <groupId>org.xolstice.maven.plugins</groupId>
@@ -706,12 +1083,6 @@
     </reporting>
 
     <profiles>
-        <profile>
-            <id>local</id>
-            <activation>
-                <activeByDefault>true</activeByDefault>
-            </activation>
-        </profile>
         <profile>
             <id>build</id>
             <build>
@@ -756,5 +1127,101 @@
                 </plugins>
             </build>
         </profile>
+        <profile>
+            <id>build-release</id>
+            <build>
+                <plugins>
+                    <plugin>
+                        <groupId>org.apache.maven.plugins</groupId>
+                        <artifactId>maven-assembly-plugin</artifactId>
+                        <executions>
+                            <execution>
+                                <id>source-release-tarball</id>
+                                <inherited>false</inherited>
+                                <phase>package</phase>
+                                <goals>
+                                    <goal>single</goal>
+                                </goals>
+                                <configuration>
+                                    
<runOnlyAtExecutionRoot>true</runOnlyAtExecutionRoot>
+                                    <descriptors>
+                                        
<descriptor>${project.basedir}/release/source-assembly.xml</descriptor>
+                                    </descriptors>
+                                    <appendAssemblyId>false</appendAssemblyId>
+                                    
<finalName>apache-bifromq-${project.version}-src</finalName>
+                                    
<outputDirectory>${build.output.dir}</outputDirectory>
+                                    <tarLongFileMode>posix</tarLongFileMode>
+                                </configuration>
+                            </execution>
+                        </executions>
+                    </plugin>
+                    <plugin>
+                        <groupId>org.apache.maven.plugins</groupId>
+                        <artifactId>maven-antrun-plugin</artifactId>
+                        <executions>
+                            <execution>
+                                <id>checksum-release-artifacts</id>
+                                <inherited>false</inherited>
+                                <phase>verify</phase>
+                                <goals>
+                                    <goal>run</goal>
+                                </goals>
+                                <configuration>
+                                    <target>
+                                        <exec executable="bash" 
failonerror="true">
+                                            <arg 
value="${maven.multiModuleProjectDirectory}/release/checksum-artifacts.sh"/>
+                                            <arg value="${build.output.dir}"/>
+                                        </exec>
+                                    </target>
+                                </configuration>
+                            </execution>
+                        </executions>
+                    </plugin>
+                    <plugin>
+                        <groupId>org.apache.rat</groupId>
+                        <artifactId>apache-rat-plugin</artifactId>
+                        <executions>
+                            <execution>
+                                <id>rat-check</id>
+                                <inherited>false</inherited>
+                                <phase>verify</phase>
+                                <goals>
+                                    <goal>check</goal>
+                                </goals>
+                                <configuration>
+                                    <excludes>
+                                        <exclude>.github/**</exclude>
+                                        <exclude>.gitignore</exclude>
+                                        <exclude>.gitattributes</exclude>
+                                        <exclude>**/target/**</exclude>
+                                        <exclude>**/.idea/**</exclude>
+                                        <exclude>**/*.iml</exclude>
+                                        <exclude>**/.run/**</exclude>
+                                        <exclude>**/.mvn/**</exclude>
+                                        <exclude>**/.tmp/**</exclude>
+                                        <exclude>**/.git/**</exclude>
+                                        <exclude>**/.DS_Store</exclude>
+                                        <exclude>lombok.config</exclude>
+                                        <exclude>META-INF/**</exclude>
+                                        <exclude>**/META-INF/**</exclude>
+                                        
<exclude>**/resources/META-INF/**</exclude>
+                                        <exclude>**/*.crt</exclude>
+                                        <exclude>**/*.pem</exclude>
+                                        <exclude>**/MANIFEST.MF</exclude>
+                                        <exclude>**/*.md</exclude>
+                                        <exclude>licenses/*.txt</exclude>
+                                        <exclude>DISCLAIMER</exclude>
+                                        <exclude>LICENSE</exclude>
+                                        <exclude>LICENSE-Binary</exclude>
+                                        <exclude>NOTICE</exclude>
+                                        <exclude>NOTICE-Binary</exclude>
+                                    </excludes>
+                                </configuration>
+                            </execution>
+                        </executions>
+                    </plugin>
+                </plugins>
+            </build>
+        </profile>
     </profiles>
 </project>
diff --git a/release/checksum-artifacts.sh b/release/checksum-artifacts.sh
new file mode 100644
index 000000000..7262dfff3
--- /dev/null
+++ b/release/checksum-artifacts.sh
@@ -0,0 +1,36 @@
+#!/usr/bin/env bash
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+# 
+#   http://www.apache.org/licenses/LICENSE-2.0
+# 
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+set -euo pipefail
+
+out_dir="${1:?output dir required}"
+
+shopt -s nullglob
+files=("${out_dir}"/*.tar.gz "${out_dir}"/*.zip)
+shopt -u nullglob
+
+if [[ ${#files[@]} -eq 0 ]]; then
+  echo "No release artifacts found in ${out_dir}"
+  exit 1
+fi
+
+for f in "${files[@]}"; do
+  shasum -a 512 "$f" > "${f}.sha512"
+done
diff --git a/release/docker-build.sh b/release/docker-build.sh
new file mode 100755
index 000000000..e3918dd3c
--- /dev/null
+++ b/release/docker-build.sh
@@ -0,0 +1,90 @@
+#!/usr/bin/env bash
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+# 
+#   http://www.apache.org/licenses/LICENSE-2.0
+# 
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+set -euo pipefail
+
+usage() {
+  echo "Usage: $(basename "$0") [-t tag] 
<path-to-apache-bifromq-VERSION.tar.gz>" >&2
+  exit 1
+}
+
+tag_override=""
+target_arch="${TARGETARCH:-}"
+
+while getopts ":t:a:h" opt; do
+  case "$opt" in
+    t) tag_override="$OPTARG" ;;
+    a) target_arch="$OPTARG" ;;
+    h) usage ;;
+    *) usage ;;
+  esac
+done
+shift $((OPTIND - 1))
+
+[[ $# -eq 1 ]] || usage
+
+artifact_path="$1"
+
+if [[ ! -f "$artifact_path" ]]; then
+  echo "Error: artifact not found: $artifact_path" >&2
+  exit 1
+fi
+
+artifact_dir="$(cd "$(dirname "$artifact_path")" && pwd)"
+artifact_file="$(basename "$artifact_path")"
+
+if [[ "$artifact_file" =~ ^apache-bifromq-(.+)\.tar\.gz$ ]]; then
+  version="${BASH_REMATCH[1]}"
+else
+  echo "Error: artifact name must match apache-bifromq-<VERSION>.tar.gz" >&2
+  exit 1
+fi
+
+sha_file="${artifact_dir}/${artifact_file}.sha512"
+if [[ ! -f "$sha_file" ]]; then
+  echo "Error: checksum file missing: ${sha_file}" >&2
+  exit 1
+fi
+
+repo_root="$(cd "$(dirname "$0")/.." && pwd)"
+dockerfile="${repo_root}/Dockerfile"
+
+if [[ ! -f "$dockerfile" ]]; then
+  echo "Error: Dockerfile not found at ${dockerfile}" >&2
+  exit 1
+fi
+
+context_dir="$artifact_dir"
+tag="${tag_override:-apache-bifromq:${version}}"
+
+if [[ -z "$target_arch" ]]; then
+  machine=$(uname -m)
+  case "$machine" in
+    x86_64|amd64) target_arch="amd64" ;;
+    aarch64|arm64|arm64e) target_arch="arm64" ;;
+    *) echo "Error: unsupported machine architecture: ${machine}. Set 
TARGETARCH explicitly." >&2; exit 1 ;;
+  esac
+fi
+
+docker build -f "$dockerfile" \
+  --build-arg BIFROMQ_VERSION="$version" \
+  --build-arg TARGETARCH="$target_arch" \
+  -t "$tag" \
+  "$context_dir"
diff --git a/release/release.sh b/release/release.sh
index 21952b47d..ac3de2f70 100755
--- a/release/release.sh
+++ b/release/release.sh
@@ -23,13 +23,15 @@
 # Print usage information
 usage() {
   cat <<EOF
-Usage: $(basename "$0") <release-branch> [<svn-username> <svn-password>]
+Usage: $(basename "$0") <release-branch> [--upload] [--gpg-passphrase <pass>] 
[<svn-username> <svn-password>]
   <release-branch>   Release branch in format release-v<major>.<minor>.x (e.g. 
release-v4.0.x)
+  --upload           (Optional) Upload artifacts to Apache dist/dev SVN
+  --gpg-passphrase   (Optional) GPG passphrase used for signing
   <svn-username>      (Optional) SVN username for committing to Apache Dev repo
   <svn-password>      (Optional) SVN password for committing to Apache Dev repo
 
 Example:
-  $(basename "$0") release-v4.0.x my_user my_password
+  $(basename "$0") release-v1.0.x-incubating --upload my_user my_password
 EOF
 }
 
@@ -42,90 +44,152 @@ fi
 set -e
 
 # =====================================================
-# BifroMQ ASF Release Tool
+# Apache BifroMQ Release Tool
 # =====================================================
 
 PROJECT_NAME="bifromq"
 
ASF_SVN_DEV_URL="https://dist.apache.org/repos/dist/dev/incubator/${PROJECT_NAME}";
 
 BRANCH="$1"
-USERNAME=$2
-PASSWORD=$3
+UPLOAD=false
+USERNAME=""
+PASSWORD=""
+GPG_PASSPHRASE=""
+SCRIPT_DIR=$(cd "$(dirname "$0")" && pwd)
+
+verify_gpg_access() {
+  local pass="$1"
+  local sign_cmd=(gpg --armor --batch --yes --pinentry-mode loopback --sign)
+  if [[ -n "$pass" ]]; then
+    if ! echo test | "${sign_cmd[@]}" --passphrase "$pass" >/dev/null 2>&1; 
then
+      echo "ERROR: Provided GPG passphrase is invalid or key is not 
accessible."
+      exit 1
+    fi
+  else
+    if ! echo test | "${sign_cmd[@]}" >/dev/null 2>&1; then
+      echo "ERROR: GPG passphrase required. Provide it via --gpg-passphrase or 
ensure gpg-agent has it cached."
+      exit 1
+    fi
+  fi
+}
+
+shift
+while [[ $# -gt 0 ]]; do
+  case "$1" in
+    --upload)
+      UPLOAD=true
+      shift
+      ;;
+    --gpg-passphrase)
+      shift
+      if [[ -z "${1:-}" ]]; then
+        echo "ERROR: --gpg-passphrase requires a value"
+        usage
+        exit 1
+      fi
+      GPG_PASSPHRASE="$1"
+      shift
+      ;;
+    *)
+      if [[ -z "$USERNAME" ]]; then
+        USERNAME="$1"
+      elif [[ -z "$PASSWORD" ]]; then
+        PASSWORD="$1"
+      else
+        echo "ERROR: Too many arguments"
+        usage
+        exit 1
+      fi
+      shift
+      ;;
+  esac
+done
 
-if [[ ! "$BRANCH" =~ ^release-v([0-9]+)\.([0-9]+)\.x$ ]]; then
-  echo "ERROR: Branch name must follow release-v<major>.<minor>.x format (e.g. 
release-v4.0.x)"
+if [[ ! "$BRANCH" =~ ^release-v([0-9]+)\.([0-9]+)\.x.*$ ]]; then
+  echo "ERROR: Branch name must follow release-v<major>.<minor>.x format (e.g. 
release-v4.0.x or release-v1.0.0-incubating)"
   exit 1
 fi
 
-MAJOR="${BASH_REMATCH[1]}"
-MINOR="${BASH_REMATCH[2]}"
-MAJOR_MINOR="${MAJOR}.${MINOR}"
-
-WORKDIR=$(pwd)
+WORKDIR="${SCRIPT_DIR}/output"
+mkdir -p "$WORKDIR"
 TMPDIR=$(mktemp -d)
 trap 'rm -rf "$TMPDIR"' EXIT
 
 command -v gpg >/dev/null || { echo "GPG is required but not installed."; exit 
1; }
+export GPG_TTY=${GPG_TTY:-$(tty)}
+gpg --list-secret-keys --with-colons | grep -q '^sec' || { echo "ERROR: No GPG 
secret key found for signing."; exit 1; }
+verify_gpg_access "$GPG_PASSPHRASE"
 
-echo "Cloning repository..."
+echo "Cloning repository to temp dir..."
 cd "$TMPDIR"
 git clone https://github.com/apache/${PROJECT_NAME}.git repo
 cd repo
 git checkout "$BRANCH"
 
-echo "Locating latest tag for branch $BRANCH..."
-LATEST_TAG=$(git tag --list "v${MAJOR_MINOR}.*" --sort=-v:refname | head -n 1)
-if [ -z "$LATEST_TAG" ]; then
-  echo "ERROR: No matching tag found."
+echo "Reading revision from POM..."
+REVISION=$(xmllint --xpath 
"string(//*[local-name()='project']/*[local-name()='properties']/*[local-name()='revision'])"
 pom.xml)
+if [[ -z "$REVISION" ]]; then
+  echo "ERROR: Cannot read revision from pom.xml"
   exit 1
 fi
-echo "Found tag: $LATEST_TAG"
-git checkout "$LATEST_TAG"
 
-# remove prefix 'v' from tag
-VERSION="${LATEST_TAG#v}"
+TAG="v${REVISION}"
+if ! git rev-parse -q --verify "refs/tags/${TAG}" >/dev/null; then
+  echo "ERROR: Tag ${TAG} not found"
+  exit 1
+fi
 
-POM_VERSION=$(xmllint --xpath "string(//project/properties/revision)" pom.xml)
-if [ "$POM_VERSION" != "$VERSION" ]; then
-  echo "ERROR: POM revision ($POM_VERSION) doesn't match tag version 
($VERSION)"
+if ! git merge-base --is-ancestor "${TAG}" "${BRANCH}"; then
+  echo "ERROR: Tag ${TAG} is not reachable from branch ${BRANCH}"
   exit 1
 fi
 
+echo "Checking out tag ${TAG}..."
+git checkout "${TAG}"
+
 echo "ASF required file check..."
 for f in LICENSE NOTICE DISCLAIMER; do
   [ -f "$f" ] || { echo "Missing $f file."; exit 1; }
 done
 
-SRC_DIR="${PROJECT_NAME}-${VERSION}-src"
-SRC_TARBALL="${SRC_DIR}.tar.gz"
-git archive --format=tar.gz --prefix="${SRC_DIR}/" -o "$WORKDIR/$SRC_TARBALL" 
"$LATEST_TAG"
-
-echo "Building binary via Maven..."
-mvn clean package -DskipTests
-
-cd "$WORKDIR"
-cp "$TMPDIR/repo/target/output/bifromq-*.*" "${WORKDIR}"
-
-cd "$WORKDIR"
-find . -maxdepth 1 -type f ! -name '*.asc' ! -name '*.sha512' -print0 | while 
IFS= read -r -d '' ARTIFACT; do
-  gpg --armor --output "${ARTIFACT}.asc" --detach-sign "$ARTIFACT"
-  shasum -a 512 "$ARTIFACT" > "${ARTIFACT}.sha512"
+echo "Running Maven build (build-release profile)..."
+echo "You may be prompted for GPG passphrase by gpg-agent/pinentry."
+MVN_ARGS=(-Pbuild-release -DskipTests)
+if [[ -n "$GPG_PASSPHRASE" ]]; then
+  MVN_ARGS+=("-Dgpg.passphrase=${GPG_PASSPHRASE}")
+fi
+mvn "${MVN_ARGS[@]}" clean verify
+
+cd "$TMPDIR/repo"
+ARTIFACTS=(target/output/apache-bifromq-*.tar.gz 
target/output/apache-bifromq-*.zip)
+ls "${ARTIFACTS[@]}" 2>/dev/null || { echo "No artifacts found under 
target/output"; exit 1; }
+for f in target/output/*; do
+  if [[ -f "$f" ]]; then
+    cp "$f" "$WORKDIR"
+  fi
 done
 
-SVN_TMP=$(mktemp -d)
-svn checkout "$ASF_SVN_DEV_URL" "$SVN_TMP"
-mkdir -p "$SVN_TMP/$VERSION"
-cp "$WORKDIR"/* "$SVN_TMP/$VERSION/"
-cd "$SVN_TMP"
-svn add --force "$VERSION"
-svn status
-
-if [ "$USERNAME" = "" ]; then
-  svn commit -m "Add release ${VERSION}" || exit
+echo "Signing artifacts..."
+bash "${SCRIPT_DIR}/sign-artifacts.sh" "$WORKDIR" "$GPG_PASSPHRASE"
+
+if [ "$UPLOAD" = true ]; then
+  SVN_TMP=$(mktemp -d)
+  svn checkout "$ASF_SVN_DEV_URL" "$SVN_TMP"
+  mkdir -p "$SVN_TMP/${REVISION}"
+  cp target/output/* "$SVN_TMP/${REVISION}/"
+  cd "$SVN_TMP"
+  svn add --force "${REVISION}"
+  svn status
+  if [ "$USERNAME" = "" ]; then
+    svn commit -m "Add release ${REVISION}" || exit
+  else
+    svn commit -m "Add release ${REVISION}" --username "${USERNAME}" 
--password "${PASSWORD}" || exit
+  fi
+  echo "Artifacts uploaded to SVN dev: ${REVISION}"
 else
-  svn commit -m "Add release ${VERSION}" --username "${USERNAME}" --password 
"${PASSWORD}" || exit
+  echo "Artifacts generated under target/output and copied to $WORKDIR. Use 
--upload to push to SVN."
 fi
 
 echo "========================================================="
-echo "BifroMQ release $VERSION has been successfully created."
-echo "========================================================="
\ No newline at end of file
+echo "Apache BifroMQ release ${REVISION} build completed."
+echo "========================================================="
diff --git a/release/sign-artifacts.sh b/release/sign-artifacts.sh
new file mode 100755
index 000000000..bb8380da0
--- /dev/null
+++ b/release/sign-artifacts.sh
@@ -0,0 +1,44 @@
+#!/usr/bin/env bash
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+set -euo pipefail
+
+# Usage: sign-artifacts.sh <output-dir> [<gpg-passphrase>]
+
+out_dir="${1:?output dir required}"
+gpg_passphrase="${2:-}"
+
+shopt -s nullglob
+files=("${out_dir}"/*.tar.gz "${out_dir}"/*.zip)
+shopt -u nullglob
+
+if [[ ${#files[@]} -eq 0 ]]; then
+  echo "No release artifacts found in ${out_dir}"
+  exit 1
+fi
+
+for f in "${files[@]}"; do
+  if [[ -n "${gpg_passphrase}" ]]; then
+    gpg --batch --yes --pinentry-mode loopback --passphrase 
"${gpg_passphrase}" --armor --detach-sign "$f"
+  else
+    gpg --batch --yes --pinentry-mode loopback --armor --detach-sign "$f"
+  fi
+  shasum -a 512 "$f" > "${f}.sha512"
+done
diff --git a/release/source-assembly.xml b/release/source-assembly.xml
new file mode 100644
index 000000000..7849dd732
--- /dev/null
+++ b/release/source-assembly.xml
@@ -0,0 +1,64 @@
+<!--
+  ~ Licensed to the Apache Software Foundation (ASF) under one
+  ~ or more contributor license agreements.  See the NOTICE file
+  ~ distributed with this work for additional information
+  ~ regarding copyright ownership.  The ASF licenses this file
+  ~ to you under the Apache License, Version 2.0 (the
+  ~ "License"); you may not use this file except in compliance
+  ~ with the License.  You may obtain a copy of the License at
+  ~
+  ~   http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing,
+  ~ software distributed under the License is distributed on an
+  ~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  ~ KIND, either express or implied.  See the License for the
+  ~ specific language governing permissions and limitations
+  ~ under the License.
+  -->
+<assembly xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";
+          
xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.3";
+          
xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.3
 https://maven.apache.org/xsd/assembly-1.1.3.xsd";>
+    <id>source-release</id>
+    <formats>
+        <format>tar.gz</format>
+    </formats>
+    <includeBaseDirectory>true</includeBaseDirectory>
+    <fileSets>
+        <fileSet>
+            <directory>${project.basedir}</directory>
+            <outputDirectory>/</outputDirectory>
+            <useDefaultExcludes>true</useDefaultExcludes>
+            <excludes>
+                <exclude>.mvn/**</exclude>
+                <exclude>.git/**</exclude>
+                <exclude>.github/**</exclude>
+                <exclude>output/**</exclude>
+                <exclude>**/target/**</exclude>
+                <exclude>*.war</exclude>
+                <exclude>*.zip</exclude>
+                <exclude>*.tar</exclude>
+                <exclude>*.tar.gz</exclude>
+                <exclude>.flattened-pom.xml</exclude>
+                <exclude>tree.txt</exclude>
+                <exclude>.settings/**</exclude>
+                <exclude>.project</exclude>
+                <exclude>.classpath</exclude>
+                <exclude>.idea/**</exclude>
+                <exclude>*.iml</exclude>
+                <exclude>.run/**</exclude>
+                <exclude>*.ipr</exclude>
+                <exclude>*.iws</exclude>
+                <exclude>.tmp/**</exclude>
+                <exclude>*.log</exclude>
+                <exclude>*.cache</exclude>
+                <exclude>*.diff</exclude>
+                <exclude>*.patch</exclude>
+                <exclude>*.tmp</exclude>
+                <exclude>.DS_Store</exclude>
+                <exclude>**/.DS_Store</exclude>
+                <exclude>Thumbs.db</exclude>
+            </excludes>
+        </fileSet>
+    </fileSets>
+</assembly>

Reply via email to