3 Commits

Author SHA1 Message Date
ac9c7a81c3 Release v25.11.06
All checks were successful
CI / Checks (push) Successful in 4m30s
Production deployment / Build (release) Successful in 23s
Production deployment / Deploy (release) Successful in 1m50s
Staging deployment / Build (release) Successful in 1m9s
Staging deployment / Deploy (release) Successful in 1m1s
2025-11-06 22:02:59 +01:00
e800d0c16c BTHLABS-63: Production deployment workflow 2025-11-06 21:58:20 +01:00
d8bbe57b17 BTHLABS-64: Support for customized environments
Co-authored-by: Tomek Wójcik <labs@tomekwojcik.pl>
Co-committed-by: Tomek Wójcik <labs@tomekwojcik.pl>
2025-10-27 19:04:48 +00:00
71 changed files with 1108 additions and 301 deletions

View File

@@ -0,0 +1,19 @@
name: "Set up Ansible"
description: "Downloads and installs Ansible"
inputs:
version:
description: "Ansible version to install"
required: false
default: "10.2.0"
runs:
using: "composite"
steps:
- name: "Install Ansible"
shell: "bash"
env:
PIP_INDEX_URL: "https://nexus.bthlabs.pl/repository/pypi/simple/"
run: |
set -x
python3 -m venv /opt/ansible
/opt/ansible/bin/pip install ansible==${{ inputs.version }}

View File

@@ -0,0 +1,81 @@
name: "Build deployment images"
on:
workflow_call:
inputs:
target:
required: true
type: "string"
registry:
required: false
type: "string"
default: "docker-hosted.nexus.bthlabs.pl"
platform:
required: false
type: "string"
default: "linux/amd64,linux/arm64"
secrets:
VAULT_ROLE_ID:
required: true
VAULT_SECRET_ID:
required: true
jobs:
build-deployment-images:
name: "Build deployment images"
runs-on: "ubuntu-latest"
steps:
- name: "Checkout the code"
uses: "actions/checkout@v2"
- name: "Get build options"
id: "get-build-options"
uses: "./.gitea/actions/get-build-options"
- name: "Get `backend` version"
id: "get-backend-version"
uses: "./.gitea/actions/get-service-version"
with:
service: "backend"
- name: "Import Secrets"
id: "import-secrets"
uses: "hashicorp/vault-action@v2"
with:
url: "https://vault.bthlabs.pl/"
method: "approle"
roleId: "${{ secrets.VAULT_ROLE_ID }}"
secretId: "${{ secrets.VAULT_SECRET_ID }}"
secrets: |
gitea/data/${{ inputs.registry }} username | DOCKER_USERNAME ;
gitea/data/${{ inputs.registry }} password | DOCKER_PASSWORD
- name: "Set up Docker Buildx"
id: "setup-docker-buildx"
uses: "docker/setup-buildx-action@v3"
with:
driver: "remote"
endpoint: "tcp://builder-01.bthlab:2375"
platforms: "linux/amd64"
append: |
- endpoint: "tcp://builder-mac-01.bthlab:2375"
platforms: "linux/arm64"
- name: "Login to Docker Registry"
uses: "docker/login-action@v3"
with:
registry: "${{ inputs.registry }}"
username: "${{ steps.import-secrets.outputs.DOCKER_USERNAME }}"
password: "${{ steps.import-secrets.outputs.DOCKER_PASSWORD }}"
- name: "Build `backend-aio` image"
env:
SHORT_SHA: "${{ steps.get-build-options.outputs.short-sha }}"
VERSION: "${{ steps.get-backend-version.outputs.version }}"
BUILD: "${{ steps.get-backend-version.outputs.build-number }}"
run: |
set -x
docker buildx build \
--cache-from "type=registry,ref=nexus.bthlab.bthlabs.net:8001/hotpocket" \
--cache-to "type=registry,ref=nexus.bthlab.bthlabs.net:8001/hotpocket,target=max" \
--push \
--platform "${{ inputs.platform }}" \
--build-arg IMAGE_ID="${{ inputs.target }}.${SHORT_SHA}" \
-f services/backend/Dockerfile \
--target "${{ inputs.target }}" \
-t "${{ inputs.registry }}/hotpocket/backend:${{ inputs.target }}-${VERSION}-${BUILD}" \
services/

View File

@@ -1,4 +1,4 @@
name: "Deploy to development" name: "Development deployment"
on: on:
push: push:
@@ -6,98 +6,28 @@ on:
- "development" - "development"
jobs: jobs:
build-deployment-images: build-for-development:
name: "Build deployment images" name: "Build"
runs-on: "ubuntu-latest" uses: "./.gitea/workflows/build-deployment-images.yaml"
steps:
- name: "Checkout the code"
uses: "actions/checkout@v2"
- name: "Get build options"
id: "get-build-options"
uses: "./.gitea/actions/get-build-options"
- name: "Get `backend` version"
id: "get-backend-version"
uses: "./.gitea/actions/get-service-version"
with: with:
service: "backend" target: "deployment"
- name: "Import Secrets" platform: "linux/amd64"
id: "import-secrets" registry: "nexus.bthlab.bthlabs.net:8002"
uses: "hashicorp/vault-action@v2" secrets:
with: VAULT_ROLE_ID: "${{ secrets.VAULT_ROLE_ID }}"
url: "https://vault.bthlabs.pl/" VAULT_SECRET_ID: "${{ secrets.VAULT_SECRET_ID }}"
method: "approle"
roleId: "${{ secrets.VAULT_ROLE_ID }}"
secretId: "${{ secrets.VAULT_SECRET_ID }}"
secrets: |
gitea/data/docker-hosted.nexus.bthlabs.pl username | DOCKER_USERNAME ;
gitea/data/docker-hosted.nexus.bthlabs.pl password | DOCKER_PASSWORD
- name: "Set up Docker Buildx"
id: "setup-docker-buildx"
uses: "docker/setup-buildx-action@v3"
with:
driver: "remote"
endpoint: "tcp://builder-01.bthlab:2375"
platforms: "linux/amd64"
append: |
- endpoint: "tcp://builder-mac-01.bthlab:2375"
platforms: "linux/arm64"
- name: "Login to Docket Registry"
uses: "docker/login-action@v3"
with:
registry: "docker-hosted.nexus.bthlabs.pl"
username: "${{ steps.import-secrets.outputs.DOCKER_USERNAME }}"
password: "${{ steps.import-secrets.outputs.DOCKER_PASSWORD }}"
- name: "Build `backend-deployment` image"
env:
SHORT_SHA: "${{ steps.get-build-options.outputs.short-sha }}"
VERSION: "${{ steps.get-backend-version.outputs.version }}"
BUILD: "${{ steps.get-backend-version.outputs.build-number }}"
run: |
set -x
docker buildx build \
--cache-from "type=registry,ref=nexus.bthlab.bthlabs.net:8001/hotpocket" \
--cache-to "type=registry,ref=nexus.bthlab.bthlabs.net:8001/hotpocket,mode=max" \
--push \
--platform linux/amd64,linux/arm64 \
--build-arg IMAGE_ID="deployment.${SHORT_SHA}" \
-f services/backend/Dockerfile \
--target deployment \
-t "docker-hosted.nexus.bthlabs.pl/hotpocket/backend:deployment-${VERSION}-${BUILD}" \
services/
- name: "Build `backend-aio` image"
env:
SHORT_SHA: "${{ steps.get-build-options.outputs.short-sha }}"
VERSION: "${{ steps.get-backend-version.outputs.version }}"
BUILD: "${{ steps.get-backend-version.outputs.build-number }}"
run: |
set -x
docker buildx build \
--cache-from "type=registry,ref=nexus.bthlab.bthlabs.net:8001/hotpocket" \
--cache-to "type=registry,ref=nexus.bthlab.bthlabs.net:8001/hotpocket,mode=max" \
--push \
--platform linux/amd64,linux/arm64 \
--build-arg IMAGE_ID="aio.${SHORT_SHA}" \
-f services/backend/Dockerfile \
--target aio \
-t "docker-hosted.nexus.bthlabs.pl/hotpocket/backend:aio-${VERSION}-${BUILD}" \
services/
deploy: deploy-to-deployment:
name: "Deploy" name: "Deploy"
runs-on: "ubuntu-latest" runs-on: "ubuntu-latest"
needs: needs:
- "build-deployment-images" - "build-for-development"
env: env:
KUBERNETES_NAMESPACE: "hotpocket-development" KUBERNETES_NAMESPACE: "hotpocket-development"
KUBERNETES_CLUSTER: "k8s.bthlab" KUBERNETES_CLUSTER: "k8s.bthlab"
steps: steps:
- name: "Checkout the code" - name: "Checkout the code"
uses: "actions/checkout@v2" uses: "actions/checkout@v2"
- name: "Get run info"
id: "get-run-info"
uses: "./.gitea/actions/get-run-info"
with:
compose-project-base: "${{ vars.COMPOSE_PROJECT_BASE }}"
- name: "Get build options" - name: "Get build options"
id: "get-build-options" id: "get-build-options"
uses: "./.gitea/actions/get-build-options" uses: "./.gitea/actions/get-build-options"
@@ -122,7 +52,6 @@ jobs:
gitea/data/k8s.bthlab config | KUBECONFIG_PAYLOAD gitea/data/k8s.bthlab config | KUBECONFIG_PAYLOAD
- name: "Set up kubeconfig" - name: "Set up kubeconfig"
env: env:
COMPOSE_PROJECT: "${{ steps.get-run-info.outputs.compose-project }}"
KUBECONFIG_PAYLOAD: "${{ steps.import-secrets.outputs.KUBECONFIG_PAYLOAD }}" KUBECONFIG_PAYLOAD: "${{ steps.import-secrets.outputs.KUBECONFIG_PAYLOAD }}"
run: | run: |
set -x set -x
@@ -134,7 +63,6 @@ jobs:
/opt/k8s/bin/kubectl get node /opt/k8s/bin/kubectl get node
- name: "Run `backend` Django migrations" - name: "Run `backend` Django migrations"
env: env:
COMPOSE_PROJECT: "${{ steps.get-run-info.outputs.compose-project }}"
BACKEND_TAG: "deployment-${{ steps.get-backend-version.outputs.version }}-${{ steps.get-backend-version.outputs.build-number }}" BACKEND_TAG: "deployment-${{ steps.get-backend-version.outputs.version }}-${{ steps.get-backend-version.outputs.build-number }}"
run: | run: |
set -x set -x
@@ -143,14 +71,14 @@ jobs:
cd deployment/hotpocket.bthlab ; cd deployment/hotpocket.bthlab ;
export KUBECONFIG="/opt/k8s/etc/kubeconfig" ; export KUBECONFIG="/opt/k8s/etc/kubeconfig" ;
/opt/k8s/bin/kubectl config use-context ${KUBERNETES_CLUSTER} ; /opt/k8s/bin/kubectl config use-context ${KUBERNETES_CLUSTER} ;
/opt/k8s/bin/kubectl -n ${KUBERNETES_NAMESPACE} set image cronjobs/backend-job-migrations migrations=docker-hosted.nexus.bthlabs.pl/hotpocket/backend:${BACKEND_TAG} ; /opt/k8s/bin/kubectl -n ${KUBERNETES_NAMESPACE} apply -f resources/backend/config-map-local-deps.yaml ;
/opt/k8s/bin/kubectl -n ${KUBERNETES_NAMESPACE} set image cronjobs/backend-job-migrations migrations=nexus.bthlab.bthlabs.net:8002/hotpocket/backend:${BACKEND_TAG} ;
/opt/k8s/bin/kubectl -n ${KUBERNETES_NAMESPACE} delete jobs --ignore-not-found=true backend-job-migrations ; /opt/k8s/bin/kubectl -n ${KUBERNETES_NAMESPACE} delete jobs --ignore-not-found=true backend-job-migrations ;
/opt/k8s/bin/kubectl -n ${KUBERNETES_NAMESPACE} create job backend-job-migrations --from=cronjob/backend-job-migrations ; /opt/k8s/bin/kubectl -n ${KUBERNETES_NAMESPACE} create job backend-job-migrations --from=cronjob/backend-job-migrations ;
/opt/k8s/bin/kubectl -n ${KUBERNETES_NAMESPACE} wait --for=condition=complete --timeout=300s job/backend-job-migrations /opt/k8s/bin/kubectl -n ${KUBERNETES_NAMESPACE} wait --for=condition=complete --timeout=300s job/backend-job-migrations
) )
- name: "Deploy" - name: "Deploy"
env: env:
COMPOSE_PROJECT: "${{ steps.get-run-info.outputs.compose-project }}"
BACKEND_TAG: "deployment-${{ steps.get-backend-version.outputs.version }}-${{ steps.get-backend-version.outputs.build-number }}" BACKEND_TAG: "deployment-${{ steps.get-backend-version.outputs.version }}-${{ steps.get-backend-version.outputs.build-number }}"
run: | run: |
set -x set -x
@@ -158,6 +86,6 @@ jobs:
cd deployment/hotpocket.bthlab ; cd deployment/hotpocket.bthlab ;
export KUBECONFIG="/opt/k8s/etc/kubeconfig" ; export KUBECONFIG="/opt/k8s/etc/kubeconfig" ;
/opt/k8s/bin/kubectl config use-context ${KUBERNETES_CLUSTER} ; /opt/k8s/bin/kubectl config use-context ${KUBERNETES_CLUSTER} ;
/opt/k8s/bin/kustomize edit set image hotpocket-backend=docker-hosted.nexus.bthlabs.pl/hotpocket/backend:${BACKEND_TAG} ; /opt/k8s/bin/kustomize edit set image hotpocket-backend=nexus.bthlab.bthlabs.net:8002/hotpocket/backend:${BACKEND_TAG} ;
/opt/k8s/bin/kustomize build . | /opt/k8s/bin/kubectl apply -f - /opt/k8s/bin/kustomize build . | /opt/k8s/bin/kubectl apply -f -
) )

View File

