From 71dd48f5f512cc86696170efb7e445195f81d5b1 Mon Sep 17 00:00:00 2001 From: bouhamza abderrahmane Date: Thu, 19 Mar 2026 04:07:22 +0100 Subject: [PATCH 1/9] feat: update Dockerfile to include build-essential --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 1f4f394..2a5a81d 100644 --- a/Dockerfile +++ b/Dockerfile @@ -3,7 +3,7 @@ FROM python:3.12-slim # Install PostgreSQL client libraries and build tools RUN apt-get update \ - && apt-get install -y --no-install-recommends libpq-dev gcc \ + && apt-get install -y --no-install-recommends libpq-dev build-essential \ && rm -rf /var/lib/apt/lists/* ENV PYTHONDONTWRITEBYTECODE=1 From cf721d2a888fc0e54ca4044a71982e1692638347 Mon Sep 17 00:00:00 2001 From: bouhamza abderrahmane Date: Thu, 19 Mar 2026 04:07:26 +0100 Subject: [PATCH 2/9] feat: add GitHub Actions workflow for Docker image build and push --- .github/workflows/docker-publish.yml | 44 ++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 .github/workflows/docker-publish.yml diff --git a/.github/workflows/docker-publish.yml b/.github/workflows/docker-publish.yml new file mode 100644 index 0000000..b9415a0 --- /dev/null +++ b/.github/workflows/docker-publish.yml @@ -0,0 +1,44 @@ +name: Build and Push Docker Image + +on: + push: + branches: + - main + workflow_dispatch: + +permissions: + contents: read + packages: write + +jobs: + build-and-push: + runs-on: ubuntu-latest + env: + IMAGE_NAME: ghcr.io/${{ github.repository }} + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Set image name + shell: bash + run: | + echo "IMAGE_NAME=ghcr.io/${GITHUB_REPOSITORY,,}" >> "$GITHUB_ENV" + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Login to GHCR + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GHCR_PAT }} + + - name: Build and push + uses: docker/build-push-action@v5 + with: + context: . + push: true + tags: | + ${{ env.IMAGE_NAME }}:latest + ${{ env.IMAGE_NAME }}:${{ github.sha }} From 161eff1a048e1b7313e6b116318cc371aa178170 Mon Sep 17 00:00:00 2001 From: bouhamza abderrahmane Date: Thu, 19 Mar 2026 21:13:00 +0100 Subject: [PATCH 3/9] chore: exclude env files from Docker build context --- .dockerignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.dockerignore b/.dockerignore index f8ffc8f..84a857e 100644 --- a/.dockerignore +++ b/.dockerignore @@ -13,4 +13,6 @@ __pycache__ *.db *.sqlite3 .env +.env.staging +.env.* db/schema.sql From a3daa627a1ac3820b0843f0a808630390091349e Mon Sep 17 00:00:00 2001 From: bouhamza abderrahmane Date: Thu, 19 Mar 2026 21:13:10 +0100 Subject: [PATCH 4/9] build: update system libs for headless OpenCV --- Dockerfile | 1 + 1 file changed, 1 insertion(+) diff --git a/Dockerfile b/Dockerfile index 2a5a81d..076b031 100644 --- a/Dockerfile +++ b/Dockerfile @@ -4,6 +4,7 @@ FROM python:3.12-slim # Install PostgreSQL client libraries and build tools RUN apt-get update \ && apt-get install -y --no-install-recommends libpq-dev build-essential \ + libglib2.0-0 libgfortran5 \ && rm -rf /var/lib/apt/lists/* ENV PYTHONDONTWRITEBYTECODE=1 From 5ee394ecfd5e57436495971e2375136387b99253 Mon Sep 17 00:00:00 2001 From: bouhamza abderrahmane Date: Thu, 19 Mar 2026 21:13:21 +0100 Subject: [PATCH 5/9] deps: switch to opencv-python-headless --- pyproject.toml | 2 +- uv.lock | 22 ++-------------------- 2 files changed, 3 insertions(+), 21 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 0f87619..ddf1649 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -21,7 +21,7 @@ dependencies = [ "pyotp>=2.9.0", "redis>=7.2.1", "setuptools>=82.0.0", - "opencv-python>=4.13.0.92", + "opencv-python-headless>=4.13.0.92", "numpy>=2.4.3", "insightface>=0.7.3", "onnxruntime>=1.24.4", diff --git a/uv.lock b/uv.lock index c5f1f36..e758c3d 100644 --- a/uv.lock +++ b/uv.lock @@ -311,7 +311,7 @@ dependencies = [ { name = "nats-py" }, { name = "numpy" }, { name = "onnxruntime" }, - { name = "opencv-python" }, + { name = "opencv-python-headless" }, { name = "passlib", extra = ["bcrypt"] }, { name = "psycopg" }, { name = "pydantic" }, @@ -342,7 +342,7 @@ requires-dist = [ { name = "nats-py", specifier = ">=2.14.0" }, { name = "numpy", specifier = ">=2.4.3" }, { name = "onnxruntime", specifier = ">=1.24.4" }, - { name = "opencv-python", specifier = ">=4.13.0.92" }, + { name = "opencv-python-headless", specifier = ">=4.13.0.92" }, { name = "passlib", extras = ["bcrypt"], specifier = ">=1.7.4" }, { name = "psycopg", specifier = ">=3.3.3" }, { name = "pydantic", specifier = ">=2.12.5" }, @@ -1852,24 +1852,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/6c/1d/1666dc64e78d8587d168fec4e3b7922b92eb286a2ddeebcf6acb55c7dc82/onnxruntime-1.24.4-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e1cc6a518255f012134bc791975a6294806be9a3b20c4a54cca25194c90cf731", size = 17247021, upload-time = "2026-03-17T22:04:52.377Z" }, ] -[[package]] -name = "opencv-python" -version = "4.13.0.92" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "numpy" }, -] -wheels = [ - { url = "https://files.pythonhosted.org/packages/fc/6f/5a28fef4c4a382be06afe3938c64cc168223016fa520c5abaf37e8862aa5/opencv_python-4.13.0.92-cp37-abi3-macosx_13_0_arm64.whl", hash = "sha256:caf60c071ec391ba51ed00a4a920f996d0b64e3e46068aac1f646b5de0326a19", size = 46247052, upload-time = "2026-02-05T07:01:25.046Z" }, - { url = "https://files.pythonhosted.org/packages/08/ac/6c98c44c650b8114a0fb901691351cfb3956d502e8e9b5cd27f4ee7fbf2f/opencv_python-4.13.0.92-cp37-abi3-macosx_14_0_x86_64.whl", hash = "sha256:5868a8c028a0b37561579bfb8ac1875babdc69546d236249fff296a8c010ccf9", size = 32568781, upload-time = "2026-02-05T07:01:41.379Z" }, - { url = "https://files.pythonhosted.org/packages/3e/51/82fed528b45173bf629fa44effb76dff8bc9f4eeaee759038362dfa60237/opencv_python-4.13.0.92-cp37-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:0bc2596e68f972ca452d80f444bc404e08807d021fbba40df26b61b18e01838a", size = 47685527, upload-time = "2026-02-05T06:59:11.24Z" }, - { url = "https://files.pythonhosted.org/packages/db/07/90b34a8e2cf9c50fe8ed25cac9011cde0676b4d9d9c973751ac7616223a2/opencv_python-4.13.0.92-cp37-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:402033cddf9d294693094de5ef532339f14ce821da3ad7df7c9f6e8316da32cf", size = 70460872, upload-time = "2026-02-05T06:59:19.162Z" }, - { url = "https://files.pythonhosted.org/packages/02/6d/7a9cc719b3eaf4377b9c2e3edeb7ed3a81de41f96421510c0a169ca3cfd4/opencv_python-4.13.0.92-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:bccaabf9eb7f897ca61880ce2869dcd9b25b72129c28478e7f2a5e8dee945616", size = 46708208, upload-time = "2026-02-05T06:59:15.419Z" }, - { url = "https://files.pythonhosted.org/packages/fd/55/b3b49a1b97aabcfbbd6c7326df9cb0b6fa0c0aefa8e89d500939e04aa229/opencv_python-4.13.0.92-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:620d602b8f7d8b8dab5f4b99c6eb353e78d3fb8b0f53db1bd258bb1aa001c1d5", size = 72927042, upload-time = "2026-02-05T06:59:23.389Z" }, - { url = "https://files.pythonhosted.org/packages/fb/17/de5458312bcb07ddf434d7bfcb24bb52c59635ad58c6e7c751b48949b009/opencv_python-4.13.0.92-cp37-abi3-win32.whl", hash = "sha256:372fe164a3148ac1ca51e5f3ad0541a4a276452273f503441d718fab9c5e5f59", size = 30932638, upload-time = "2026-02-05T07:02:14.98Z" }, - { url = "https://files.pythonhosted.org/packages/e9/a5/1be1516390333ff9be3a9cb648c9f33df79d5096e5884b5df71a588af463/opencv_python-4.13.0.92-cp37-abi3-win_amd64.whl", hash = "sha256:423d934c9fafb91aad38edf26efb46da91ffbc05f3f59c4b0c72e699720706f5", size = 40212062, upload-time = "2026-02-05T07:02:12.724Z" }, -] - [[package]] name = "opencv-python-headless" version = "4.13.0.92" From 62ab60a511a3408bcdb8f02849831f7d2b93e414 Mon Sep 17 00:00:00 2001 From: bouhamza abderrahmane Date: Thu, 19 Mar 2026 21:22:43 +0100 Subject: [PATCH 6/9] ci: publish linux/amd64 and linux/arm64 images --- .github/workflows/docker-publish.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/docker-publish.yml b/.github/workflows/docker-publish.yml index b9415a0..840f3c8 100644 --- a/.github/workflows/docker-publish.yml +++ b/.github/workflows/docker-publish.yml @@ -24,6 +24,9 @@ jobs: run: | echo "IMAGE_NAME=ghcr.io/${GITHUB_REPOSITORY,,}" >> "$GITHUB_ENV" + - name: Set up QEMU + uses: docker/setup-qemu-action@v3 + - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 @@ -39,6 +42,7 @@ jobs: with: context: . push: true + platforms: linux/amd64,linux/arm64 tags: | ${{ env.IMAGE_NAME }}:latest ${{ env.IMAGE_NAME }}:${{ github.sha }} From d1ab59907476d2902022f6ae5e5f47977f50a989 Mon Sep 17 00:00:00 2001 From: bouhamza abderrahmane Date: Thu, 19 Mar 2026 22:20:02 +0100 Subject: [PATCH 7/9] ci: update GHCR workflow and silence insightface mypy warning --- .github/workflows/docker-publish.yml | 25 ++++++++++++++++++------- app/service/face_embedding.py | 4 ++-- 2 files changed, 20 insertions(+), 9 deletions(-) diff --git a/.github/workflows/docker-publish.yml b/.github/workflows/docker-publish.yml index 840f3c8..5f14801 100644 --- a/.github/workflows/docker-publish.yml +++ b/.github/workflows/docker-publish.yml @@ -14,7 +14,8 @@ jobs: build-and-push: runs-on: ubuntu-latest env: - IMAGE_NAME: ghcr.io/${{ github.repository }} + REGISTRY: ghcr.io + IMAGE_NAME: ${{ github.repository }} steps: - name: Checkout uses: actions/checkout@v4 @@ -22,7 +23,7 @@ jobs: - name: Set image name shell: bash run: | - echo "IMAGE_NAME=ghcr.io/${GITHUB_REPOSITORY,,}" >> "$GITHUB_ENV" + echo "IMAGE_NAME=${GITHUB_REPOSITORY,,}" >> "$GITHUB_ENV" - name: Set up QEMU uses: docker/setup-qemu-action@v3 @@ -33,9 +34,18 @@ jobs: - name: Login to GHCR uses: docker/login-action@v3 with: - registry: ghcr.io + registry: ${{ env.REGISTRY }} username: ${{ github.actor }} - password: ${{ secrets.GHCR_PAT }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Extract metadata + id: meta + uses: docker/metadata-action@v5 + with: + images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} + tags: | + type=raw,value=latest + type=sha,prefix= - name: Build and push uses: docker/build-push-action@v5 @@ -43,6 +53,7 @@ jobs: context: . push: true platforms: linux/amd64,linux/arm64 - tags: | - ${{ env.IMAGE_NAME }}:latest - ${{ env.IMAGE_NAME }}:${{ github.sha }} + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + cache-from: type=gha + cache-to: type=gha,mode=max diff --git a/app/service/face_embedding.py b/app/service/face_embedding.py index 6f5b6a4..d4541a8 100644 --- a/app/service/face_embedding.py +++ b/app/service/face_embedding.py @@ -3,9 +3,9 @@ import asyncio from typing import List, Literal, Optional, Sequence, Tuple, TypedDict -import cv2 +import cv2 # type: ignore import numpy as np -from insightface.app import FaceAnalysis +from insightface.app import FaceAnalysis # type: ignore[import-untyped] from app.core.exceptions import AppException From 91f358d2ed44453bd00227cfd685620c847481b9 Mon Sep 17 00:00:00 2001 From: bouhamza abderrahmane Date: Fri, 20 Mar 2026 06:35:27 +0100 Subject: [PATCH 8/9] Add mobile session settings to config --- app/core/config.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/app/core/config.py b/app/core/config.py index 3267862..011970f 100644 --- a/app/core/config.py +++ b/app/core/config.py @@ -31,6 +31,11 @@ class Settings(BaseSettings): POSTGRES_HOST: str = "localhost" POSTGRES_PORT: int = 5432 + # Mobile auth/session defaults + MOBILE_SESSION_LIMIT: int = 3 + MOBILE_SESSION_TTL_SECONDS: int = 180 + MOBILE_SESSION_DAYS: int = 7 + # Security jwt_secret: str jwt_algorithm: str = "HS256" From 42c48262a817ad7a1f946f13456de81048f3161d Mon Sep 17 00:00:00 2001 From: bouhamza abderrahmane Date: Fri, 20 Mar 2026 06:35:31 +0100 Subject: [PATCH 9/9] Use config for mobile session limits and TTL --- app/service/users.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/app/service/users.py b/app/service/users.py index ecfaf91..a7b3434 100644 --- a/app/service/users.py +++ b/app/service/users.py @@ -12,6 +12,7 @@ decode_refresh_mobile_token, Get_expiry_time, ) +from app.core.config import settings from app.infra.redis import RedisClient from app.schema.request.mobile.auth import MobileAuthRequest @@ -28,8 +29,8 @@ class AuthService: user_querier: user_queries.AsyncQuerier device_querier: device_queries.AsyncQuerier session_querier: session_queries.AsyncQuerier - SESSION_LIMIT = 3 - REDIS_SESSION_TTL = 180 + SESSION_LIMIT = settings.MOBILE_SESSION_LIMIT + REDIS_SESSION_TTL = settings.MOBILE_SESSION_TTL_SECONDS def __init__( self, @@ -84,7 +85,9 @@ async def mobile_register_login( raise AppException.forbidden("Maximum session limit reached") device_id = req.device_id - expires_at = datetime.now(timezone.utc) + timedelta(days=7) + expires_at = datetime.now(timezone.utc) + timedelta( + days=settings.MOBILE_SESSION_DAYS + ) device = await self.device_querier.create_device( arg=device_queries.CreateDeviceParams(