@@ -0,0 +1,76 @@
name: "Production deployment"
on:
release:
types: ["published"]
jobs:
build-for-production:
name: "Build"
uses: "./.gitea/workflows/build-deployment-images.yaml"
with:
target: "deployment"
platform: "linux/amd64"
secrets:
VAULT_ROLE_ID: "${{ secrets.VAULT_ROLE_ID }}"
VAULT_SECRET_ID: "${{ secrets.VAULT_SECRET_ID }}"
deploy-to-production:
name: "Deploy"
runs-on: "ubuntu-latest"
needs:
- "build-for-production"
steps:
- name: "Checkout the code"
uses: "actions/checkout@v2"
- name: "Get build options"
id: "get-build-options"
uses: "./.gitea/actions/get-build-options"
- name: "Get `backend` version"
id: "get-backend-version"
uses: "./.gitea/actions/get-service-version"
with:
service: "backend"
- name: "Import Secrets"
id: "import-secrets"
uses: "hashicorp/vault-action@v2"
with:
url: "https://vault.bthlabs.pl/"
method: "approle"
roleId: "${{ secrets.VAULT_ROLE_ID }}"
secretId: "${{ secrets.VAULT_SECRET_ID }}"
secrets: |
gitea/data/hotpocket.app ansible_vault_payload | ANSIBLE_VAULT_PAYLOAD ;
gitea/data/hotpocket.app ansible_vault_password | ANSIBLE_VAULT_PASSWORD ;
gitea/data/hotpocket.app ansible_inventory_payload | ANSIBLE_INVENTORY_PAYLOAD ;
gitea/data/hotpocket.app ssh_key_payload | SSH_KEY_PAYLOAD
- name: "Setup Ansible"
uses: "./.gitea/actions/setup-ansible"
- name: "Prepare Ansible secrets"
run: |
set -x
mkdir deployment/hotpocket_app/.ci
echo "${ANSIBLE_VAULT_PAYLOAD}" | base64 -d >"deployment/hotpocket_app/env_vars/production/vault.yaml"
echo "${ANSIBLE_VAULT_PASSWORD}" >"deployment/hotpocket_app/.ci/vault_password"
echo "${ANSIBLE_INVENTORY_PAYLOAD}" | base64 -d >"deployment/hotpocket_app/inventory_ci.yaml"
echo "${SSH_KEY_PAYLOAD}" | base64 -d >"deployment/hotpocket_app/.ci/ssh_key"
chmod 600 deployment/hotpocket_app/.ci/ssh_key
- name: "Engage!"
env:
VERSION: "${{ steps.get-backend-version.outputs.version }}"
BUILD: "${{ steps.get-backend-version.outputs.build-number }}"
run: |
set -x
(
cd deployment/hotpocket_app ;
ANSIBLE_HOST_KEY_CHECKING="False" /opt/ansible/bin/ansible-playbook \
-i inventory_ci.yaml \
--vault-id hotpocket@.ci/vault_password \
-e @env_vars/production/vars.yaml \
-e @env_vars/production/vault.yaml \
-e hotpocket_app_image_tag="deployment-${VERSION}-${BUILD}" \
--limit "*.production.hotpocket.app" \
deploy.yaml
)

View File

@@ -0,0 +1,76 @@
name: "Staging deployment"
on:
release:
types: ["published"]
jobs:
build-for-staging:
name: "Build"
uses: "./.gitea/workflows/build-deployment-images.yaml"
with:
target: "aio"
platform: "linux/amd64"
secrets:
VAULT_ROLE_ID: "${{ secrets.VAULT_ROLE_ID }}"
VAULT_SECRET_ID: "${{ secrets.VAULT_SECRET_ID }}"
deploy-to-staging:
name: "Deploy"
runs-on: "ubuntu-latest"
needs:
- "build-for-staging"
steps:
- name: "Checkout the code"
uses: "actions/checkout@v2"
- name: "Get build options"
id: "get-build-options"
uses: "./.gitea/actions/get-build-options"
- name: "Get `backend` version"
id: "get-backend-version"
uses: "./.gitea/actions/get-service-version"
with:
service: "backend"
- name: "Import Secrets"
id: "import-secrets"
uses: "hashicorp/vault-action@v2"
with:
url: "https://vault.bthlabs.pl/"
method: "approle"
roleId: "${{ secrets.VAULT_ROLE_ID }}"
secretId: "${{ secrets.VAULT_SECRET_ID }}"
secrets: |
gitea/data/staging.hotpocket.app ansible_vault_payload | ANSIBLE_VAULT_PAYLOAD ;
gitea/data/staging.hotpocket.app ansible_vault_password | ANSIBLE_VAULT_PASSWORD ;
gitea/data/staging.hotpocket.app ansible_inventory_payload | ANSIBLE_INVENTORY_PAYLOAD ;
gitea/data/staging.hotpocket.app ssh_key_payload | SSH_KEY_PAYLOAD
- name: "Setup Ansible"
uses: "./.gitea/actions/setup-ansible"
- name: "Prepare Ansible secrets"
run: |
set -x
mkdir deployment/hotpocket_app/.ci
echo "${ANSIBLE_VAULT_PAYLOAD}" | base64 -d >"deployment/hotpocket_app/env_vars/staging/vault.yaml"
echo "${ANSIBLE_VAULT_PASSWORD}" >"deployment/hotpocket_app/.ci/vault_password"
echo "${ANSIBLE_INVENTORY_PAYLOAD}" | base64 -d >"deployment/hotpocket_app/inventory_ci.yaml"
echo "${SSH_KEY_PAYLOAD}" | base64 -d >"deployment/hotpocket_app/.ci/ssh_key"
chmod 600 deployment/hotpocket_app/.ci/ssh_key
- name: "Engage!"
env:
VERSION: "${{ steps.get-backend-version.outputs.version }}"
BUILD: "${{ steps.get-backend-version.outputs.build-number }}"
run: |
set -x
(
cd deployment/hotpocket_app ;
ANSIBLE_HOST_KEY_CHECKING="False" /opt/ansible/bin/ansible-playbook \
-i inventory_ci.yaml \
--vault-id hotpocket@.ci/vault_password \
-e @env_vars/staging/vars.yaml \
-e @env_vars/staging/vault.yaml \
-e hotpocket_app_image_tag="aio-${VERSION}-${BUILD}" \
--limit "*.staging.hotpocket.app" \
deploy.yaml
)

1
.gitignore vendored
View File

@@ -1,4 +1,5 @@
.ci/ .ci/
.envrc* .envrc*
.ipythonhome/ .ipythonhome/
services/vendor/
/docker-compose-ci-*.yaml /docker-compose-ci-*.yaml

View File

@@ -66,7 +66,7 @@ $ docker run --rm -it \
-e HOTPOCKET_BACKEND_INITIAL_ACCOUNT_USERNAME=hotpocket \ -e HOTPOCKET_BACKEND_INITIAL_ACCOUNT_USERNAME=hotpocket \
-e HOTPOCKET_BACKEND_INITIAL_ACCOUNT_PASSWORD=hotpocketm4st3r \ -e HOTPOCKET_BACKEND_INITIAL_ACCOUNT_PASSWORD=hotpocketm4st3r \
-p 8000:8000 \ -p 8000:8000 \
docker-hosted.nexus.bthlabs.pl/hotpocket/backend:aio-v25.10.21-01 docker-hosted.nexus.bthlabs.pl/hotpocket/backend:aio-v25.11.06-01
``` ```
The command above will set up and start the application. The SQLite file will The command above will set up and start the application. The SQLite file will

View File

@@ -1,6 +1,6 @@
services: services:
backend: backend:
image: "docker-hosted.nexus.bthlabs.pl/hotpocket/backend:aio-v25.10.21-01" image: "docker-hosted.nexus.bthlabs.pl/hotpocket/backend:aio-v25.11.06-01"
environment: environment:
HOTPOCKET_BACKEND_SECRET_KEY: "thisisntright" HOTPOCKET_BACKEND_SECRET_KEY: "thisisntright"
HOTPOCKET_BACKEND_INITIAL_ACCOUNT_USERNAME: "hotpocket" HOTPOCKET_BACKEND_INITIAL_ACCOUNT_USERNAME: "hotpocket"

View File

@@ -8,7 +8,7 @@ x-backend-environment: &x-backend-environment
services: services:
webapp: webapp:
image: "docker-hosted.nexus.bthlabs.pl/hotpocket/backend:deployment-v25.10.21-01" image: "docker-hosted.nexus.bthlabs.pl/hotpocket/backend:deployment-v25.11.06-01"
environment: environment:
<<: *x-backend-environment <<: *x-backend-environment
HOTPOCKET_BACKEND_ALLOWED_HOSTS: "app.staging.hotpocket.bthlab.bthlabs.net" HOTPOCKET_BACKEND_ALLOWED_HOSTS: "app.staging.hotpocket.bthlab.bthlabs.net"
@@ -21,7 +21,7 @@ services:
restart: "unless-stopped" restart: "unless-stopped"
admin: admin:
image: "docker-hosted.nexus.bthlabs.pl/hotpocket/backend:deployment-v25.10.21-01" image: "docker-hosted.nexus.bthlabs.pl/hotpocket/backend:deployment-v25.11.06-01"
environment: environment:
<<: *x-backend-environment <<: *x-backend-environment
HOTPOCKET_BACKEND_APP: "admin" HOTPOCKET_BACKEND_APP: "admin"
@@ -35,7 +35,7 @@ services:
restart: "unless-stopped" restart: "unless-stopped"
celery-worker: celery-worker:
image: "docker-hosted.nexus.bthlabs.pl/hotpocket/backend:deployment-v25.10.21-01" image: "docker-hosted.nexus.bthlabs.pl/hotpocket/backend:deployment-v25.11.06-01"
command: command:
- "/srv/venv/bin/celery" - "/srv/venv/bin/celery"
- "-A" - "-A"
@@ -57,7 +57,7 @@ services:
restart: "unless-stopped" restart: "unless-stopped"
celery-beat: celery-beat:
image: "docker-hosted.nexus.bthlabs.pl/hotpocket/backend:deployment-v25.10.21-01" image: "docker-hosted.nexus.bthlabs.pl/hotpocket/backend:deployment-v25.11.06-01"
command: command:
- "/srv/venv/bin/celery" - "/srv/venv/bin/celery"
- "-A" - "-A"

View File

@@ -1,5 +1,7 @@
DJANGO_SETTINGS_MODULE=hotpocket_backend.settings.deployment.admin DJANGO_SETTINGS_MODULE=hotpocket_bthlabs.settings.admin
HOTPOCKET_BACKEND_GUNICORN_WORKERS=2 HOTPOCKET_BACKEND_GUNICORN_WORKERS=2
HOTPOCKET_BACKEND_SECRETS_PACKAGE=hotpocket_bthlabs.secrets
HOTPOCKET_BACKEND_ENV=development
HOTPOCKET_BACKEND_APP=admin HOTPOCKET_BACKEND_APP=admin
HOTPOCKET_BACKEND_SECRET_KEY=thisissecret HOTPOCKET_BACKEND_SECRET_KEY=thisissecret
HOTPOCKET_BACKEND_ALLOWED_HOSTS=thisissecret HOTPOCKET_BACKEND_ALLOWED_HOSTS=admin.hotpocket.bthlab.bthlabs.net

View File

@@ -1,7 +1,9 @@
DJANGO_SETTINGS_MODULE=hotpocket_backend.settings.deployment.webapp DJANGO_SETTINGS_MODULE=hotpocket_bthlabs.settings.webapp
HOTPOCKET_BACKEND_GUNICORN_WORKERS=2 HOTPOCKET_BACKEND_GUNICORN_WORKERS=2
HOTPOCKET_BACKEND_SECRETS_PACKAGE=hotpocket_bthlabs.secrets
HOTPOCKET_BACKEND_ENV=development
HOTPOCKET_BACKEND_APP=webapp HOTPOCKET_BACKEND_APP=webapp
HOTPOCKET_BACKEND_SECRET_KEY=thisissecret HOTPOCKET_BACKEND_SECRET_KEY=thisissecret
HOTPOCKET_BACKEND_ALLOWED_HOSTS=thisissecret HOTPOCKET_BACKEND_ALLOWED_HOSTS=app.hotpocket.bthlab.bthlabs.net
HOTPOCKET_BACKEND_SAVES_SAVE_ADAPTER=hotpocket_backend.apps.saves.adapters.postgres:PostgresSaveAdapter HOTPOCKET_BACKEND_SAVES_SAVE_ADAPTER=hotpocket_backend.apps.saves.adapters.postgres:PostgresSaveAdapter
HOTPOCKET_BACKEND_SAVES_ASSOCIATION_ADAPTER=hotpocket_backend.apps.saves.adapters.postgres:PostgresAssociationAdapter HOTPOCKET_BACKEND_SAVES_ASSOCIATION_ADAPTER=hotpocket_backend.apps.saves.adapters.postgres:PostgresAssociationAdapter

View File

@@ -4,6 +4,7 @@ kind: Kustomization
resources: resources:
- resources/namespace.yaml - resources/namespace.yaml
- resources/volumes.yaml - resources/volumes.yaml
- resources/backend/config-map-local-deps.yaml
- resources/backend/job-migrations.yaml - resources/backend/job-migrations.yaml
- resources/backend/webapp.yaml - resources/backend/webapp.yaml
- resources/backend/webapp-service.yaml - resources/backend/webapp-service.yaml
@@ -35,5 +36,5 @@ patches: []
images: images:
- name: hotpocket-backend - name: hotpocket-backend
newName: docker-hosted.nexus.bthlabs.pl/hotpocket/backend newName: nexus.bthlab.bthlabs.net:8002/hotpocket/backend
newTag: deployment-v25.10.4-01 newTag: deployment-8e09ae51-01

View File

@@ -26,7 +26,7 @@ spec:
containers: containers:
- name: app - name: app
image: hotpocket-backend:latest image: hotpocket-backend:latest
command: args:
- "/srv/venv/bin/gunicorn" - "/srv/venv/bin/gunicorn"
- "-c" - "-c"
- "/srv/lib/gunicorn.conf.py" - "/srv/lib/gunicorn.conf.py"
@@ -37,36 +37,21 @@ spec:
- configMapRef: - configMapRef:
name: backend-admin-config name: backend-admin-config
env: env:
- name: HOTPOCKET_BACKEND_SECRET_KEY - name: VAULT_URL
valueFrom: valueFrom:
secretKeyRef: secretKeyRef:
name: backend-admin name: backend-vault
key: secret_key key: url
- name: HOTPOCKET_BACKEND_ALLOWED_HOSTS - name: VAULT_ROLE_ID
valueFrom: valueFrom:
secretKeyRef: secretKeyRef:
name: backend-admin name: backend-vault
key: allowed_hosts key: role_id
- name: HOTPOCKET_BACKEND_DATABASE_USER - name: VAULT_SECRET_ID
valueFrom: valueFrom:
secretKeyRef: secretKeyRef:
name: backend-postgres name: backend-vault
key: username key: secret_id
- name: HOTPOCKET_BACKEND_DATABASE_PASSWORD
valueFrom:
secretKeyRef:
name: backend-postgres
key: password
- name: HOTPOCKET_BACKEND_CELERY_BROKER_URL
valueFrom:
secretKeyRef:
name: backend-celery
key: broker_url
- name: HOTPOCKET_BACKEND_CELERY_RESULT_BACKEND
valueFrom:
secretKeyRef:
name: backend-celery
key: result_backend
ports: ports:
- containerPort: 8000 - containerPort: 8000
name: http name: http
@@ -91,6 +76,15 @@ spec:
name: shm name: shm
- mountPath: /srv/run - mountPath: /srv/run
name: backend-admin-srv-run name: backend-admin-srv-run
- name: backend-admin-local-deps
mountPath: "/srv/lib/requirements.txt"
subPath: "requirements.txt"
- name: backend-admin-local-deps
mountPath: "/srv/etc/entrypoint.d/01-install-extra-deps.sh"
subPath: "01-install-extra-deps.sh"
- name: backend-admin-local-deps
mountPath: "/srv/etc/entrypoint.d/99-collectstatic.sh"
subPath: "99-collectstatic.sh"
dnsPolicy: ClusterFirst dnsPolicy: ClusterFirst
restartPolicy: Always restartPolicy: Always
volumes: volumes:
@@ -99,3 +93,7 @@ spec:
medium: Memory medium: Memory
- name: backend-admin-srv-run - name: backend-admin-srv-run
emptyDir: {} emptyDir: {}
- name: backend-admin-local-deps
configMap:
name: "backend-local-deps"
defaultMode: 0755

View File

@@ -20,7 +20,7 @@ spec:
containers: containers:
- name: app - name: app
image: hotpocket-backend:latest image: hotpocket-backend:latest
command: args:
- "/srv/venv/bin/celery" - "/srv/venv/bin/celery"
- "-A" - "-A"
- "hotpocket_backend.celery:app" - "hotpocket_backend.celery:app"
@@ -35,36 +35,21 @@ spec:
- configMapRef: - configMapRef:
name: backend-webapp-config name: backend-webapp-config
env: env:
- name: HOTPOCKET_BACKEND_SECRET_KEY - name: VAULT_URL
valueFrom: valueFrom:
secretKeyRef: secretKeyRef:
name: backend-webapp name: backend-vault
key: secret_key key: url
- name: HOTPOCKET_BACKEND_ALLOWED_HOSTS - name: VAULT_ROLE_ID
valueFrom: valueFrom:
secretKeyRef: secretKeyRef:
name: backend-webapp name: backend-vault
key: allowed_hosts key: role_id
- name: HOTPOCKET_BACKEND_DATABASE_USER - name: VAULT_SECRET_ID
valueFrom: valueFrom:
secretKeyRef: secretKeyRef:
name: backend-postgres name: backend-vault
key: username key: secret_id
- name: HOTPOCKET_BACKEND_DATABASE_PASSWORD
valueFrom:
secretKeyRef:
name: backend-postgres
key: password
- name: HOTPOCKET_BACKEND_CELERY_BROKER_URL
valueFrom:
secretKeyRef:
name: backend-celery
key: broker_url
- name: HOTPOCKET_BACKEND_CELERY_RESULT_BACKEND
valueFrom:
secretKeyRef:
name: backend-celery
key: result_backend
volumeMounts: volumeMounts:
- mountPath: /dev/shm - mountPath: /dev/shm
name: shm name: shm
@@ -72,6 +57,12 @@ spec:
name: backend-celery-beat-srv-run name: backend-celery-beat-srv-run
- mountPath: /srv/uploads - mountPath: /srv/uploads
name: backend-celery-beat-srv-uploads name: backend-celery-beat-srv-uploads
- name: backend-admin-local-deps
mountPath: "/srv/lib/requirements.txt"
subPath: "requirements.txt"
- name: backend-admin-local-deps
mountPath: "/srv/etc/entrypoint.d/01-install-extra-deps.sh"
subPath: "01-install-extra-deps.sh"
dnsPolicy: ClusterFirst dnsPolicy: ClusterFirst
restartPolicy: Always restartPolicy: Always
volumes: volumes:
@@ -83,3 +74,7 @@ spec:
claimName: backend-celery-beat-run claimName: backend-celery-beat-run
- name: backend-celery-beat-srv-uploads - name: backend-celery-beat-srv-uploads
emptyDir: {} emptyDir: {}
- name: backend-admin-local-deps
configMap:
name: "backend-local-deps"
defaultMode: 0755

View File

@@ -26,7 +26,7 @@ spec:
containers: containers:
- name: app - name: app
image: hotpocket-backend:latest image: hotpocket-backend:latest
command: args:
- "/srv/venv/bin/celery" - "/srv/venv/bin/celery"
- "-A" - "-A"
- "hotpocket_backend.celery:app" - "hotpocket_backend.celery:app"
@@ -43,36 +43,21 @@ spec:
- configMapRef: - configMapRef:
name: backend-webapp-config name: backend-webapp-config
env: env:
- name: HOTPOCKET_BACKEND_SECRET_KEY - name: VAULT_URL
valueFrom: valueFrom:
secretKeyRef: secretKeyRef:
name: backend-webapp name: backend-vault
key: secret_key key: url
- name: HOTPOCKET_BACKEND_ALLOWED_HOSTS - name: VAULT_ROLE_ID
valueFrom: valueFrom:
secretKeyRef: secretKeyRef:
name: backend-webapp name: backend-vault
key: allowed_hosts key: role_id
- name: HOTPOCKET_BACKEND_DATABASE_USER - name: VAULT_SECRET_ID
valueFrom: valueFrom:
secretKeyRef: secretKeyRef:
name: backend-postgres name: backend-vault
key: username key: secret_id
- name: HOTPOCKET_BACKEND_DATABASE_PASSWORD
valueFrom:
secretKeyRef:
name: backend-postgres
key: password
- name: HOTPOCKET_BACKEND_CELERY_BROKER_URL
valueFrom:
secretKeyRef:
name: backend-celery
key: broker_url
- name: HOTPOCKET_BACKEND_CELERY_RESULT_BACKEND
valueFrom:
secretKeyRef:
name: backend-celery
key: result_backend
volumeMounts: volumeMounts:
- mountPath: /dev/shm - mountPath: /dev/shm
name: shm name: shm
@@ -80,6 +65,12 @@ spec:
name: backend-celery-worker-srv-run name: backend-celery-worker-srv-run
- mountPath: /srv/uploads - mountPath: /srv/uploads
name: backend-celery-worker-srv-uploads name: backend-celery-worker-srv-uploads
- name: backend-admin-local-deps
mountPath: "/srv/lib/requirements.txt"
subPath: "requirements.txt"
- name: backend-admin-local-deps
mountPath: "/srv/etc/entrypoint.d/01-install-extra-deps.sh"
subPath: "01-install-extra-deps.sh"
dnsPolicy: ClusterFirst dnsPolicy: ClusterFirst
restartPolicy: Always restartPolicy: Always
volumes: volumes:
@@ -91,3 +82,7 @@ spec:
- name: backend-celery-worker-srv-uploads - name: backend-celery-worker-srv-uploads
persistentVolumeClaim: persistentVolumeClaim:
claimName: backend-uploads claimName: backend-uploads
- name: backend-admin-local-deps
configMap:
name: "backend-local-deps"
defaultMode: 0755

View File

@@ -0,0 +1,18 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: backend-local-deps
namespace: hotpocket-development
data:
01-install-extra-deps.sh: |
#!/usr/bin/env bash
export PIP_INDEX_URL="https://nexus.bthlabs.pl/repository/pypi/simple/"
/srv/venv/bin/pip install -r /srv/lib/requirements.txt
99-collectstatic.sh: |
#!/usr/bin/env bash
(
cd /srv/app;
./manage.py collectstatic --no-input
)
requirements.txt: |
hotpocket_bthlabs>=25.10.28

View File

@@ -22,7 +22,7 @@ spec:
containers: containers:
- name: migrations - name: migrations
image: hotpocket-backend:latest image: hotpocket-backend:latest
command: args:
- "./manage.py" - "./manage.py"
- "migrate" - "migrate"
envFrom: envFrom:
@@ -31,36 +31,21 @@ spec:
- configMapRef: - configMapRef:
name: backend-webapp-config name: backend-webapp-config
env: env:
- name: HOTPOCKET_BACKEND_SECRET_KEY - name: VAULT_URL
valueFrom: valueFrom:
secretKeyRef: secretKeyRef:
name: backend-webapp name: backend-vault
key: secret_key key: url
- name: HOTPOCKET_BACKEND_ALLOWED_HOSTS - name: VAULT_ROLE_ID
valueFrom: valueFrom:
secretKeyRef: secretKeyRef:
name: backend-webapp name: backend-vault
key: allowed_hosts key: role_id
- name: HOTPOCKET_BACKEND_DATABASE_USER - name: VAULT_SECRET_ID
valueFrom: valueFrom:
secretKeyRef: secretKeyRef:
name: backend-postgres name: backend-vault
key: username key: secret_id
- name: HOTPOCKET_BACKEND_DATABASE_PASSWORD
valueFrom:
secretKeyRef:
name: backend-postgres
key: password
- name: HOTPOCKET_BACKEND_CELERY_BROKER_URL
valueFrom:
secretKeyRef:
name: backend-celery
key: broker_url
- name: HOTPOCKET_BACKEND_CELERY_RESULT_BACKEND
valueFrom:
secretKeyRef:
name: backend-celery
key: result_backend
volumeMounts: volumeMounts:
- mountPath: /dev/shm - mountPath: /dev/shm
name: shm name: shm
@@ -68,6 +53,12 @@ spec:
name: backend-webapp-srv-run name: backend-webapp-srv-run
- mountPath: /srv/uploads - mountPath: /srv/uploads
name: backend-webapp-srv-uploads name: backend-webapp-srv-uploads
- name: backend-admin-local-deps
mountPath: "/srv/lib/requirements.txt"
subPath: "requirements.txt"
- name: backend-admin-local-deps
mountPath: "/srv/etc/entrypoint.d/01-install-extra-deps.sh"
subPath: "01-install-extra-deps.sh"
dnsPolicy: ClusterFirst dnsPolicy: ClusterFirst
restartPolicy: Never restartPolicy: Never
volumes: volumes:
@@ -78,3 +69,7 @@ spec:
emptyDir: {} emptyDir: {}
- name: backend-webapp-srv-uploads - name: backend-webapp-srv-uploads
emptyDir: {} emptyDir: {}
- name: backend-admin-local-deps
configMap:
name: "backend-local-deps"
defaultMode: 0755

View File

@@ -26,7 +26,7 @@ spec:
containers: containers:
- name: app - name: app
image: hotpocket-backend:latest image: hotpocket-backend:latest
command: args:
- "/srv/venv/bin/gunicorn" - "/srv/venv/bin/gunicorn"
- "-c" - "-c"
- "/srv/lib/gunicorn.conf.py" - "/srv/lib/gunicorn.conf.py"
@@ -37,36 +37,23 @@ spec:
- configMapRef: - configMapRef:
name: backend-webapp-config name: backend-webapp-config
env: env:
- name: HOTPOCKET_BACKEND_SECRET_KEY - name: VAULT_URL
valueFrom: valueFrom:
secretKeyRef: secretKeyRef:
name: backend-webapp name: backend-vault
key: secret_key key: url
- name: HOTPOCKET_BACKEND_ALLOWED_HOSTS - name: VAULT_ROLE_ID
valueFrom: valueFrom:
secretKeyRef: secretKeyRef:
name: backend-webapp name: backend-vault
key: allowed_hosts key: role_id
- name: HOTPOCKET_BACKEND_DATABASE_USER - name: VAULT_SECRET_ID
valueFrom: valueFrom:
secretKeyRef: secretKeyRef:
name: backend-postgres name: backend-vault
key: username key: secret_id
- name: HOTPOCKET_BACKEND_DATABASE_PASSWORD - name: HOTPOCKET_BACKEND_CREATE_INITIAL_ACCOUNT
valueFrom: value: "true"
secretKeyRef:
name: backend-postgres
key: password
- name: HOTPOCKET_BACKEND_CELERY_BROKER_URL
valueFrom:
secretKeyRef:
name: backend-celery
key: broker_url
- name: HOTPOCKET_BACKEND_CELERY_RESULT_BACKEND
valueFrom:
secretKeyRef:
name: backend-celery
key: result_backend
ports: ports:
- containerPort: 8000 - containerPort: 8000
name: http name: http
@@ -93,6 +80,15 @@ spec:
name: backend-webapp-srv-run name: backend-webapp-srv-run
- mountPath: /srv/uploads - mountPath: /srv/uploads
name: backend-webapp-srv-uploads name: backend-webapp-srv-uploads
- name: backend-admin-local-deps
mountPath: "/srv/lib/requirements.txt"
subPath: "requirements.txt"
- name: backend-admin-local-deps
mountPath: "/srv/etc/entrypoint.d/01-install-extra-deps.sh"
subPath: "01-install-extra-deps.sh"
- name: backend-admin-local-deps
mountPath: "/srv/etc/entrypoint.d/99-collectstatic.sh"
subPath: "99-collectstatic.sh"
dnsPolicy: ClusterFirst dnsPolicy: ClusterFirst
restartPolicy: Always restartPolicy: Always
volumes: volumes:
@@ -104,3 +100,7 @@ spec:
- name: backend-webapp-srv-uploads - name: backend-webapp-srv-uploads
persistentVolumeClaim: persistentVolumeClaim:
claimName: backend-uploads claimName: backend-uploads
- name: backend-admin-local-deps
configMap:
name: "backend-local-deps"
defaultMode: 0755

3
deployment/hotpocket_app/.gitignore vendored Normal file
View File

@@ -0,0 +1,3 @@
.ci/
inventory_ci.yaml
vault.yaml

View File

@@ -0,0 +1,5 @@
- name: "Deploy HotPocket"
hosts: "hotpocket_app"
roles:
- role: "hotpocket_app"
tags: ["hotpocket-app"]

View File

@@ -0,0 +1,3 @@
#!/usr/bin/env bash
export PIP_INDEX_URL="https://nexus.bthlabs.pl/repository/pypi/simple/"
/srv/venv/bin/pip install -r /srv/lib/backend/requirements.txt

View File

@@ -0,0 +1,5 @@
#!/usr/bin/env bash
(
cd /srv/app;
./manage.py collectstatic --no-input
)

View File

@@ -0,0 +1 @@
hotpocket-bthlabs>=25.10.28

View File

@@ -0,0 +1,60 @@
hotpocket_app:
deployment_directory: "/srv/hotpocket"
owner: "hotpocket"
group: "hotpocket"
mode: "fullstack"
loki:
url: "http://monitoring.vm.snakeweb.net.bthlabs.net:3100/loki/api/v1/push"
node: "home.vm.snakeweb.net"
docker:
extra_hosts:
- "home.vm:10.0.1.2"
backend:
image_tag: "{{ hotpocket_app_image_tag|default('deployment-v25.10.21-01') }}"
database:
name: "thisissecret"
user: "thisissecret"
host: "thisissecret"
rabbitmq:
vhost: "thisissecret"
user: "thisissecret"
host: "thisissecret"
model_auth_is_disabled: true
env: "production"
extra_env:
- "HOTPOCKET_BACKEND_SECRETS_PACKAGE=hotpocket_bthlabs.secrets"
- "VAULT_URL={{ hotpocket_app_secrets.backend.vault.url }}"
- "VAULT_ROLE_ID={{ hotpocket_app_secrets.backend.vault.role_id }}"
- "VAULT_SECRET_ID={{ hotpocket_app_secrets.backend.vault.secret_id }}"
oidc:
enabled: true
endpoint: "thisissecret"
display_name: "thisissecret"
webapp:
settings_module: "hotpocket_bthlabs.settings.webapp"
loki:
external_labels: "job=hotpocket,service=backend-webapp,environment=production"
allowed_hosts:
- "my.hotpocket.app"
admin:
settings_module: "hotpocket_bthlabs.settings.admin"
loki:
external_labels: "job=hotpocket,service=backend-admin,environment=production"
allowed_hosts:
- "admin.hotpocket.app"
celery_worker:
concurrency: 2
loki:
external_labels: "job=hotpocket,service=backend-celery-worker,environment=production"
celery_beat:
loki:
external_labels: "job=hotpocket,service=backend-celery-beat,environment=production"
customization:
- src: "{{ inventory_dir }}/env_vars/production/etc/backend/entrypoint.d/01-install-customized-deps.sh"
dest: "etc/backend/entrypoint.d/01-install-customized-deps.sh"
mode: "755"
- src: "{{ inventory_dir }}/env_vars/production/etc/backend/entrypoint.d/99-collectstatic.sh"
dest: "etc/backend/entrypoint.d/99-collectstatic.sh"
mode: "755"
- src: "{{ inventory_dir }}/env_vars/production/lib/backend/requirements.txt"
dest: "lib/backend/requirements.txt"

View File

@@ -0,0 +1,3 @@
#!/usr/bin/env bash
export PIP_INDEX_URL="https://nexus.bthlabs.pl/repository/pypi/simple/"
/srv/venv/bin/pip install -r /srv/lib/backend/requirements.txt

View File

@@ -0,0 +1,5 @@
#!/usr/bin/env bash
(
cd /srv/app;
./manage.py collectstatic --no-input
)

View File

@@ -0,0 +1 @@
hotpocket-bthlabs>=25.10.28

View File

@@ -0,0 +1,37 @@
hotpocket_app:
deployment_directory: "/srv/hotpocket_staging"
owner: "hotpocket_staging"
group: "hotpocket_staging"
mode: "aio"
loki:
url: "http://monitoring.vm.snakeweb.net.bthlabs.net:3100/loki/api/v1/push"
node: "home.vm.snakeweb.net"
docker:
extra_hosts:
- "home.vm:10.0.1.2"
backend:
image_tag: "{{ hotpocket_app_image_tag|default('aio-v25.10.29-rc1-01') }}"
model_auth_is_disabled: false
env: "staging"
extra_env:
- "HOTPOCKET_BACKEND_SECRETS_PACKAGE=hotpocket_bthlabs.secrets"
- "VAULT_URL={{ hotpocket_app_secrets.backend.vault.url }}"
- "VAULT_ROLE_ID={{ hotpocket_app_secrets.backend.vault.role_id }}"
- "VAULT_SECRET_ID={{ hotpocket_app_secrets.backend.vault.secret_id }}"
oidc:
enabled: false
webapp:
settings_module: "hotpocket_bthlabs.settings.webapp"
loki:
external_labels: "job=hotpocket,service=backend-webapp,environment=staging"
allowed_hosts:
- "staging.hotpocket.app"
customization:
- src: "{{ inventory_dir }}/env_vars/staging/etc/backend/entrypoint.d/01-install-customized-deps.sh"
dest: "etc/backend/entrypoint.d/01-install-customized-deps.sh"
mode: "755"
- src: "{{ inventory_dir }}/env_vars/staging/etc/backend/entrypoint.d/99-collectstatic.sh"
dest: "etc/backend/entrypoint.d/99-collectstatic.sh"
mode: "755"
- src: "{{ inventory_dir }}/env_vars/staging/lib/backend/requirements.txt"
dest: "lib/backend/requirements.txt"

View File

@@ -0,0 +1,10 @@
hotpocket_app:
hosts:
web1.staging.hotpocket.app:
ansible_host: vm-125.homelab01.bthlab
ansible_port: 22
ansible_user: hotpocket_staging
web1.production.hotpocket.app:
ansible_host: vm-125.homelab01.bthlab
ansible_port: 22
ansible_user: hotpocket

View File

@@ -0,0 +1,73 @@
- name: "Create workspace directories"
ansible.builtin.file:
path: "{{ hotpocket_app.deployment_directory }}/{{ item }}"
state: "directory"
loop:
- "etc"
- "etc/backend"
- "etc/backend/entrypoint.d"
- "lib"
- "lib/backend"
- "log"
- "run"
- "run/backend-admin"
- "run/backend-celery-beat"
- "run/backend-celery-worker"
- "run/backend-webapp"
- "run/uploads"
- name: "Install docker-compose.yml"
ansible.builtin.template:
src: "templates/{{ hotpocket_app.mode }}/docker-compose.yaml.jinja2"
dest: "{{ hotpocket_app.deployment_directory }}/docker-compose.yaml"
owner: "{{ hotpocket_app.owner }}"
group: "{{ hotpocket_app.group }}"
- name: "Install env files"
ansible.builtin.template:
src: "templates/{{ hotpocket_app.mode }}/{{ item }}.jinja2"
dest: "{{ hotpocket_app.deployment_directory }}/etc/{{ item }}"
owner: "{{ hotpocket_app.owner }}"
group: "{{ hotpocket_app.group }}"
loop: "{{ hotpocket_app_role.env_files[hotpocket_app.mode] }}"
- name: "Upload customization files"
ansible.builtin.copy:
src: "{{ item.src }}"
dest: "{{ hotpocket_app.deployment_directory }}/{{ item.dest }}"
owner: "{{ hotpocket_app.owner }}"
group: "{{ hotpocket_app.group }}"
mode: "{{ item.mode|default('644') }}"
loop: "{{ hotpocket_app.customization }}"
when: "hotpocket_app.customization is defined"
- name: "Install hotpocket_app.service unit"
ansible.builtin.template:
src: "templates/{{ hotpocket_app_role.services[hotpocket_app.mode].src }}.jinja2"
dest: "{{ hotpocket_app.deployment_directory }}/etc/{{ hotpocket_app_role.services[hotpocket_app.mode].dest }}"
owner: "{{ hotpocket_app.owner }}"
group: "{{ hotpocket_app.group }}"
- name: "Stop the stack"
ansible.builtin.command:
argv:
- "docker"
- "compose"
- "down"
chdir: "{{ hotpocket_app.deployment_directory }}"
- name: "Run backend migrations"
ansible.builtin.command:
argv:
- "docker"
- "compose"
- "run"
- "--rm"
- "backend-webapp"
- "./manage.py"
- "migrate"
chdir: "{{ hotpocket_app.deployment_directory }}"
when: "hotpocket_app.mode == 'fullstack' and is_manual_run is not defined"
- name: "Start the stack"
ansible.builtin.command:
argv:
- "docker"
- "compose"
- "up"
- "-d"
chdir: "{{ hotpocket_app.deployment_directory }}"
when: "is_manual_run is not defined"

View File

@@ -0,0 +1,9 @@
DJANGO_SETTINGS_MODULE="{{ hotpocket_app.backend.webapp.settings_module|default('hotpocket_backend.settings.aio')}}"
HOTPOCKET_BACKEND_ENV="{{ hotpocket_app.backend.env|default('aio') }}"
HOTPOCKET_BACKEND_MODEL_AUTH_IS_DISABLED="{% if hotpocket_app.backend.model_auth_is_disabled %}true{% else %}false{% endif %}"
{% if hotpocket_app.backend.oidc.enabled %}HOTPOCKET_BACKEND_OIDC_PAYLOAD='{"endpoint":"{{ hotpocket_app.backend.oidc.endpoint }}","key":"{{ hotpocket_app_secrets.backend.oidc.key }}","secret":"{{ hotpocket_app_secrets.backend.oidc.secret }}","display_name":"{{ hotpocket_app.backend.oidc.display_name }}"}'{% else %}#noop{% endif %}
{% for extra_env in hotpocket_app.backend.extra_env|default([]) %}
{{ extra_env }}
{% endfor %}

View File

@@ -0,0 +1,7 @@
HOTPOCKET_BACKEND_SECRET_KEY: "{{ hotpocket_app_secrets.backend.webapp.secret_key }}"
HOTPOCKET_BACKEND_ALLOWED_HOSTS="{{ hotpocket_app.backend.webapp.allowed_hosts|join(',') }}"
HOTPOCKET_BACKEND_INITIAL_ACCOUNT_USERNAME: "{{ hotpocket_app_secrets.backend.webapp.initial_account.username }}"
HOTPOCKET_BACKEND_INITIAL_ACCOUNT_PASSWORD: "{{ hotpocket_app_secrets.backend.webapp.initial_account.password }}"
{% for extra_env in hotpocket_app.backend.webapp.extra_env|default([]) %}
{{ extra_env }}
{% endfor %}

View File

@@ -0,0 +1,28 @@
services:
backend-webapp:
image: "docker-hosted.nexus.bthlabs.pl/hotpocket/backend:{{ hotpocket_app.backend.image_tag }}"
command:
- "/srv/venv/bin/gunicorn"
- "-c"
- "/srv/lib/gunicorn.conf.py"
- "-b"
- "unix:///srv/run/gunicorn.sock"
- "hotpocket_backend.wsgi:application"
logging:
driver: "loki"
options:
loki-url: "{{ hotpocket_app.loki.url }}"
loki-external-labels: "{{ hotpocket_app.backend.webapp.loki.external_labels }}"
labels: "node"
labels:
node: "{{ hotpocket_app.loki.node }}"
env_file:
- "etc/backend_base.env"
- "etc/backend_webapp.env"
extra_hosts: [{% for extra_host in hotpocket_app.docker.extra_hosts|default([]) %}"{{ extra_host }}"{% endfor %}]
restart: "unless-stopped"
volumes:
- "{{ hotpocket_app.deployment_directory }}/etc/backend:/srv/etc"
- "{{ hotpocket_app.deployment_directory }}/lib/backend:/srv/lib/backend"
- "{{ hotpocket_app.deployment_directory }}/run/backend-webapp:/srv/run"
- "{{ hotpocket_app.deployment_directory }}/run/uploads:/srv/uploads"

View File

@@ -0,0 +1,8 @@
DJANGO_SETTINGS_MODULE="{{ hotpocket_app.backend.admin.settings_module|default('hotpocket_backend.settings.deployment.admin')}}"
HOTPOCKET_BACKEND_GUNICORN_WORKERS=2
HOTPOCKET_BACKEND_APP="admin"
HOTPOCKET_BACKEND_SECRET_KEY="{{ hotpocket_app_secrets.backend.admin.secret_key }}"
HOTPOCKET_BACKEND_ALLOWED_HOSTS="{{ hotpocket_app.backend.admin.allowed_hosts|join(',') }}"
{% for extra_env in hotpocket_app.backend.admin.extra_env|default([]) %}
{{ extra_env }}
{% endfor %}

View File

@@ -0,0 +1,15 @@
HOTPOCKET_BACKEND_ENV="{{ hotpocket_app.backend.env|default('deployment') }}"
HOTPOCKET_BACKEND_DATABASE_NAME="{{ hotpocket_app.backend.database.name }}"
HOTPOCKET_BACKEND_DATABASE_USER="{{ hotpocket_app.backend.database.user }}"
HOTPOCKET_BACKEND_DATABASE_PASSWORD="{{ hotpocket_app_secrets.backend.database.password }}"
HOTPOCKET_BACKEND_DATABASE_HOST="{{ hotpocket_app.backend.database.host }}"
HOTPOCKET_BACKEND_CELERY_BROKER_URL="amqp://{{ hotpocket_app.backend.rabbitmq.user }}:{{ hotpocket_app_secrets.backend.rabbitmq.password }}@{{ hotpocket_app.backend.rabbitmq.host }}/{{ hotpocket_app.backend.rabbitmq.vhost }}"
HOTPOCKET_BACKEND_CELERY_RESULT_BACKEND="db+postgresql+psycopg://{{ hotpocket_app.backend.database.user }}:{{ hotpocket_app_secrets.backend.database.password }}@{{ hotpocket_app.backend.database.host }}/{{ hotpocket_app.backend.database.name }}"
HOTPOCKET_BACKEND_MODEL_AUTH_IS_DISABLED="{% if hotpocket_app.backend.model_auth_is_disabled %}true{% else %}false{% endif %}"
{% if hotpocket_app.backend.oidc.enabled %}HOTPOCKET_BACKEND_OIDC_PAYLOAD='{"endpoint":"{{ hotpocket_app.backend.oidc.endpoint }}","key":"{{ hotpocket_app_secrets.backend.oidc.key }}","secret":"{{ hotpocket_app_secrets.backend.oidc.secret }}","display_name":"{{ hotpocket_app.backend.oidc.display_name }}"}'{% else %}#noop{% endif %}
{% for extra_env in hotpocket_app.backend.extra_env|default([]) %}
{{ extra_env }}
{% endfor %}

View File

@@ -0,0 +1,9 @@
DJANGO_SETTINGS_MODULE="{{ hotpocket_app.backend.webapp.settings_module|default('hotpocket_backend.settings.deployment.webapp')}}"
HOTPOCKET_BACKEND_APP="webapp"
HOTPOCKET_BACKEND_SECRET_KEY="{{ hotpocket_app_secrets.backend.webapp.secret_key }}"
HOTPOCKET_BACKEND_ALLOWED_HOSTS="{{ hotpocket_app.backend.webapp.allowed_hosts|join(',') }}"
HOTPOCKET_BACKEND_SAVES_SAVE_ADAPTER="hotpocket_backend.apps.saves.adapters.postgres:PostgresSaveAdapter"
HOTPOCKET_BACKEND_SAVES_ASSOCIATION_ADAPTER="hotpocket_backend.apps.saves.adapters.postgres:PostgresAssociationAdapter"
{% for extra_env in hotpocket_app.backend.webapp.extra_env|default([]) %}
{{ extra_env }}
{% endfor %}

View File

@@ -0,0 +1,118 @@
services:
backend-webapp:
image: "docker-hosted.nexus.bthlabs.pl/hotpocket/backend:{{ hotpocket_app.backend.image_tag }}"
command:
- "/srv/venv/bin/gunicorn"
- "-c"
- "/srv/lib/gunicorn.conf.py"
- "-b"
- "unix:///srv/run/gunicorn.sock"
- "hotpocket_backend.wsgi:application"
logging:
driver: "loki"
options:
loki-url: "{{ hotpocket_app.loki.url }}"
loki-external-labels: "{{ hotpocket_app.backend.webapp.loki.external_labels }}"
labels: "node"
labels:
node: "{{ hotpocket_app.loki.node }}"
env_file:
- "etc/backend_base.env"
- "etc/backend_webapp.env"
extra_hosts: [{% for extra_host in hotpocket_app.docker.extra_hosts %}"{{ extra_host }}"{% endfor %}]
restart: "unless-stopped"
volumes:
- "{{ hotpocket_app.deployment_directory }}/etc/backend:/srv/etc"
- "{{ hotpocket_app.deployment_directory }}/lib/backend:/srv/lib/backend"
- "{{ hotpocket_app.deployment_directory }}/run/backend-webapp:/srv/run"
- "{{ hotpocket_app.deployment_directory }}/run/uploads:/srv/uploads"
backend-admin:
image: "docker-hosted.nexus.bthlabs.pl/hotpocket/backend:{{ hotpocket_app.backend.image_tag }}"
command:
- "/srv/venv/bin/gunicorn"
- "-c"
- "/srv/lib/gunicorn.conf.py"
- "-b"
- "unix:///srv/run/gunicorn.sock"
- "hotpocket_backend.wsgi:application"
logging:
driver: "loki"
options:
loki-url: "{{ hotpocket_app.loki.url }}"
loki-external-labels: "{{ hotpocket_app.backend.admin.loki.external_labels }}"
labels: "node"
labels:
node: "{{ hotpocket_app.loki.node }}"
env_file:
- "etc/backend_base.env"
- "etc/backend_admin.env"
extra_hosts: [{% for extra_host in hotpocket_app.docker.extra_hosts %}"{{ extra_host }}"{% endfor %}]
restart: "unless-stopped"
volumes:
- "{{ hotpocket_app.deployment_directory }}/etc/backend:/srv/etc"
- "{{ hotpocket_app.deployment_directory }}/lib/backend:/srv/lib/backend"
- "{{ hotpocket_app.deployment_directory }}/run/backend-admin:/srv/run"
- "{{ hotpocket_app.deployment_directory }}/run/uploads:/srv/uploads"
backend-celery-worker:
image: "docker-hosted.nexus.bthlabs.pl/hotpocket/backend:{{ hotpocket_app.backend.image_tag }}"
command:
- "/srv/venv/bin/celery"
- "-A"
- "hotpocket_backend.celery:app"
- "worker"
- "-l"
- "INFO"
- "-Q"
- "celery,webapp"
- "-c"
- "{{ hotpocket_app.backend.celery_worker.concurrency }}"
logging:
driver: "loki"
options:
loki-url: "{{ hotpocket_app.loki.url }}"
loki-external-labels: "{{ hotpocket_app.backend.celery_worker.loki.external_labels }}"
labels: "node"
labels:
node: "{{ hotpocket_app.loki.node }}"
env_file:
- "etc/backend_base.env"
- "etc/backend_webapp.env"
extra_hosts: [{% for extra_host in hotpocket_app.docker.extra_hosts %}"{{ extra_host }}"{% endfor %}]
restart: "unless-stopped"
volumes:
- "{{ hotpocket_app.deployment_directory }}/etc/backend:/srv/etc"
- "{{ hotpocket_app.deployment_directory }}/lib/backend:/srv/lib/backend"
- "{{ hotpocket_app.deployment_directory }}/run/backend-celery-worker:/srv/run"
- "{{ hotpocket_app.deployment_directory }}/run/uploads:/srv/uploads"
backend-celery-beat:
image: "docker-hosted.nexus.bthlabs.pl/hotpocket/backend:{{ hotpocket_app.backend.image_tag }}"
command:
- "/srv/venv/bin/celery"
- "-A"
- "hotpocket_backend.celery:app"
- "beat"
- "-l"
- "INFO"
- "-s"
- "/srv/run/celery-beat-schedule"
logging:
driver: "loki"
options:
loki-url: "{{ hotpocket_app.loki.url }}"
loki-external-labels: "{{ hotpocket_app.backend.celery_beat.loki.external_labels }}"
labels: "node"
labels:
node: "{{ hotpocket_app.loki.node }}"
env_file:
- "etc/backend_base.env"
- "etc/backend_webapp.env"
extra_hosts: [{% for extra_host in hotpocket_app.docker.extra_hosts %}"{{ extra_host }}"{% endfor %}]
restart: "unless-stopped"
volumes:
- "{{ hotpocket_app.deployment_directory }}/etc/backend:/srv/etc"
- "{{ hotpocket_app.deployment_directory }}/lib/backend:/srv/lib/backend"
- "{{ hotpocket_app.deployment_directory }}/run/backend-celery-beat:/srv/run"
- "{{ hotpocket_app.deployment_directory }}/run/uploads:/srv/uploads"

View File

@@ -0,0 +1,15 @@
[Unit]
Description=hotpocket_backend.webapp
Requires=docker.service
After=docker.service
[Service]
Type=oneshot
RemainAfterExit=yes
WorkingDirectory={{ hotpocket_app.deployment_directory }}
ExecStart=/usr/bin/docker compose up -d
ExecStop=/usr/bin/docker compose down
TimeoutStartSec=0
[Install]
WantedBy=multi-user.target

View File

@@ -0,0 +1,16 @@
hotpocket_app_role:
env_files:
fullstack:
- "backend_admin.env"
- "backend_base.env"
- "backend_webapp.env"
aio:
- "backend_base.env"
- "backend_webapp.env"
services:
fullstack:
src: "hotpocket_app.service"
dest: "hotpocket_app.service"
aio:
src: "hotpocket_app.service"
dest: "staging_hotpocket_app.service"

View File

@@ -1,6 +1,6 @@
[tool.poetry] [tool.poetry]
name = "hotpocket-workspace" name = "hotpocket-workspace"
version = "25.10.21" version = "25.11.06"
description = "HotPocket Workspace" description = "HotPocket Workspace"
authors = ["Tomek Wójcik <contact@bthlabs.pl>"] authors = ["Tomek Wójcik <contact@bthlabs.pl>"]
license = "Apache-2.0" license = "Apache-2.0"

View File

@@ -13,4 +13,5 @@ backend/hotpocket_backend/settings/metal/
backend/hotpocket_backend/static/ backend/hotpocket_backend/static/
extension/node_modules/ extension/node_modules/
extension/dist/ extension/dist/
vendor/
.envrc* .envrc*

View File

@@ -713,7 +713,7 @@
buildSettings = { buildSettings = {
CODE_SIGN_ENTITLEMENTS = "iOS (Share Extension)/iOS (Share Extension).entitlements"; CODE_SIGN_ENTITLEMENTS = "iOS (Share Extension)/iOS (Share Extension).entitlements";
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 2025102101; CURRENT_PROJECT_VERSION = 2025110601;
DEVELOPMENT_TEAM = 648728X64K; DEVELOPMENT_TEAM = 648728X64K;
GENERATE_INFOPLIST_FILE = YES; GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = "iOS (Share Extension)/Info.plist"; INFOPLIST_FILE = "iOS (Share Extension)/Info.plist";
@@ -726,7 +726,7 @@
"@executable_path/Frameworks", "@executable_path/Frameworks",
"@executable_path/../../Frameworks", "@executable_path/../../Frameworks",
); );
MARKETING_VERSION = 25.10.21; MARKETING_VERSION = 25.11.06;
PRODUCT_BUNDLE_IDENTIFIER = pl.bthlabs.HotPocket.ShareExtension; PRODUCT_BUNDLE_IDENTIFIER = pl.bthlabs.HotPocket.ShareExtension;
PRODUCT_NAME = "Save to HotPocket"; PRODUCT_NAME = "Save to HotPocket";
SDKROOT = iphoneos; SDKROOT = iphoneos;
@@ -746,7 +746,7 @@
buildSettings = { buildSettings = {
CODE_SIGN_ENTITLEMENTS = "iOS (Share Extension)/iOS (Share Extension).entitlements"; CODE_SIGN_ENTITLEMENTS = "iOS (Share Extension)/iOS (Share Extension).entitlements";
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 2025102101; CURRENT_PROJECT_VERSION = 2025110601;
DEVELOPMENT_TEAM = 648728X64K; DEVELOPMENT_TEAM = 648728X64K;
GENERATE_INFOPLIST_FILE = YES; GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = "iOS (Share Extension)/Info.plist"; INFOPLIST_FILE = "iOS (Share Extension)/Info.plist";
@@ -759,7 +759,7 @@
"@executable_path/Frameworks", "@executable_path/Frameworks",
"@executable_path/../../Frameworks", "@executable_path/../../Frameworks",
); );
MARKETING_VERSION = 25.10.21; MARKETING_VERSION = 25.11.06;
PRODUCT_BUNDLE_IDENTIFIER = pl.bthlabs.HotPocket.ShareExtension; PRODUCT_BUNDLE_IDENTIFIER = pl.bthlabs.HotPocket.ShareExtension;
PRODUCT_NAME = "Save to HotPocket"; PRODUCT_NAME = "Save to HotPocket";
SDKROOT = iphoneos; SDKROOT = iphoneos;
@@ -779,7 +779,7 @@
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
buildSettings = { buildSettings = {
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 2025102101; CURRENT_PROJECT_VERSION = 2025110601;
DEVELOPMENT_TEAM = 648728X64K; DEVELOPMENT_TEAM = 648728X64K;
GENERATE_INFOPLIST_FILE = YES; GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = "iOS (Extension)/Info.plist"; INFOPLIST_FILE = "iOS (Extension)/Info.plist";
@@ -792,7 +792,7 @@
"@executable_path/Frameworks", "@executable_path/Frameworks",
"@executable_path/../../Frameworks", "@executable_path/../../Frameworks",
); );
MARKETING_VERSION = 25.10.21; MARKETING_VERSION = 25.11.06;
OTHER_LDFLAGS = ( OTHER_LDFLAGS = (
"-framework", "-framework",
SafariServices, SafariServices,
@@ -814,7 +814,7 @@
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
buildSettings = { buildSettings = {
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 2025102101; CURRENT_PROJECT_VERSION = 2025110601;
DEVELOPMENT_TEAM = 648728X64K; DEVELOPMENT_TEAM = 648728X64K;
GENERATE_INFOPLIST_FILE = YES; GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = "iOS (Extension)/Info.plist"; INFOPLIST_FILE = "iOS (Extension)/Info.plist";
@@ -827,7 +827,7 @@
"@executable_path/Frameworks", "@executable_path/Frameworks",
"@executable_path/../../Frameworks", "@executable_path/../../Frameworks",
); );
MARKETING_VERSION = 25.10.21; MARKETING_VERSION = 25.11.06;
OTHER_LDFLAGS = ( OTHER_LDFLAGS = (
"-framework", "-framework",
SafariServices, SafariServices,
@@ -853,7 +853,7 @@
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
CODE_SIGN_ENTITLEMENTS = "iOS (App)/HotPocket (iOS).entitlements"; CODE_SIGN_ENTITLEMENTS = "iOS (App)/HotPocket (iOS).entitlements";
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 2025102101; CURRENT_PROJECT_VERSION = 2025110601;
DEVELOPMENT_TEAM = 648728X64K; DEVELOPMENT_TEAM = 648728X64K;
GENERATE_INFOPLIST_FILE = YES; GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = "iOS (App)/Info.plist"; INFOPLIST_FILE = "iOS (App)/Info.plist";
@@ -873,7 +873,7 @@
"$(inherited)", "$(inherited)",
"@executable_path/Frameworks", "@executable_path/Frameworks",
); );
MARKETING_VERSION = 25.10.21; MARKETING_VERSION = 25.11.06;
OTHER_LDFLAGS = ( OTHER_LDFLAGS = (
"-framework", "-framework",
SafariServices, SafariServices,
@@ -899,7 +899,7 @@
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
CODE_SIGN_ENTITLEMENTS = "iOS (App)/HotPocket (iOS).entitlements"; CODE_SIGN_ENTITLEMENTS = "iOS (App)/HotPocket (iOS).entitlements";
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 2025102101; CURRENT_PROJECT_VERSION = 2025110601;
DEVELOPMENT_TEAM = 648728X64K; DEVELOPMENT_TEAM = 648728X64K;
GENERATE_INFOPLIST_FILE = YES; GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = "iOS (App)/Info.plist"; INFOPLIST_FILE = "iOS (App)/Info.plist";
@@ -919,7 +919,7 @@
"$(inherited)", "$(inherited)",
"@executable_path/Frameworks", "@executable_path/Frameworks",
); );
MARKETING_VERSION = 25.10.21; MARKETING_VERSION = 25.11.06;
OTHER_LDFLAGS = ( OTHER_LDFLAGS = (
"-framework", "-framework",
SafariServices, SafariServices,
@@ -945,7 +945,7 @@
CODE_SIGN_ENTITLEMENTS = "macOS (Extension)/HotPocket.entitlements"; CODE_SIGN_ENTITLEMENTS = "macOS (Extension)/HotPocket.entitlements";
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development"; "CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development";
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 2025102101; CURRENT_PROJECT_VERSION = 2025110601;
DEVELOPMENT_TEAM = 648728X64K; DEVELOPMENT_TEAM = 648728X64K;
ENABLE_HARDENED_RUNTIME = YES; ENABLE_HARDENED_RUNTIME = YES;
ENABLE_USER_SCRIPT_SANDBOXING = NO; ENABLE_USER_SCRIPT_SANDBOXING = NO;
@@ -960,7 +960,7 @@
"@executable_path/../../../../Frameworks", "@executable_path/../../../../Frameworks",
); );
MACOSX_DEPLOYMENT_TARGET = 15.0; MACOSX_DEPLOYMENT_TARGET = 15.0;
MARKETING_VERSION = 25.10.21; MARKETING_VERSION = 25.11.06;
OTHER_LDFLAGS = ( OTHER_LDFLAGS = (
"-framework", "-framework",
SafariServices, SafariServices,
@@ -980,7 +980,7 @@
CODE_SIGN_ENTITLEMENTS = "macOS (Extension)/HotPocket.entitlements"; CODE_SIGN_ENTITLEMENTS = "macOS (Extension)/HotPocket.entitlements";
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development"; "CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development";
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 2025102101; CURRENT_PROJECT_VERSION = 2025110601;
DEVELOPMENT_TEAM = 648728X64K; DEVELOPMENT_TEAM = 648728X64K;
ENABLE_HARDENED_RUNTIME = YES; ENABLE_HARDENED_RUNTIME = YES;
ENABLE_USER_SCRIPT_SANDBOXING = NO; ENABLE_USER_SCRIPT_SANDBOXING = NO;
@@ -995,7 +995,7 @@
"@executable_path/../../../../Frameworks", "@executable_path/../../../../Frameworks",
); );
MACOSX_DEPLOYMENT_TARGET = 15.0; MACOSX_DEPLOYMENT_TARGET = 15.0;
MARKETING_VERSION = 25.10.21; MARKETING_VERSION = 25.11.06;
OTHER_LDFLAGS = ( OTHER_LDFLAGS = (
"-framework", "-framework",
SafariServices, SafariServices,
@@ -1017,7 +1017,7 @@
CODE_SIGN_ENTITLEMENTS = "macOS (App)/HotPocket.entitlements"; CODE_SIGN_ENTITLEMENTS = "macOS (App)/HotPocket.entitlements";
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development"; "CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development";
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 2025102101; CURRENT_PROJECT_VERSION = 2025110601;
DEVELOPMENT_TEAM = 648728X64K; DEVELOPMENT_TEAM = 648728X64K;
ENABLE_HARDENED_RUNTIME = YES; ENABLE_HARDENED_RUNTIME = YES;
GENERATE_INFOPLIST_FILE = YES; GENERATE_INFOPLIST_FILE = YES;
@@ -1033,7 +1033,7 @@
"@executable_path/../Frameworks", "@executable_path/../Frameworks",
); );
MACOSX_DEPLOYMENT_TARGET = 15.0; MACOSX_DEPLOYMENT_TARGET = 15.0;
MARKETING_VERSION = 25.10.21; MARKETING_VERSION = 25.11.06;
OTHER_LDFLAGS = ( OTHER_LDFLAGS = (
"-framework", "-framework",
SafariServices, SafariServices,
@@ -1056,7 +1056,7 @@
CODE_SIGN_ENTITLEMENTS = "macOS (App)/HotPocket.entitlements"; CODE_SIGN_ENTITLEMENTS = "macOS (App)/HotPocket.entitlements";
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development"; "CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development";
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 2025102101; CURRENT_PROJECT_VERSION = 2025110601;
DEVELOPMENT_TEAM = 648728X64K; DEVELOPMENT_TEAM = 648728X64K;
ENABLE_HARDENED_RUNTIME = YES; ENABLE_HARDENED_RUNTIME = YES;
GENERATE_INFOPLIST_FILE = YES; GENERATE_INFOPLIST_FILE = YES;
@@ -1072,7 +1072,7 @@
"@executable_path/../Frameworks", "@executable_path/../Frameworks",
); );
MACOSX_DEPLOYMENT_TARGET = 15.0; MACOSX_DEPLOYMENT_TARGET = 15.0;
MARKETING_VERSION = 25.10.21; MARKETING_VERSION = 25.11.06;
OTHER_LDFLAGS = ( OTHER_LDFLAGS = (
"-framework", "-framework",
SafariServices, SafariServices,
@@ -1206,7 +1206,7 @@
CODE_SIGN_ENTITLEMENTS = "macOS (Share Extension)/macOS (Share Extension).entitlements"; CODE_SIGN_ENTITLEMENTS = "macOS (Share Extension)/macOS (Share Extension).entitlements";
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES; COMBINE_HIDPI_IMAGES = YES;
CURRENT_PROJECT_VERSION = 2025102101; CURRENT_PROJECT_VERSION = 2025110601;
DEVELOPMENT_TEAM = 648728X64K; DEVELOPMENT_TEAM = 648728X64K;
ENABLE_HARDENED_RUNTIME = YES; ENABLE_HARDENED_RUNTIME = YES;
GENERATE_INFOPLIST_FILE = YES; GENERATE_INFOPLIST_FILE = YES;
@@ -1220,7 +1220,7 @@
"@executable_path/../../../../Frameworks", "@executable_path/../../../../Frameworks",
); );
MACOSX_DEPLOYMENT_TARGET = 15.0; MACOSX_DEPLOYMENT_TARGET = 15.0;
MARKETING_VERSION = 25.10.21; MARKETING_VERSION = 25.11.06;
PRODUCT_BUNDLE_IDENTIFIER = pl.bthlabs.HotPocket.ShareExtension; PRODUCT_BUNDLE_IDENTIFIER = pl.bthlabs.HotPocket.ShareExtension;
PRODUCT_NAME = "Save to HotPocket"; PRODUCT_NAME = "Save to HotPocket";
REGISTER_APP_GROUPS = YES; REGISTER_APP_GROUPS = YES;
@@ -1236,7 +1236,7 @@
CODE_SIGN_ENTITLEMENTS = "macOS (Share Extension)/macOS (Share Extension).entitlements"; CODE_SIGN_ENTITLEMENTS = "macOS (Share Extension)/macOS (Share Extension).entitlements";
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES; COMBINE_HIDPI_IMAGES = YES;
CURRENT_PROJECT_VERSION = 2025102101; CURRENT_PROJECT_VERSION = 2025110601;
DEVELOPMENT_TEAM = 648728X64K; DEVELOPMENT_TEAM = 648728X64K;
ENABLE_HARDENED_RUNTIME = YES; ENABLE_HARDENED_RUNTIME = YES;
GENERATE_INFOPLIST_FILE = YES; GENERATE_INFOPLIST_FILE = YES;
@@ -1250,7 +1250,7 @@
"@executable_path/../../../../Frameworks", "@executable_path/../../../../Frameworks",
); );
MACOSX_DEPLOYMENT_TARGET = 15.0; MACOSX_DEPLOYMENT_TARGET = 15.0;
MARKETING_VERSION = 25.10.21; MARKETING_VERSION = 25.11.06;
PRODUCT_BUNDLE_IDENTIFIER = pl.bthlabs.HotPocket.ShareExtension; PRODUCT_BUNDLE_IDENTIFIER = pl.bthlabs.HotPocket.ShareExtension;
PRODUCT_NAME = "Save to HotPocket"; PRODUCT_NAME = "Save to HotPocket";
REGISTER_APP_GROUPS = YES; REGISTER_APP_GROUPS = YES;

View File

@@ -1,6 +1,6 @@
[tool.poetry] [tool.poetry]
name = "hotpocket-apple" name = "hotpocket-apple"
version = "25.10.21" version = "25.11.06"
description = "HotPocket Apple Integrations" description = "HotPocket Apple Integrations"
authors = ["Tomek Wójcik <contact@bthlabs.pl>"] authors = ["Tomek Wójcik <contact@bthlabs.pl>"]
license = "Apache-2.0" license = "Apache-2.0"

View File

@@ -45,11 +45,12 @@ COPY --from=deployment-build /srv/packages /srv/packages
COPY --from=deployment-build /srv/venv /srv/venv COPY --from=deployment-build /srv/venv /srv/venv
COPY --chown=$APP_USER_UID:$APP_USER_GID backend/ops/bin/*.sh /srv/bin/ COPY --chown=$APP_USER_UID:$APP_USER_GID backend/ops/bin/*.sh /srv/bin/
COPY --chown=$APP_USER_UID:$APP_USER_GID backend/ops/deployment/gunicorn.conf.py backend/ops/deployment/gunicorn.logging.conf /srv/lib/ COPY --chown=$APP_USER_UID:$APP_USER_GID backend/ops/deployment/gunicorn.conf.py backend/ops/deployment/gunicorn.logging.conf /srv/lib/
COPY --chown=root:root backend/ops/etc/sudoers_app /etc/sudoers.d/app
USER root USER root
RUN apt-get update && \ RUN apt-get update && \
apt-get install -y libpq5 dumb-init && \ apt-get install -y libpq5 dumb-init sudo && \
apt-get clean autoclean && \ apt-get clean autoclean && \
apt-get autoremove --yes && \ apt-get autoremove --yes && \
rm -rf /var/lib/apt /var/lib/dpkg && \ rm -rf /var/lib/apt /var/lib/dpkg && \
@@ -67,6 +68,8 @@ ARG APP_USER_GID
ARG IMAGE_ID ARG IMAGE_ID
ENV DJANGO_SETTINGS_MODULE=hotpocket_backend.settings.deployment.webapp ENV DJANGO_SETTINGS_MODULE=hotpocket_backend.settings.deployment.webapp
ENV HOTPOCKET_BACKEND_APP_USER_UID=${APP_USER_UID}
ENV HOTPOCKET_BACKEND_APP_USER_GID=${APP_USER_GID}
ENV HOTPOCKET_BACKEND_ENV=deployment ENV HOTPOCKET_BACKEND_ENV=deployment
ENV HOTPOCKET_BACKEND_APP=webapp ENV HOTPOCKET_BACKEND_APP=webapp
@@ -79,6 +82,8 @@ ARG APP_USER_GID
ARG IMAGE_ID ARG IMAGE_ID
ENV DJANGO_SETTINGS_MODULE=hotpocket_backend.settings.aio ENV DJANGO_SETTINGS_MODULE=hotpocket_backend.settings.aio
ENV HOTPOCKET_BACKEND_APP_USER_UID=${APP_USER_UID}
ENV HOTPOCKET_BACKEND_APP_USER_GID=${APP_USER_GID}
ENV HOTPOCKET_BACKEND_ENV=aio ENV HOTPOCKET_BACKEND_ENV=aio
ENV HOTPOCKET_BACKEND_APP=webapp ENV HOTPOCKET_BACKEND_APP=webapp
ENV HOTPOCKET_BACKEND_DEBUG=false ENV HOTPOCKET_BACKEND_DEBUG=false
@@ -92,6 +97,7 @@ ENV HOTPOCKET_BACKEND_CELERY_IGNORE_RESULT=true
ENV HOTPOCKET_BACKEND_CELERY_ALWAYS_EAGER=true ENV HOTPOCKET_BACKEND_CELERY_ALWAYS_EAGER=true
ENV HOTPOCKET_BACKEND_GUNICORN_WORKERS=2 ENV HOTPOCKET_BACKEND_GUNICORN_WORKERS=2
ENV HOTPOCKET_BACKEND_RUN_MIGRATIONS=true ENV HOTPOCKET_BACKEND_RUN_MIGRATIONS=true
ENV HOTPOCKET_BACKEND_CREATE_INITIAL_ACCOUNT=true
ENV HOTPOCKET_BACKEND_UPLOADS_PATH=/srv/run/uploads ENV HOTPOCKET_BACKEND_UPLOADS_PATH=/srv/run/uploads
VOLUME ["/srv/run"] VOLUME ["/srv/run"]

View File

@@ -1,4 +1,4 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from __future__ import annotations from __future__ import annotations
version = '25.10.21' version = '25.11.06'

View File

@@ -8,6 +8,7 @@ from django.core.management import BaseCommand
import django.db import django.db
from hotpocket_backend.apps.accounts.models import Account from hotpocket_backend.apps.accounts.models import Account
from hotpocket_backend.apps.core.conf import settings
LOGGER = logging.getLogger(__name__) LOGGER = logging.getLogger(__name__)
@@ -17,12 +18,12 @@ class Command(BaseCommand):
def add_arguments(self, parser: ArgumentParser): def add_arguments(self, parser: ArgumentParser):
parser.add_argument( parser.add_argument(
'username', '-u', '--username', default=None,
help='Username for the Account', help='Override username for the Account',
) )
parser.add_argument( parser.add_argument(
'password', '-p', '--password', default=None,
help='Password for the Account', help='Override Password for the Account',
) )
parser.add_argument( parser.add_argument(
'-d', '--dry-run', action='store_true', default=False, '-d', '--dry-run', action='store_true', default=False,
@@ -31,10 +32,22 @@ class Command(BaseCommand):
def handle(self, *args, **options): def handle(self, *args, **options):
LOGGER.debug('args=`%s` options=`%s`', args, options) LOGGER.debug('args=`%s` options=`%s`', args, options)
username = options.get('username')
password = options.get('password')
dry_run = options.get('dry_run', False) dry_run = options.get('dry_run', False)
username = options.get('username') or settings.SECRETS.INITIAL_ACCOUNT.username
if not username:
LOGGER.info('Not creating initial Account: empty `username`')
return
password = options.get('password') or settings.SECRETS.INITIAL_ACCOUNT.password
assert password, 'Unable to proceed: empty `password`'
LOGGER.debug(
'Creating initial Account: username=`%s` password=`%s`',
username,
password,
)
with django.db.transaction.atomic(): with django.db.transaction.atomic():
current_account = Account.objects.filter(username=username).first() current_account = Account.objects.filter(username=username).first()
if current_account is not None: if current_account is not None:

View File

@@ -1,12 +1,25 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from __future__ import annotations from __future__ import annotations
import logging
from django.apps import AppConfig from django.apps import AppConfig
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
from hotpocket_backend.apps.core.conf import settings
LOGGER = logging.getLogger(__name__)
class CoreConfig(AppConfig): class CoreConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField' default_auto_field = 'django.db.models.BigAutoField'
label = 'core' label = 'core'
name = 'hotpocket_backend.apps.core' name = 'hotpocket_backend.apps.core'
verbose_name = _('Core') verbose_name = _('Core')
def ready(self):
LOGGER.info(
'HotPocket Backend ready: env=`%s` app=`%s`',
settings.ENV.name,
settings.APP.name,
)

View File

@@ -6,7 +6,7 @@ import typing
from hotpocket_backend.secrets.admin import AdminSecrets from hotpocket_backend.secrets.admin import AdminSecrets
from hotpocket_backend.secrets.webapp import WebAppSecrets from hotpocket_backend.secrets.webapp import WebAppSecrets
from hotpocket_common.constants import App, Env from hotpocket_common.constants import App, Environment
class PSettings(typing.Protocol): class PSettings(typing.Protocol):
@@ -16,7 +16,7 @@ class PSettings(typing.Protocol):
SECRET_KEY: str SECRET_KEY: str
APP: App APP: App
ENV: Env ENV: Environment
SECRETS: AdminSecrets | WebAppSecrets SECRETS: AdminSecrets | WebAppSecrets
@@ -32,3 +32,9 @@ class PSettings(typing.Protocol):
UPLOADS_PATH: pathlib.Path UPLOADS_PATH: pathlib.Path
AUTH_KEY_TTL: int AUTH_KEY_TTL: int
UI_BASE_HEAD_INCLUDES: list
UI_BASE_SCRIPT_INCLUDES: list
UI_PAGE_HEAD_INCLUDES: list
UI_PAGE_SCRIPT_INCLUDES: list

View File

@@ -82,3 +82,21 @@ def appearance_settings(request: HttpRequest) -> dict:
return { return {
'APPEARANCE_SETTINGS': result, 'APPEARANCE_SETTINGS': result,
} }
def base_includes(request: HttpRequest) -> dict:
return {
'BASE_INCLUDES': {
'head': settings.UI_BASE_HEAD_INCLUDES,
'script': settings.UI_BASE_SCRIPT_INCLUDES,
},
}
def page_includes(request: HttpRequest) -> dict:
return {
'PAGE_INCLUDES': {
'head': settings.UI_PAGE_HEAD_INCLUDES,
'script': settings.UI_PAGE_SCRIPT_INCLUDES,
},
}

View File

@@ -31,11 +31,17 @@
<link rel="icon" type="image/png" sizes="32x32" href="{% static 'ui/img/icon-32.png' %}"> <link rel="icon" type="image/png" sizes="32x32" href="{% static 'ui/img/icon-32.png' %}">
<link rel="icon" type="image/png" sizes="16x16" href="{% static 'ui/img/icon-16.png' %}"> <link rel="icon" type="image/png" sizes="16x16" href="{% static 'ui/img/icon-16.png' %}">
<link rel="manifest" href="{% url 'ui.meta.manifest_json' %}"> <link rel="manifest" href="{% url 'ui.meta.manifest_json' %}">
{% for head_include in BASE_INCLUDES.head %}
{% include head_include %}
{% endfor %}
{% block page_head %}{% endblock %} {% block page_head %}{% endblock %}
</head> </head>
<body class="{% block body_class %}{% endblock %}" hx-headers='{"x-csrftoken": "{{ csrf_token }}"}'> <body class="{% block body_class %}{% endblock %}" hx-headers='{"x-csrftoken": "{{ csrf_token }}"}'>
{% block body %} {% block body %}
{% endblock %} {% endblock %}
{% block scripts %}{% endblock %} {% block scripts %}{% endblock %}
{% for script_include in BASE_INCLUDES.script %}
{% include script_include %}
{% endfor %}
</body> </body>
</html> </html>

View File

@@ -2,6 +2,12 @@
{% load i18n static ui %} {% load i18n static ui %}
{% block page_head %}
{% for head_include in PAGE_INCLUDES.head %}
{% include head_include %}
{% endfor %}
{% endblock %}
{% block body %} {% block body %}
<nav id="navbar" class="navbar navbar-expand-sm bg-body-tertiary fixed-top"> <nav id="navbar" class="navbar navbar-expand-sm bg-body-tertiary fixed-top">
<div class="container"> <div class="container">
@@ -153,7 +159,11 @@
<script src="{% static 'ui/js/hotpocket-backend.ui.BrowseAccountAppsView.js' %}" type="text/javascript"></script> <script src="{% static 'ui/js/hotpocket-backend.ui.BrowseAccountAppsView.js' %}" type="text/javascript"></script>
<script src="{% static 'ui/js/hotpocket-backend.ui.InlineCreateSaveForm.js' %}" type="text/javascript"></script> <script src="{% static 'ui/js/hotpocket-backend.ui.InlineCreateSaveForm.js' %}" type="text/javascript"></script>
<script src="{% static 'ui/js/hotpocket-backend.ui.PasteboardLink.js' %}" type="text/javascript"></script> <script src="{% static 'ui/js/hotpocket-backend.ui.PasteboardLink.js' %}" type="text/javascript"></script>
{% block page_scripts %}{% endblock %} {% for script_include in PAGE_INCLUDES.script %}
{% include script_include %}
{% endfor %}
{% block page_scripts %}
{% endblock %}
<script type="text/javascript"> <script type="text/javascript">
(() => { (() => {
window.HotPocket.run({ window.HotPocket.run({

View File

@@ -3,7 +3,13 @@ from __future__ import annotations
import json import json
from keep_it_secret import AbstractField, LiteralField, Secrets, SecretsField from keep_it_secret import (
AbstractField,
EnvField,
LiteralField,
Secrets,
SecretsField,
)
class DatabaseSecrets(Secrets): class DatabaseSecrets(Secrets):
@@ -84,6 +90,19 @@ class CelerySecrets(Secrets):
result_backend: str = AbstractField.new() result_backend: str = AbstractField.new()
class InitialAccountSecrets(Secrets):
username: str = EnvField.new(
'HOTPOCKET_BACKEND_INITIAL_ACCOUNT_USERNAME',
default=None,
required=False,
)
password: str = EnvField.new(
'HOTPOCKET_BACKEND_INITIAL_ACCOUNT_PASSWORD',
default=None,
required=False,
)
class BaseSecrets(Secrets): class BaseSecrets(Secrets):
SECRET_KEY: str = AbstractField.new() SECRET_KEY: str = AbstractField.new()
@@ -91,3 +110,4 @@ class BaseSecrets(Secrets):
CELERY: CelerySecrets = SecretsField.new(CelerySecrets) CELERY: CelerySecrets = SecretsField.new(CelerySecrets)
OIDC: OIDCSecrets = SecretsField.new(OIDCSecrets) OIDC: OIDCSecrets = SecretsField.new(OIDCSecrets)
INITIAL_ACCOUNT: InitialAccountSecrets = SecretsField.new(InitialAccountSecrets)

View File

@@ -17,6 +17,9 @@ MIDDLEWARE = [
'whitenoise.middleware.WhiteNoiseMiddleware', 'whitenoise.middleware.WhiteNoiseMiddleware',
] ]
SESSION_COOKIE_SAMESITE = 'Lax'
SESSION_COOKIE_SECURE = False
STORAGES['staticfiles'] = { # noqa: F405 STORAGES['staticfiles'] = { # noqa: F405
'BACKEND': 'whitenoise.storage.CompressedManifestStaticFilesStorage', 'BACKEND': 'whitenoise.storage.CompressedManifestStaticFilesStorage',
} }

View File

@@ -19,8 +19,12 @@ ALLOWED_HOSTS = []
ENV = Env(os.getenv('HOTPOCKET_BACKEND_ENV', None)) ENV = Env(os.getenv('HOTPOCKET_BACKEND_ENV', None))
APP = App(os.getenv('HOTPOCKET_BACKEND_APP', None)) APP = App(os.getenv('HOTPOCKET_BACKEND_APP', None))
HOTPOCKET_BACKEND_SECRETS_PACKAGE = os.getenv(
'HOTPOCKET_BACKEND_SECRETS_PACKAGE', 'hotpocket_backend.secrets',
)
SECRETS: BaseSecrets = load_secrets( SECRETS: BaseSecrets = load_secrets(
'hotpocket_backend.secrets', ENV.value, APP.value, HOTPOCKET_BACKEND_SECRETS_PACKAGE, ENV.value, APP.value,
) )
SECRET_KEY = SECRETS.SECRET_KEY SECRET_KEY = SECRETS.SECRET_KEY
@@ -111,6 +115,8 @@ STATIC_URL = 'static/'
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
LOGGING_LEVEL = os.environ.get('HOTPOCKET_BACKEND_LOGGING_LEVEL', 'INFO')
LOG_FORMAT = '%(asctime)s %(levelname)s [%(name)s] [%(request_id)s] (%(funcName)s:%(lineno)s) %(message)s' LOG_FORMAT = '%(asctime)s %(levelname)s [%(name)s] [%(request_id)s] (%(funcName)s:%(lineno)s) %(message)s'
LOGGING = { LOGGING = {
'version': 1, 'version': 1,
@@ -145,17 +151,17 @@ LOGGING = {
'loggers': { 'loggers': {
'hotpocket_backend': { 'hotpocket_backend': {
'handlers': ['hotpocket'], 'handlers': ['hotpocket'],
'level': 'INFO', 'level': LOGGING_LEVEL,
'propagate': False, 'propagate': False,
}, },
'hotpocket_common': { 'hotpocket_common': {
'handlers': ['hotpocket'], 'handlers': ['hotpocket'],
'level': 'INFO', 'level': LOGGING_LEVEL,
'propagate': False, 'propagate': False,
}, },
'hotpocket_soa': { 'hotpocket_soa': {
'handlers': ['hotpocket'], 'handlers': ['hotpocket'],
'level': 'INFO', 'level': LOGGING_LEVEL,
'propagate': False, 'propagate': False,
}, },
'django': { 'django': {

View File

@@ -4,13 +4,15 @@ from __future__ import annotations
from pathlib import Path from pathlib import Path
from hotpocket_common.constants import App, Environment
BASE_DIR = Path(__file__).resolve().parent.parent.parent BASE_DIR = Path(__file__).resolve().parent.parent.parent
DEBUG = False DEBUG = False
ALLOWED_HOSTS = [] ALLOWED_HOSTS = []
ENV = 'build' ENV = Environment('BUILD', 'build')
APP = 'backend' APP = App.WEBAPP
INSTALLED_APPS = [ INSTALLED_APPS = [
'django.contrib.auth', 'django.contrib.auth',

View File

@@ -31,6 +31,11 @@ MIDDLEWARE = [
'django_htmx.middleware.HtmxMiddleware', 'django_htmx.middleware.HtmxMiddleware',
] ]
TEMPLATES[0]['OPTIONS']['context_processors'] += [ # noqa: F405
'hotpocket_backend.apps.ui.context_processors.base_includes',
'hotpocket_backend.apps.ui.context_processors.page_includes',
]
ROOT_URLCONF = 'hotpocket_backend.urls.webapp' ROOT_URLCONF = 'hotpocket_backend.urls.webapp'
LOGIN_REDIRECT_URL = '/accounts/post-login/' LOGIN_REDIRECT_URL = '/accounts/post-login/'
@@ -81,3 +86,9 @@ CORS_ALLOW_HEADERS = (
) )
AUTH_KEY_TTL = 30 AUTH_KEY_TTL = 30
UI_BASE_HEAD_INCLUDES = []
UI_BASE_SCRIPT_INCLUDES = []
UI_PAGE_HEAD_INCLUDES = []
UI_PAGE_SCRIPT_INCLUDES = []

View File

@@ -13,26 +13,21 @@ cat <<EOF
|_| |_|
production production
HotPocket v25.10.21 [${HOTPOCKET_BACKEND_IMAGE_ID}] (https://hotpocket.app/) HotPocket v25.11.06 [${HOTPOCKET_BACKEND_IMAGE_ID}] (https://hotpocket.app/)
Copyright 2025-present by BTHLabs. All rights reserved. (https://bthlabs.pl/) Copyright 2025-present by BTHLabs. All rights reserved. (https://bthlabs.pl/)
Licensed under Apache-2.0 Licensed under Apache-2.0
EOF EOF
export PYTHONPATH="/srv/app:$PYTHONPATH" export PYTHONPATH="/srv/app:$PYTHONPATH"
if [ -n "${HOTPOCKET_BACKEND_RUN_MIGRATIONS}" ];then echo; echo "--- Preparing the system..."
echo; echo "--- Running migrations..."
${VIRTUAL_ENV}/bin/python /srv/app/manage.py migrate UPLOADS_PATH="${HOTPOCKET_BACKEND_UPLOADS_PATH:-/srv/uploads}"
if [ ! -d "${UPLOADS_PATH}" ];then
mkdir -p "${UPLOADS_PATH}"
fi fi
if [[ -n "${HOTPOCKET_BACKEND_INITIAL_ACCOUNT_USERNAME}" && -n "${HOTPOCKET_BACKEND_INITIAL_ACCOUNT_PASSWORD}" ]]; then sudo /srv/bin/fix-run-uploads-permissions.sh ${HOTPOCKET_BACKEND_APP_USER_UID} "${UPLOADS_PATH}"
echo; echo "--- Creating initial Account..."
${VIRTUAL_ENV}/bin/python /srv/app/manage.py create_initial_account "${HOTPOCKET_BACKEND_INITIAL_ACCOUNT_USERNAME}" "${HOTPOCKET_BACKEND_INITIAL_ACCOUNT_PASSWORD}"
fi
if [ "${HOTPOCKET_BACKEND_ENV}" = "aio" ];then
mkdir -p "${HOTPOCKET_BACKEND_UPLOADS_PATH:-/srv/run/uploads}"
fi
echo; echo "--- Running entrypoint.d parts..." echo; echo "--- Running entrypoint.d parts..."
find "/srv/etc/entrypoint.d/" -follow -type f -print | sort -V | while read -r ENTRYPOINT_PART; do find "/srv/etc/entrypoint.d/" -follow -type f -print | sort -V | while read -r ENTRYPOINT_PART; do
@@ -48,6 +43,16 @@ find "/srv/etc/entrypoint.d/" -follow -type f -print | sort -V | while read -r E
esac esac
done done
if [ -n "${HOTPOCKET_BACKEND_RUN_MIGRATIONS}" ];then
echo; echo "--- Running migrations..."
${VIRTUAL_ENV}/bin/python /srv/app/manage.py migrate
fi
if [ -n "${HOTPOCKET_BACKEND_CREATE_INITIAL_ACCOUNT}" ];then
echo; echo "--- Creating initial Account..."
${VIRTUAL_ENV}/bin/python /srv/app/manage.py create_initial_account
fi
echo; echo "--- Setup done, booting the app..."; echo echo; echo "--- Setup done, booting the app..."; echo
exec /usr/bin/dumb-init "$@" exec /usr/bin/dumb-init "$@"

View File

@@ -0,0 +1,9 @@
#!/usr/bin/env bash
echo "Fixing runtime directory permissions..."
chown $1 /srv/run || true
chmod 775 /srv/run
chown $1 $2 || true
chmod 775 $2

View File

@@ -0,0 +1 @@
app ALL=(root) NOPASSWD: /srv/bin/fix-run-uploads-permissions.sh

View File

@@ -1,6 +1,6 @@
{ {
"name": "hotpocket-backend", "name": "hotpocket-backend",
"version": "25.10.21", "version": "25.11.06",
"description": "HotPocket Backend", "description": "HotPocket Backend",
"main": "hotpocket_backend/apps/frontend/src/index.js", "main": "hotpocket_backend/apps/frontend/src/index.js",
"repository": "https://git.bthlabs.pl/tomekwojcik/hotpocket", "repository": "https://git.bthlabs.pl/tomekwojcik/hotpocket",

View File

@@ -1190,14 +1190,14 @@ files = [
[[package]] [[package]]
name = "keep-it-secret" name = "keep-it-secret"
version = "1.2.0" version = "1.3.0"
description = "Keep It Secret by BTHLabs" description = "Keep It Secret by BTHLabs"
optional = false optional = false
python-versions = ">=3.10,<4.0" python-versions = ">=3.10,<4.0"
groups = ["main"] groups = ["main"]
files = [ files = [
{file = "keep_it_secret-1.2.0-py3-none-any.whl", hash = "sha256:aae8f3d3c1db93223ad3afb5c35c2c7202068b082b8bf7d199ed5bc610e63449"}, {file = "keep_it_secret-1.3.0-py3-none-any.whl", hash = "sha256:9efe032bd1efbf18fa0cc15b73e38e17e23ee8a8690ffab948f16368f8eb9126"},
{file = "keep_it_secret-1.2.0.tar.gz", hash = "sha256:2585591d451674e30c08fcdbba95de2180904069da149bca628cc51261720839"}, {file = "keep_it_secret-1.3.0.tar.gz", hash = "sha256:80d6907b296e1f520c1ad30f9748c75ed007bb91ec4db7a83b0cb1b200804f6c"},
] ]
[package.dependencies] [package.dependencies]
@@ -1208,6 +1208,11 @@ hvac = {version = ">=2.1.0", optional = true, markers = "extra == \"vault\""}
aws = ["boto3 (>=1.34.0)"] aws = ["boto3 (>=1.34.0)"]
vault = ["hvac (>=2.1.0)"] vault = ["hvac (>=2.1.0)"]
[package.source]
type = "legacy"
url = "https://nexus.bthlabs.pl/repository/pypi/simple"
reference = "nexus"
[[package]] [[package]]
name = "kombu" name = "kombu"
version = "5.5.4" version = "5.5.4"
@@ -2572,4 +2577,4 @@ brotli = ["brotli"]
[metadata] [metadata]
lock-version = "2.1" lock-version = "2.1"
python-versions = "^3.12" python-versions = "^3.12"
content-hash = "bdbe000a5510f8f6eadb468eaa66df87c65df006c05dbfdde0a660316efbb120" content-hash = "9ea38ee8174f679163c0b46cde1cb4eff4b7330db8a3b4649a7a910bdf5fe15d"

View File

@@ -1,6 +1,6 @@
[tool.poetry] [tool.poetry]
name = "hotpocket-backend" name = "hotpocket-backend"
version = "25.10.21" version = "25.11.06"
description = "HotPocket Backend" description = "HotPocket Backend"
authors = ["Tomek Wójcik <contact@bthlabs.pl>"] authors = ["Tomek Wójcik <contact@bthlabs.pl>"]
license = "Apache-2.0" license = "Apache-2.0"
@@ -22,7 +22,7 @@ django-crispy-forms = "2.4"
django-htmx = "1.26.0" django-htmx = "1.26.0"
hotpocket-common = {path = "../packages/common", develop = true} hotpocket-common = {path = "../packages/common", develop = true}
hotpocket-soa = {path = "../packages/soa", develop = true} hotpocket-soa = {path = "../packages/soa", develop = true}
keep-it-secret = {version = "1.2.0", extras = ["aws", "vault"]} keep-it-secret = {version = "1.3.0", extras = ["aws", "vault"]}
psycopg = {version = "3.2.10", extras = ["binary"]} psycopg = {version = "3.2.10", extras = ["binary"]}
pydantic = "2.12.2" pydantic = "2.12.2"
pyquery = "2.0.1" pyquery = "2.0.1"

View File

@@ -1,6 +1,6 @@
{ {
"name": "hotpocket-extension", "name": "hotpocket-extension",
"version": "25.10.21", "version": "25.11.06",
"description": "HotPocket Extension", "description": "HotPocket Extension",
"main": "src/index.js", "main": "src/index.js",
"repository": "https://git.bthlabs.pl/tomekwojcik/hotpocket", "repository": "https://git.bthlabs.pl/tomekwojcik/hotpocket",

View File

@@ -1,6 +1,6 @@
[tool.poetry] [tool.poetry]
name = "hotpocket-extension" name = "hotpocket-extension"
version = "25.10.21" version = "25.11.06"
description = "HotPocket Extension" description = "HotPocket Extension"
authors = ["Tomek Wójcik <contact@bthlabs.pl>"] authors = ["Tomek Wójcik <contact@bthlabs.pl>"]
license = "Apache-2.0" license = "Apache-2.0"

View File

@@ -13,7 +13,7 @@
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1,viewport-fit=cover,user-scalable=no"> <meta name="viewport" content="width=device-width,initial-scale=1,viewport-fit=cover,user-scalable=no">
<meta name="generator" content="pl.bthlabs.HotPocket.Extension@v25.10.21"> <meta name="generator" content="pl.bthlabs.HotPocket.Extension@v25.11.06">
<meta name="theme-color" content="#2b3035"/> <meta name="theme-color" content="#2b3035"/>
<title>HotPocket by BTHLabs</title> <title>HotPocket by BTHLabs</title>
<link rel="icon" type="image/png" sizes="32x32" href="data:image/png;base64,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"> <link rel="icon" type="image/png" sizes="32x32" href="data:image/png;base64,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">
@@ -79,7 +79,7 @@ body, html {
</div> </div>
<p class="mb-0 mt-2 text-center text-muted ui-uname"> <p class="mb-0 mt-2 text-center text-muted ui-uname">
<span> <span>
<a href="https://hotpocket.app/" target="_blank" rel="noopener noreferer">HotPocket by BTHLabs</a> v25.10.21 <a href="https://hotpocket.app/" target="_blank" rel="noopener noreferer">HotPocket by BTHLabs</a> v25.11.06
</span> </span>
<br> <br>
<span>Copyright &copy; 2025-present by BTHLabs. All rights reserved.</span> <span>Copyright &copy; 2025-present by BTHLabs. All rights reserved.</span>

View File

@@ -3,7 +3,7 @@
"default_locale": "en", "default_locale": "en",
"name": "__MSG_extension_name__", "name": "__MSG_extension_name__",
"description": "__MSG_extension_description__", "description": "__MSG_extension_description__",
"version": "25.10.21", "version": "25.11.06",
"icons": { "icons": {
"16": "images/icon-16.png", "16": "images/icon-16.png",
"32": "images/icon-32.png", "32": "images/icon-32.png",

View File

@@ -1,3 +1,3 @@
from .accounts import AccessTokenOriginApp # noqa: F401 from .accounts import AccessTokenOriginApp # noqa: F401
from .associations import AssociationsSearchMode # noqa: F401 from .associations import AssociationsSearchMode # noqa: F401
from .core import NULL_UUID, App, Env # noqa: F401 from .core import NULL_UUID, App, Env, Environment # noqa: F401

View File

@@ -2,16 +2,69 @@
from __future__ import annotations from __future__ import annotations
import enum import enum
import typing
import uuid import uuid
NULL_UUID = uuid.UUID('00000000-0000-0000-0000-000000000000') NULL_UUID = uuid.UUID('00000000-0000-0000-0000-000000000000')
class Env(enum.Enum): class Environment:
METAL = 'metal' def __init__(self, name: str, value: str):
DOCKER = 'docker' self._name = name
DEPLOYMENT = 'deployment' self._value = value
AIO = 'aio'
@property
def name(self) -> str:
return self._name
@property
def value(self) -> str:
return self._value
def __repr__(self) -> str:
return f'<Env {self.name}: {self.value}>'
def __str__(self) -> str:
return self.name
def to_rpc(self) -> str:
return self.value
class Environments:
METAL = Environment('METAL', 'metal')
DOCKER = Environment('DOCKER', 'docker')
DEPLOYMENT = Environment('DEPLOYMENT', 'deployment')
AIO = Environment('AIO', 'aio')
def _current_envs(self) -> typing.Generator[Environment, None, None]:
for attribute in dir(self):
candidate = getattr(self, attribute)
if isinstance(candidate, Environment):
yield candidate
def __call__(self, value: str) -> Environment:
result: Environment | None = None
for candidate in self._current_envs():
if candidate.value == value:
result = candidate
break
if result is None:
raise ValueError(f'Could not resolve env: `{value}`')
return result
def choices(self) -> list[tuple[str, str]]:
result = []
for env in self._current_envs():
result.append((env.value, env.name))
return result
Env = Environments()
class App(enum.Enum): class App(enum.Enum):

View File

@@ -146,6 +146,7 @@ def build(ctx: Context,
image_tag=None, image_tag=None,
machine=None, machine=None,
platform=None, platform=None,
registry='docker-hosted.nexus.bthlabs.pl',
): ):
image_tag = image_tag or '{target}.{{short_sha}}'.format(target=target) image_tag = image_tag or '{target}.{{short_sha}}'.format(target=target)
@@ -178,7 +179,7 @@ def build(ctx: Context,
if platform is not None if platform is not None
else '' else ''
), ),
f'-t docker-hosted.nexus.bthlabs.pl/hotpocket/{service}:{docker_build_ctx.tag}', # noqa: E501 f'-t {registry}/hotpocket/{service}:{docker_build_ctx.tag}', # noqa: E501
f'-f services/{service}/Dockerfile', f'-f services/{service}/Dockerfile',
f'--build-arg IMAGE_ID={image_tag}', f'--build-arg IMAGE_ID={image_tag}',
f'--target {docker_build_ctx.target}', f'--target {docker_build_ctx.target}',
@@ -290,5 +291,5 @@ def bump_version(ctx: Context,
f'inv bump-version {next_version} --build {build}', f'inv bump-version {next_version} --build {build}',
) )
if 'backend' in services_to_bump: if service is None:
tools_bump_version_task(ctx, next_version, build=build) tools_bump_version_task(ctx, next_version, build=build)