diff --git a/.dockerignore b/.dockerignore
new file mode 100644
index 00000000..46fb3ddf
--- /dev/null
+++ b/.dockerignore
@@ -0,0 +1,26 @@
+.composer/
+.editorconfig
+.env*
+.git/
+.gitattributes
+.github/
+.gitignore
+.idea/
+.sops.yaml
+
+codestyle.php
+docker-compose*
+eslint.config.js
+Taskfile.yml
+node_modules/
+phpstan*
+public/build/
+public/hot
+readme.md
+renovate.json5
+vendor/
+
+/environment
+!/environment/.deployment/scripts/post-deploy-actions.sh
+!/environment/.docker
+!/environment/dev
diff --git a/.env.example b/.env.example
index 121994b8..8a0ebf77 100644
--- a/.env.example
+++ b/.env.example
@@ -3,7 +3,11 @@ APP_ENV=local
APP_KEY=
APP_DEBUG=true
APP_TIMEZONE=Europe/Warsaw
-APP_URL=http://lmt.blumilk.localhost
+APP_URL=https://lmt.blumilk.local.env
+
+APP_DOCKER_HOST_NAME=lmt.blumilk.local.env
+MAILPIT_DOCKER_HOST_NAME=lmt-mailpit.blumilk.local.env
+VITE_DEV_SERVER_DOCKER_HOST_NAME=lmt-vite-dev-server.blumilk.local.env
APP_LOCALE=pl
APP_FALLBACK_LOCALE=en
@@ -21,7 +25,7 @@ LOG_DEPRECATIONS_CHANNEL=null
LOG_LEVEL=debug
DB_CONNECTION=pgsql
-DB_HOST=lmt-db-dev
+DB_HOST=lmt-db-local
DB_PORT=5432
DB_DATABASE=lmt
DB_USERNAME=lmt
@@ -41,7 +45,7 @@ CACHE_STORE=database
CACHE_PREFIX=
MAIL_MAILER=smtp
-MAIL_HOST=lmt-dev-mailpit-container
+MAIL_HOST=lmt-mailpit-local
MAIL_PORT=1025
MAIL_USERNAME=null
MAIL_PASSWORD=null
@@ -51,6 +55,7 @@ REGISTRATION_NOTIFICATION_EMAIL="hello@example.com"
VITE_APP_NAME="${APP_NAME}"
+SOPS_AGE_DEV_SECRET_KEY=
SOPS_AGE_PROD_SECRET_KEY=
DOCKER_APP_HOST_PORT=8051
@@ -58,3 +63,5 @@ DOCKER_DATABASE_HOST_PORT=8055
DOCKER_MAILPIT_DASHBOARD_HOST_PORT=8052
DOCKER_HOST_USER_ID=1000
+DOCKER_INSTALL_XDEBUG=false
+ALLOWED_EMAIL_DOMAIN=@example.com
diff --git a/.github/workflows/deploy-to-dev.yml b/.github/workflows/deploy-to-dev.yml
index beb372a2..c8fafa75 100644
--- a/.github/workflows/deploy-to-dev.yml
+++ b/.github/workflows/deploy-to-dev.yml
@@ -18,6 +18,7 @@ jobs:
DOCKER_REGISTRY_PROJECT_NAME: internal-public
DOCKER_REGISTRY_REPO_NAME: lmt
TARGET_DIR_ON_SERVER: /blumilk/deployments/dev/projects
+ ENVIRONMENT: dev
steps:
- name: set branch name
run: echo "BRANCH_NAME=$GITHUB_REF_NAME" >> $GITHUB_ENV
@@ -27,3 +28,141 @@ jobs:
with:
fetch-depth: 0
ref: ${{ env.BRANCH_NAME }}
+
+ - name: sync with main branch
+ run: |
+ git config user.name "GitHub Actions Bot"
+ git config user.email "<>"
+ git merge --no-commit --no-ff origin/main
+
+ - name: set deployment project version
+ run: echo "DEPLOYMENT_PROJECT_VERSION=$(bash ./environment/.deployment/scripts/version.sh --long)" >> $GITHUB_ENV
+
+ - name: set docker image name
+ run: echo "DOCKER_IMAGE_NAME=${{ env.DOCKER_REGISTRY }}/${{ env.DOCKER_REGISTRY_PROJECT_NAME }}/${{ env.DOCKER_REGISTRY_REPO_NAME }}" >> $GITHUB_ENV
+
+ - name: fetch server secrets
+ uses: Infisical/secrets-action@v1.0.8
+ with:
+ domain: https://infisical.blumilk.pl
+ client-id: ${{ secrets.INFISICAL_MACHINE_IDENTITY_GHA_BOT_CLIENT_ID }}
+ client-secret: ${{ secrets.INFISICAL_MACHINE_IDENTITY_GHA_BOT_CLIENT_SECRET }}
+ project-slug: blumilk-infra-pv-ih
+ env-slug: infra
+ secret-path: /servers/ovh/ns31445530
+ export-type: env
+ recursive: true
+ include-imports: true
+
+ - name: set up Docker Buildx
+ uses: docker/setup-buildx-action@988b5a0280414f521da01fcc63a27aeeb4b104db # v3.6.1
+
+ - name: login to Docker Registry
+ uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 # v3.3.0
+ with:
+ registry: ${{ env.DOCKER_REGISTRY }}
+ username: ${{ env.DOCKER_REGISTRY_USER_NAME }}
+ password: ${{ env.HARBOR_ROBOT_BLUMILKBOT_TOKEN }} # masked secret fetched from Infisical
+
+ - name: set docker app database image name
+ run: echo "DOCKER_APP_DATABASE_IMAGE_NAME=${{ env.DOCKER_REGISTRY }}/${{ env.DOCKER_REGISTRY_PROJECT_NAME }}/${{ env.DOCKER_REGISTRY_REPO_NAME }}-postgres" >> $GITHUB_ENV
+
+
+ - name: Docker meta for app database
+ id: meta-app-database
+ uses: docker/metadata-action@v5.5.1
+ with:
+ images: |
+ ${{ env.DOCKER_APP_DATABASE_IMAGE_NAME }}
+ tags: |
+ type=raw,value=dev
+ context: workflow
+
+ - name: build and push app database image
+ uses: docker/build-push-action@v5.1.0
+ with:
+ context: .
+ file: ./environment/.docker/postgres/Dockerfile
+ labels: ${{ steps.meta-app-database.outputs.labels }}
+ tags: ${{ steps.meta-app-database.outputs.tags }}
+ push: true
+ cache-from: type=gha, ref=${{ env.DOCKER_APP_DATABASE_IMAGE_NAME }}-dev-build-cache
+ cache-to: type=gha, ref=${{ env.DOCKER_APP_DATABASE_IMAGE_NAME }}-dev-build-cache, mode=max
+
+ - name: Docker meta for app
+ id: meta
+ uses: docker/metadata-action@8e5442c4ef9f78752691e2d8f8d19755c6f78e81 # v5.5.1
+ with:
+ images: ${{ env.DOCKER_IMAGE_NAME }}
+ tags: |
+ type=raw,value=dev
+ context: workflow
+
+ - name: build and push app image
+ uses: docker/build-push-action@ca052bb54ab0790a636c9b5f226502c73d547a25 # v5.4.0
+ with:
+ context: .
+ file: ./environment/.docker/app/Dockerfile
+ target: production
+ build-args: |
+ DEPLOYMENT_PROJECT_VERSION_ARG=${{ env.DEPLOYMENT_PROJECT_VERSION }}
+ ENVIRONMENT=${{ env.ENVIRONMENT }}
+ labels: ${{ steps.meta.outputs.labels }}
+ tags: ${{ steps.meta.outputs.tags }}
+ push: true
+ cache-from: type=gha, ref=${{ env.DOCKER_IMAGE_NAME }}-dev-build-cache
+ cache-to: type=gha, ref=${{ env.DOCKER_IMAGE_NAME }}-dev-build-cache, mode=max
+
+ - name: set deployment path on server
+ run: echo "DEPLOYMENT_PATH_ON_SERVER=${{ env.TARGET_DIR_ON_SERVER }}/${{ env.DOCKER_REGISTRY_PROJECT_NAME }}/${{ env.DOCKER_REGISTRY_REPO_NAME }}" >> $GITHUB_ENV
+
+ - name: copy files via ssh
+ uses: appleboy/scp-action@917f8b81dfc1ccd331fef9e2d61bdc6c8be94634 # v0.1.7
+ with:
+ timeout: 10s
+ command_timeout: 10m
+ host: ${{ env.SERVER_OVH_NS31445530_IP }} # masked secret fetched from Infisical
+ port: ${{ env.SERVER_OVH_NS31445530_SSH_PORT }} # masked secret fetched from Infisical
+ username: ${{ env.SERVER_OVH_NS31445530_BLUMILKBOT_USER_NAME }} # masked secret fetched from Infisical
+ key: ${{ env.SERVER_OVH_NS31445530_BLUMILKBOT_USER_SSH_PRIVATE_KEY }} # masked secret fetched from Infisical
+ passphrase: ${{ env.SERVER_OVH_NS31445530_BLUMILKBOT_USER_SSH_PRIVATE_KEY_PASSPHRASE }} # masked secret fetched from Infisical
+ source: "./environment/.deployment/dev/*,./environment/.deployment/Taskfile.yml"
+ target: ${{ env.DEPLOYMENT_PATH_ON_SERVER }}
+ rm: true
+
+
+ - name: fetch project deployment secrets
+ uses: Infisical/secrets-action@v1.0.8
+ with:
+ domain: https://infisical.blumilk.pl
+ client-id: ${{ secrets.INFISICAL_MACHINE_IDENTITY_GHA_BOT_CLIENT_ID }}
+ client-secret: ${{ secrets.INFISICAL_MACHINE_IDENTITY_GHA_BOT_CLIENT_SECRET }}
+ project-slug: lmt-d-hr8
+ env-slug: dev
+ secret-path: /deployment
+ export-type: env
+ recursive: false
+ include-imports: false
+
+ - name: run deployment script over ssh
+ uses: appleboy/ssh-action@v1.2.2
+ with:
+ timeout: 10s
+ command_timeout: 10m
+ host: ${{ env.SERVER_OVH_NS31445530_IP }} # masked secret fetched from Infisical
+ port: ${{ env.SERVER_OVH_NS31445530_SSH_PORT }} # masked secret fetched from Infisical
+ username: ${{ env.SERVER_OVH_NS31445530_BLUMILKBOT_USER_NAME }} # masked secret fetched from Infisical
+ key: ${{ env.SERVER_OVH_NS31445530_BLUMILKBOT_USER_SSH_PRIVATE_KEY }} # masked secret fetched from Infisical
+ passphrase: ${{ env.SERVER_OVH_NS31445530_BLUMILKBOT_USER_SSH_PRIVATE_KEY_PASSPHRASE }} # masked secret fetched from Infisical
+ # masked secrets from Infisical: HARBOR_ROBOT_BLUMILKBOT_TOKEN, SOPS_AGE_DEV_SECRET_KEY
+ script: |
+ cd ${{ env.DEPLOYMENT_PATH_ON_SERVER }}/environment/.deployment/
+ mv Taskfile.yml ${{ env.ENVIRONMENT }}/
+ cd ${{ env.ENVIRONMENT }}/
+ echo ${{ env.HARBOR_ROBOT_BLUMILKBOT_TOKEN }} | docker login ${{ env.DOCKER_REGISTRY }} --username ${{ env.DOCKER_REGISTRY_USER_NAME }} --password-stdin
+ export SOPS_AGE_KEY=${{ env.SOPS_AGE_DEV_SECRET_KEY }}
+ export ENVIRONMENT=${{ env.ENVIRONMENT }}
+ task deploy
+ docker images --filter dangling=true | grep "${{ env.DOCKER_IMAGE_NAME }}" | awk '{print $3}'| xargs --no-run-if-empty docker rmi
+ docker images --filter dangling=true | grep ${{ env.DOCKER_APP_DATABASE_IMAGE_NAME }} | awk '{print $3}'| xargs --no-run-if-empty docker rmi
+ docker logout ${{ env.DOCKER_REGISTRY }}
diff --git a/.github/workflows/deploy-to-prod-init.yml b/.github/workflows/deploy-to-prod-init.yml
deleted file mode 100644
index eb7111dc..00000000
--- a/.github/workflows/deploy-to-prod-init.yml
+++ /dev/null
@@ -1,87 +0,0 @@
-name: Deploy to production
-
-concurrency:
- group: deploy-prod
- cancel-in-progress: false
-
-on:
- release:
- types: [ published ]
- workflow_dispatch:
-
-jobs:
- deploy:
- environment: production
- runs-on: ubuntu-22.04
- name: Deploy to production
- env:
- DOCKER_REGISTRY: ghcr.io
- REPO_NAME: ${{ github.event.repository.name }}
- REPO_OWNER: ${{ github.repository_owner }}
- TARGET_DIR_ON_SERVER: /blumilk/production
- steps:
- - name: checkout
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
-
- - name: set deployment project version
- run: echo "DEPLOYMENT_PROJECT_VERSION=$(bash ./environment/prod/deployment/scripts/version.sh --long)" >> $GITHUB_ENV
-
- - name: set up Docker Buildx
- uses: docker/setup-buildx-action@6524bf65af31da8d45b59e8c27de4bd072b392f5 # v3.8.0
-
- - name: login to GitHub Container Registry
- uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 # v3
- with:
- registry: ${{ env.DOCKER_REGISTRY }}
- username: ${{ github.actor }}
- password: ${{ github.token }}
-
- - name: Docker meta
- id: meta
- uses: docker/metadata-action@369eb591f429131d6889c46b94e711f089e6ca96 # v5.6.1
- with:
- images: ${{ env.DOCKER_REGISTRY }}/${{ github.repository_owner }}/${{ env.REPO_NAME }}
- tags: |
- type=raw,value=latest
- context: workflow
-
- - name: build and push image
- uses: docker/build-push-action@ca877d9245402d1537745e0e356eab47c3520991 # v6.13.0
- with:
- context: .
- file: ./environment/prod/app/Dockerfile
- build-args: DEPLOYMENT_PROJECT_VERSION_ARG=${{ env.DEPLOYMENT_PROJECT_VERSION }}
- push: true
- labels: ${{ steps.meta.outputs.labels }}
- tags: ${{ steps.meta.outputs.tags }}
- cache-from: type=gha, ref=${{ env.DOCKER_REGISTRY }}/${{ github.repository_owner }}/${{ env.REPO_NAME }}-prod-build-cache
- cache-to: type=gha, ref=${{ env.DOCKER_REGISTRY }}/${{ github.repository_owner }}/${{ env.REPO_NAME }}-prod-build-cache, mode=max
-
- - name: copy files via ssh
- uses: appleboy/scp-action@917f8b81dfc1ccd331fef9e2d61bdc6c8be94634 # v0.1.7
- with:
- timeout: 10s
- command_timeout: 10m
- host: ${{ secrets.VPS_OVH_BF7EC892_HOST }}
- port: ${{ secrets.VPS_OVH_BF7EC892_PORT }}
- username: ${{ secrets.VPS_OVH_BF7EC892_USERNAME }}
- key: ${{ secrets.VPS_OVH_BF7EC892_SSH_PRIVATE_KEY }}
- passphrase: ${{ secrets.VPS_OVH_BF7EC892_SSH_PRIVATE_KEY_PASSPHRASE }}
- source: "./environment/prod/deployment/prod/*,./environment/prod/deployment/scripts/*"
- target: ${{ env.TARGET_DIR_ON_SERVER }}/${{ env.REPO_NAME }}
- rm: true
-
- - uses: appleboy/ssh-action@7eaf76671a0d7eec5d98ee897acda4f968735a17 # v1.2.0
- with:
- timeout: 10s
- command_timeout: 10m
- host: ${{ secrets.VPS_OVH_BF7EC892_HOST }}
- port: ${{ secrets.VPS_OVH_BF7EC892_PORT }}
- username: ${{ secrets.VPS_OVH_BF7EC892_USERNAME }}
- key: ${{ secrets.VPS_OVH_BF7EC892_SSH_PRIVATE_KEY }}
- passphrase: ${{ secrets.VPS_OVH_BF7EC892_SSH_PRIVATE_KEY_PASSPHRASE }}
- script_stop: true
- script: |
- cd ${{ env.TARGET_DIR_ON_SERVER }}/${{ env.REPO_NAME }}/environment/prod/deployment/prod
- make prod-deploy SOPS_AGE_KEY=${{ secrets.SOPS_AGE_PROD_SECRET_KEY }}
- docker images --filter dangling=true | grep "${{ env.DOCKER_REGISTRY }}/${{ env.REPO_OWNER }}/${{ env.REPO_NAME }}" | awk '{print $3}'| xargs --no-run-if-empty docker rmi
diff --git a/.gitignore b/.gitignore
index d5c76a03..7322f145 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,8 +1,8 @@
.idea
.vscode
/vendor/
+*.decrypted
.env
-.env.prod.secrets.decrypted
/cache/*
!/cache/.gitkeep
node_modules/
diff --git a/.sops.yaml b/.sops.yaml
index 3d63c84f..7ccac98d 100644
--- a/.sops.yaml
+++ b/.sops.yaml
@@ -1,5 +1,10 @@
creation_rules:
+ - name: dev
+ path_regex: \.env\.dev\.secrets.*$
+ age: >-
+ age1m3ruqh8ldq9wy9w5rpyj2wed0nc0n4ejda2lau2009w2rlvu7qjqacfqp2
+
- name: prod
path_regex: \.env\.prod\.secrets.*$
age: >-
diff --git a/Makefile b/Makefile
deleted file mode 100644
index cd3f5c80..00000000
--- a/Makefile
+++ /dev/null
@@ -1,59 +0,0 @@
-include .env
-
-SHELL := /bin/bash
-
-DOCKER_COMPOSE_FILE = docker-compose.yml
-DOCKER_COMPOSE_APP_CONTAINER = app
-
-CURRENT_USER_ID = $(shell id --user)
-CURRENT_USER_GROUP_ID = $(shell id --group)
-CURRENT_DIR = $(shell pwd)
-PHP_SERVICE_NAME=app
-
-DATABASE_USERNAME=lmt
-TEST_DATABASE_NAME=lmt-test
-
-build:
- docker compose build --pull
-
-run:
- docker compose up -d
-
-dev:
- docker compose exec --user ${CURRENT_USER_ID} ${PHP_SERVICE_NAME} npm run dev
-
-stop:
- docker compose stop
-
-restart: stop run
-
-lint:
- docker compose exec --user ${CURRENT_USER_ID} ${PHP_SERVICE_NAME} npm run lint
-
-lintf:
- docker compose exec --user ${CURRENT_USER_ID} ${PHP_SERVICE_NAME} npm run lintf
-
-shell:
- @docker compose exec --user ${CURRENT_USER_ID} ${PHP_SERVICE_NAME} bash
-
-encrypt-prod-secrets:
- @$(MAKE) encrypt-secrets SECRETS_ENV=prod
-
-decrypt-prod-secrets:
- @$(MAKE) decrypt-secrets SECRETS_ENV=prod AGE_SECRET_KEY=${SOPS_AGE_PROD_SECRET_KEY}
-
-decrypt-secrets:
- @docker compose --file ${DOCKER_COMPOSE_FILE} exec --user "${CURRENT_USER_ID}:${CURRENT_USER_GROUP_ID}" --env SOPS_AGE_KEY=${AGE_SECRET_KEY} ${DOCKER_COMPOSE_APP_CONTAINER} \
- bash -c "echo 'Decrypting ${SECRETS_ENV} secrets' \
- && cd ./environment/prod/deployment/${SECRETS_ENV} \
- && sops --decrypt --input-type=dotenv --output-type=dotenv --output .env.${SECRETS_ENV}.secrets.decrypted .env.${SECRETS_ENV}.secrets \
- && echo 'Done'"
-
-encrypt-secrets:
- @docker compose --file ${DOCKER_COMPOSE_FILE} exec --user "${CURRENT_USER_ID}:${CURRENT_USER_GROUP_ID}" ${DOCKER_COMPOSE_APP_CONTAINER} \
- bash -c "echo 'Encrypting ${SECRETS_ENV} secrets' \
- && cd ./environment/prod/deployment/${SECRETS_ENV} \
- && sops --encrypt --input-type=dotenv --output-type=dotenv --output .env.${SECRETS_ENV}.secrets .env.${SECRETS_ENV}.secrets.decrypted \
- && echo 'Done'"
-
-.PHONY: build run tailwind stop restart shell encrypt-prod-secrets decrypt-prod-secrets decrypt-secrets encrypt-secrets dev
diff --git a/Taskfile.yml b/Taskfile.yml
new file mode 100644
index 00000000..ed3099b8
--- /dev/null
+++ b/Taskfile.yml
@@ -0,0 +1,138 @@
+# https://taskfile.dev
+version: "3.42.1"
+
+silent: true
+
+env:
+ COMPOSE_DOCKER_CLI_BUILD: 1
+ DOCKER_BUILDKIT: 1
+ CURRENT_USER_ID:
+ sh: id --user
+ DOCKER_COMPOSE_APP_CONTAINER: app
+ DOCKER_COMPOSE_DATABASE_CONTAINER: database
+
+dotenv:
+ - .env
+
+includes:
+ secops: ./environment/secops-Taskfile.yml
+ devops: ./environment/devops-Taskfile.yml
+
+tasks:
+ default:
+ desc: "List all available tasks"
+ cmds:
+ - task --list-all
+
+ init-project:
+ desc: "Initialize the project"
+ aliases: [init]
+ deps: [run]
+ cmds:
+ - cmd: docker compose exec --user $CURRENT_USER_ID $DOCKER_COMPOSE_APP_CONTAINER composer install
+ - task: _set-app-key
+ - cmd: docker compose exec --user $CURRENT_USER_ID $DOCKER_COMPOSE_APP_CONTAINER php artisan migrate --seed
+ - cmd: docker compose exec --user $CURRENT_USER_ID $DOCKER_COMPOSE_APP_CONTAINER php artisan storage:link
+ - cmd: docker compose exec --user $CURRENT_USER_ID $DOCKER_COMPOSE_APP_CONTAINER npm install
+ - task: create-test-database
+
+ dev:
+ desc: "Run Vite local dev server"
+ deps: [run]
+ cmds:
+ - cmd: docker compose exec --user $CURRENT_USER_ID $DOCKER_COMPOSE_APP_CONTAINER npm run dev
+
+ run-containers:
+ desc: "Run containers"
+ aliases: [run]
+ deps: [build]
+ preconditions:
+ - sh: test -f .env
+ msg: "Please create .env for app."
+ cmds:
+ - cmd: docker compose up --detach
+
+ stop-containers:
+ desc: "Stop containers"
+ aliases: [stop]
+ cmds:
+ - cmd: docker compose stop
+
+ restart-containers:
+ desc: "Restart containers"
+ aliases: [restart]
+ cmds:
+ - task: stop-containers
+ - task: run-containers
+
+ build-containers:
+ desc: "Build containers"
+ aliases: [build]
+ cmds:
+ - cmd: docker compose build --pull
+
+ shell-app:
+ desc: "Enter app shell"
+ aliases: [shell]
+ deps: [run]
+ cmds:
+ - cmd: docker compose exec --user $CURRENT_USER_ID $DOCKER_COMPOSE_APP_CONTAINER bash
+
+ shell-app-root:
+ desc: "Enter app shell as root"
+ aliases: [shell-root]
+ deps: [run]
+ cmds:
+ - cmd: docker compose exec --user root $DOCKER_COMPOSE_APP_CONTAINER bash
+
+ test:
+ desc: "Run tests"
+ deps: [run]
+ cmds:
+ - cmd: docker compose exec --user $CURRENT_USER_ID $DOCKER_COMPOSE_APP_CONTAINER composer test
+
+ fix:
+ desc: "Run fixers"
+ deps: [run]
+ cmds:
+ - cmd: docker compose exec --user $CURRENT_USER_ID $DOCKER_COMPOSE_APP_CONTAINER composer csf
+
+ analyse:
+ desc: "Run composer analyse"
+ deps: [run]
+ cmds:
+ - cmd: docker compose exec --user $CURRENT_USER_ID $DOCKER_COMPOSE_APP_CONTAINER composer analyse
+
+ type-check:
+ desc: "Run npm type-check"
+ deps: [run]
+ cmds:
+ - cmd: docker compose exec --user $CURRENT_USER_ID $DOCKER_COMPOSE_APP_CONTAINER npm run type-check
+
+ queue:
+ desc: "Run queue:work"
+ deps: [run]
+ cmds:
+ - cmd: docker compose exec --user $CURRENT_USER_ID $DOCKER_COMPOSE_APP_CONTAINER php artisan queue:work
+
+ create-test-database:
+ desc: "Create test database"
+ deps: [run]
+ aliases: [create-test-db]
+ vars:
+ TEST_DB_NAME: lmt-test
+ cmds:
+ - cmd: docker compose exec $DOCKER_COMPOSE_DATABASE_CONTAINER bash -c "createdb --username=$DB_USERNAME {{ .TEST_DB_NAME }} && echo 'Created database for tests ({{ .TEST_DB_NAME }}).'"
+ ignore_error: true
+
+ _set-app-key:
+ desc: "Create APP_KEY if not set"
+ internal: true
+ cmds:
+ - |
+ APP_KEY_VALUE=$(grep APP_KEY .env | cut --delimiter '=' --fields 2-)
+
+ if [ -z "${APP_KEY_VALUE}" ]; then
+ echo "APP_KEY is not set. Creating:"
+ docker compose exec $DOCKER_COMPOSE_APP_CONTAINER php artisan key:generate
+ fi
diff --git a/app/Models/User.php b/app/Models/User.php
index 904a5220..2e1319eb 100644
--- a/app/Models/User.php
+++ b/app/Models/User.php
@@ -5,6 +5,8 @@
namespace Blumilksoftware\Lmt\Models;
use database\factories\UserFactory;
+use Filament\Models\Contracts\FilamentUser;
+use Filament\Panel;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Support\Carbon;
@@ -18,7 +20,7 @@
* @property Carbon $created_at
* @property Carbon $updated_at
*/
-class User extends Authenticatable
+class User extends Authenticatable implements FilamentUser
{
/** @use HasFactory */
use HasFactory;
@@ -29,6 +31,11 @@ class User extends Authenticatable
"remember_token",
];
+ public function canAccessPanel(Panel $panel): bool
+ {
+ return str_ends_with($this->email, config("app.allowed_email_domain"));
+ }
+
protected function casts(): array
{
return [
diff --git a/bootstrap/app.php b/bootstrap/app.php
index d5b09ce6..83e485ba 100644
--- a/bootstrap/app.php
+++ b/bootstrap/app.php
@@ -12,6 +12,7 @@
health: "/up",
)
->withMiddleware(function (Middleware $middleware): void {
+ $middleware->trustProxies(at: "*");
})
->withExceptions(function (Exceptions $exceptions): void {
})->create();
diff --git a/config/app.php b/config/app.php
index 1c531b92..9e4ac8a9 100644
--- a/config/app.php
+++ b/config/app.php
@@ -22,4 +22,5 @@
"driver" => env("APP_MAINTENANCE_DRIVER", "file"),
"store" => env("APP_MAINTENANCE_STORE", "database"),
],
+ "allowed_email_domain" => env("ALLOWED_EMAIL_DOMAIN", "@example.com"),
];
diff --git a/docker-compose.yml b/docker-compose.yml
index f145cfe6..0c2a54b5 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -1,7 +1,7 @@
networks:
- lmt-dev:
+ lmt-local:
driver: bridge
- traefik-proxy-blumilk-local:
+ traefik-proxy-blumilk-local-environment:
external: true
volumes:
@@ -10,42 +10,52 @@ volumes:
services:
app:
+ container_name: lmt-app-local
build:
- context: ./environment/dev/app
- dockerfile: Dockerfile
+ context: .
+ dockerfile: environment/.docker/app/Dockerfile
+ target: local
args:
+ - INSTALL_XDEBUG=${DOCKER_INSTALL_XDEBUG:-false}
- USER_ID=${DOCKER_HOST_USER_ID:-1000}
labels:
- "traefik.enable=true"
- - "traefik.blumilk.environment=true"
+ - "traefik.blumilk.local.environment=true"
# HTTP
- - "traefik.http.routers.lmt-http-router.rule=Host(`lmt.blumilk.localhost`)"
+ - "traefik.http.routers.lmt-http-router.rule=Host(`${APP_DOCKER_HOST_NAME}`)"
- "traefik.http.routers.lmt-http-router.entrypoints=web"
- # HTTP to HTTPS redirect
- # - "traefik.http.routers.lmt-http-router.middlewares=https-redirect@file"
+ - "traefik.http.routers.lmt-http-router.service=lmt-app"
# HTTPS
- - "traefik.http.routers.lmt-https-router.rule=Host(`lmt.blumilk.localhost`)"
+ - "traefik.http.routers.lmt-https-router.rule=Host(`${APP_DOCKER_HOST_NAME}`)"
- "traefik.http.routers.lmt-https-router.entrypoints=websecure"
- "traefik.http.routers.lmt-https-router.tls=true"
- container_name: lmt-dev-app-container
+ - "traefik.http.routers.lmt-https-router.service=lmt-app"
+ # APP LOADBALANCER
+ - "traefik.http.services.lmt-app.loadbalancer.server.port=80"
+ # VITE DEV SERVER
+ - "traefik.http.routers.lmt-vite-dev-server-https-router.rule=Host(`${VITE_DEV_SERVER_DOCKER_HOST_NAME}`)"
+ - "traefik.http.routers.lmt-vite-dev-server-https-router.entrypoints=websecure"
+ - "traefik.http.routers.lmt-vite-dev-server-https-router.tls=true"
+ - "traefik.http.routers.lmt-vite-dev-server-https-router.service=lmt-vite-dev-server"
+ - "traefik.http.services.lmt-vite-dev-server.loadbalancer.server.port=5173"
working_dir: /application
volumes:
- - ./environment/dev/app/nginx.conf:/etc/nginx/nginx.conf:ro
- - ./environment/dev/app/php.ini:/usr/local/etc/php/conf.d/zzz-overrides.ini:ro
- - ./environment/dev/app/php-fpm.conf:/usr/local/etc/php-fpm.d/zzz-overrides.conf:ro
- - ./environment/dev/app/supervisord.conf:/etc/supervisor/custom-supervisord.conf:ro
+ - ./environment/local/app/php.ini:/usr/local/etc/php/conf.d/zzz-overrides.ini:ro
+ - ./environment/local/app/php-fpm.conf:/usr/local/etc/php-fpm.d/zzz-overrides.conf:ro
+ - ./environment/local/app/supervisord.conf:/etc/supervisor/custom-supervisord.conf:ro
- .:/application
ports:
- ${DOCKER_APP_HOST_PORT:-8051}:80
networks:
- - lmt-dev
- - traefik-proxy-blumilk-local
+ - lmt-local
+ - traefik-proxy-blumilk-local-environment
restart: unless-stopped
database:
build:
- context: environment/dev/postgres
- container_name: lmt-db-dev
+ context: .
+ dockerfile: environment/.docker/postgres/Dockerfile
+ container_name: lmt-db-local
environment:
- POSTGRES_USER=${DB_USERNAME}
- POSTGRES_PASSWORD=${DB_PASSWORD}
@@ -61,30 +71,28 @@ services:
volumes:
- lmt-postgres-data:/var/lib/postgresql/data
networks:
- - lmt-dev
+ - lmt-local
restart: unless-stopped
mailpit:
image: axllent/mailpit:v1.22.0@sha256:1ebd4123a99eb6b74799d13d4811f9fc5c3b70df26e1ae536af82987022fcb48
- container_name: lmt-dev-mailpit-container
+ container_name: lmt-mailpit-local
ports:
- ${EXTERNAL_MAILPIT_DASHBOARD_PORT:-8052}:8025
- ${EXTERNAL_MAILPIT_SMTP_PORT:-8053}:1025
networks:
- - lmt-dev
- - traefik-proxy-blumilk-local
+ - lmt-local
+ - traefik-proxy-blumilk-local-environment
labels:
- "traefik.enable=true"
- - "traefik.blumilk.environment=true"
+ - "traefik.blumilk.local.environment=true"
# HTTP
- - "traefik.http.routers.lmt-mailpit-http-router.rule=Host(`lmt-mailpit.blumilk.localhost`)"
+ - "traefik.http.routers.lmt-mailpit-http-router.rule=Host(`${MAILPIT_DOCKER_HOST_NAME}`)"
- "traefik.http.routers.lmt-mailpit-http-router.entrypoints=web"
- # HTTP to HTTPS redirect
- # - "traefik.http.routers.lmt-mailpit-http-router.middlewares=https-redirect@file"
# HTTPS
- - "traefik.http.routers.lmt-mailpit-https-router.rule=Host(`lmt-mailpit.blumilk.localhost`)"
+ - "traefik.http.routers.lmt-mailpit-https-router.rule=Host(`${MAILPIT_DOCKER_HOST_NAME}`)"
- "traefik.http.routers.lmt-mailpit-https-router.entrypoints=websecure"
- "traefik.http.routers.lmt-mailpit-https-router.tls=true"
- # LOADBALANCER MAILHOG PORT
+ # LOADBALANCER MAILPIT PORT
- "traefik.http.services.lmt-mailpit.loadbalancer.server.port=8025"
restart: unless-stopped
diff --git a/environment/.deployment/Taskfile.yml b/environment/.deployment/Taskfile.yml
new file mode 100644
index 00000000..5a06a322
--- /dev/null
+++ b/environment/.deployment/Taskfile.yml
@@ -0,0 +1,38 @@
+# https://taskfile.dev
+version: "3.42.1"
+
+silent: true
+
+tasks:
+ deploy:
+ deps: [create-deployment-file, decrypt-secrets]
+ vars:
+ DOCKER_COMPOSE_FILE: docker-compose.{{ .ENVIRONMENT }}.yml
+ DOCKER_COMPOSE_APP_SERVICE: lmt-{{ .ENVIRONMENT }}-app
+ POST_DEPLOY_SCRIPT_FILE: post-deploy-actions.sh
+ cmds:
+ - cmd: docker compose --file {{ .DOCKER_COMPOSE_FILE }} pull
+ - cmd: docker compose --file {{ .DOCKER_COMPOSE_FILE }} up --detach
+ - cmd: sleep 5
+ - cmd: echo "Run app post deploy actions"
+ - cmd: docker compose --file {{ .DOCKER_COMPOSE_FILE }} exec --user www-data --workdir /application/environment/.deployment/scripts {{ .DOCKER_COMPOSE_APP_SERVICE }} bash {{ .POST_DEPLOY_SCRIPT_FILE }}
+
+ decrypt-secrets:
+ requires:
+ vars: [SOPS_AGE_KEY]
+ vars:
+ DOTENV_FILE: .env.{{ .ENVIRONMENT }}
+ SECRETS_FILE: .env.{{ .ENVIRONMENT }}.secrets
+ cmds:
+ - cmd: echo "Moving {{ .DOTENV_FILE }} to .env"
+ - cmd: mv {{ .DOTENV_FILE }} .env
+ - cmd: echo "Decrypting secrets from {{ .SECRETS_FILE }}"
+ - cmd: sops --decrypt --input-type=dotenv --output-type=dotenv {{ .SECRETS_FILE }} >> .env
+ - cmd: echo "Done"
+
+ create-deployment-file:
+ vars:
+ DATETIME:
+ sh: TZ=Europe/Warsaw date --rfc-3339=seconds
+ cmds:
+ - cmd: echo "DEPLOY_DATE='{{ .DATETIME }}'" >> .deployment
diff --git a/environment/.deployment/dev/.env.dev b/environment/.deployment/dev/.env.dev
new file mode 100644
index 00000000..aa49e578
--- /dev/null
+++ b/environment/.deployment/dev/.env.dev
@@ -0,0 +1,45 @@
+APP_NAME="LMT DEV"
+APP_ENV=dev
+APP_DEBUG=false
+APP_TIMEZONE=Europe/Warsaw
+LMT_HOST_NAME=dev.lmt.blumilk.pl
+APP_URL=https://${LMT_HOST_NAME}
+TELESCOPE_ENABLED=false
+ALLOWED_EMAIL_DOMAIN=@example.com
+
+COMPOSE_PROJECT_NAME=lmt-dev
+
+APP_LOCALE=pl
+APP_FALLBACK_LOCALE=en
+APP_FAKER_LOCALE=pl_PL
+
+BCRYPT_ROUNDS=12
+
+LOG_CHANNEL=stack
+LOG_STACK=single
+LOG_DEPRECATIONS_CHANNEL=null
+LOG_LEVEL=debug
+
+DB_CONNECTION=pgsql
+DB_HOST=lmt-dev-database
+DB_PORT=5432
+
+SESSION_DRIVER=database
+SESSION_LIFETIME=120
+SESSION_ENCRYPT=false
+SESSION_PATH=/
+SESSION_DOMAIN=null
+
+BROADCAST_CONNECTION=log
+FILESYSTEM_DISK=local
+QUEUE_CONNECTION=database
+
+CACHE_STORE=database
+CACHE_PREFIX=
+
+MAIL_MAILER=smtp
+MAIL_HOST=smtp.gmail.com
+MAIL_PORT=587
+MAIL_ENCRYPTION=tls
+MAIL_FROM_ADDRESS="no-reply@blumilk.pl"
+MAIL_FROM_NAME="${APP_NAME}"
diff --git a/environment/.deployment/dev/.env.dev.secrets b/environment/.deployment/dev/.env.dev.secrets
new file mode 100644
index 00000000..5818a98f
--- /dev/null
+++ b/environment/.deployment/dev/.env.dev.secrets
@@ -0,0 +1,13 @@
+APP_KEY=ENC[AES256_GCM,data:UtEkAzHrRNWleKdfyLcZH/Fg3GtDRHu2upqNK7wNp/AUUhG/xqyaJi/s6mCi/KWCWhwl,iv:X0mT1/mmHyWXP4mctpOtaTq3XW4DD7WAMXB1ck1er5w=,tag:cF3MVhltaGQETnOXqxjKlg==,type:str]
+MAIL_USERNAME=ENC[AES256_GCM,data:94ATmtsFdOwUTwH8rJhLDFsb3w==,iv:quEHA+EYS7OEsJ8Ksy0R1xFN/J1GpLZcNvgn5Cr5eKA=,tag:dBBX/WKqT5gN1NWtK+VqLQ==,type:str]
+MAIL_PASSWORD=ENC[AES256_GCM,data:u+eiFebZdU9+yGNRTxAA8uWS3qBK,iv:SBbZOVqaQl6vWag4OmOo8ayofA73M0tzAfJgD1Nbf5A=,tag:ozyqTqx/7psn9tC7MVCZgQ==,type:str]
+REGISTRATION_NOTIFICATION_EMAIL=ENC[AES256_GCM,data:xStQHqmFhGbwKgxtdC9b+qPcBnCOtjtK5759xuwj,iv:apIGrp6eMyWFlmSKPR+6w/eLa9+3TQOUCavFkhnpO10=,tag:Nt2l5y2RGlAdG2UxQ4vCHA==,type:str]
+DB_DATABASE=ENC[AES256_GCM,data:RfxjaQkVsg==,iv:DGFZqkw6HcxQmZYpdz+Y7zBnkmbpGKCzdKQLp1CVY70=,tag:oUkQxKD2Z79r5mNM0o3srA==,type:str]
+DB_USERNAME=ENC[AES256_GCM,data:XsOvcS1E8g==,iv:t1BpO6HE+uRFJiimRirt02owxmLU2TZoCHLcVlruIec=,tag:ynSL/pnWF2C0inqhSf1uwg==,type:str]
+DB_PASSWORD=ENC[AES256_GCM,data:ZQBCxZ81bVHEVgK3eD16jDjqrge5CanaXg==,iv:IoLgy3nh9vkxL78bzSU0NbT6TLFlVGTuwoOu6DU4Y8A=,tag:hVGmv1tVr5FXrqEWkVQBvQ==,type:str]
+sops_age__list_0__map_enc=-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSA0aS9wcnlhczU5OGZrZkpW\nVWhWbFlvazlseWRCUitOUGRBZWhzZmdWMlRzCm0zQTRqa2NDYUZNUFpleUdubkVi\nNGFuQnQ1K2U4SlFmTkVvUlBvT3l3VTQKLS0tIHRXZTlwQ2VnbDVGWGhpQlR5WW1V\nVFMrOFZqa0xPMmxjbnpLQk5ZV2t5V1UK9DlzfHVO4HW6Ni5mB+DlTedxT4A6ZhiD\nG4F+ZtXmojGkxFJTN3oIHxy+yspHRMJb0ZiUFszDSo8TU82w/CzpXA==\n-----END AGE ENCRYPTED FILE-----\n
+sops_age__list_0__map_recipient=age1m3ruqh8ldq9wy9w5rpyj2wed0nc0n4ejda2lau2009w2rlvu7qjqacfqp2
+sops_lastmodified=2025-04-24T10:46:53Z
+sops_mac=ENC[AES256_GCM,data:VzwqATi2EENXeEBm16txHAzagtrjyTihEuHC63iZTyVwvQG5hYIJ81YXpjTI+hKZSxFcXKTe/QVElGuVKJhBDuoCGKmsDLB1OyKHPwAVk/VMlBVDEcVJxQVCuON5S8wf52dF2WN3+4CHaefQQcE3UymRmeVNyVrg/myDjjNHnZU=,iv:S0/BMCXZCWtrQ/FmuRZojOHpgkSRexkV22C5d4ipA9k=,tag:5H8k/kbAZJUzdUZDL57x+w==,type:str]
+sops_unencrypted_suffix=_unencrypted
+sops_version=3.9.4
diff --git a/environment/.deployment/dev/docker-compose.dev.yml b/environment/.deployment/dev/docker-compose.dev.yml
new file mode 100644
index 00000000..f5b85848
--- /dev/null
+++ b/environment/.deployment/dev/docker-compose.dev.yml
@@ -0,0 +1,76 @@
+networks:
+ traefik-proxy:
+ external: true
+ lmt-dev:
+ driver: bridge
+
+volumes:
+ lmt-dev-postgres-data:
+ name: lmt-dev-postgres-data
+
+services:
+ lmt-dev-app:
+ image: registry.blumilk.pl/internal-public/lmt:dev
+ container_name: lmt-dev-app-container
+ pull_policy: always
+ logging:
+ driver: "json-file"
+ options:
+ max-size: "50m"
+ max-file: "5"
+ deploy:
+ mode: replicated
+ replicas: 1
+ resources:
+ limits:
+ memory: 1GB
+ labels:
+ - "traefik.enable=true"
+ - "traefik.http.routers.lmt-dev-app.rule=Host(`${LMT_HOST_NAME}`)"
+ - "traefik.http.routers.lmt-dev-app.entrypoints=websecure"
+ - "traefik.http.routers.lmt-dev-app.tls=true"
+ - "traefik.http.routers.lmt-dev-app.tls.certresolver=lets-encrypt-resolver"
+ - "traefik.http.routers.lmt-dev-app.middlewares=no-index-robots-response-header@file,security-headers@file"
+ - "io.portainer.accesscontrol.teams=LMT"
+ working_dir: /application
+ volumes:
+ - ./.env:/application/.env:ro
+ networks:
+ - lmt-dev
+ - traefik-proxy
+ restart: unless-stopped
+ env_file:
+ - .deployment
+
+ lmt-dev-database:
+ image: registry.blumilk.pl/internal-public/lmt-postgres:dev
+ pull_policy: always
+ container_name: lmt-dev-database-container
+ deploy:
+ mode: replicated
+ replicas: 1
+ resources:
+ limits:
+ memory: 512M
+ logging:
+ driver: "json-file"
+ options:
+ max-size: "50m"
+ max-file: "5"
+ labels:
+ - "io.portainer.accesscontrol.teams=LMT"
+ environment:
+ - POSTGRES_USER=${DB_USERNAME:? variable DB_USERNAME not set}
+ - POSTGRES_PASSWORD=${DB_PASSWORD:? variable DB_PASSWORD not set}
+ - POSTGRES_DB=${DB_DATABASE:? variable DB_DATABASE not set}
+ - PGDATA=/var/lib/postgresql/data
+ healthcheck:
+ test: [ "CMD-SHELL", "pg_isready --dbname ${DB_DATABASE} --username ${DB_USERNAME}" ]
+ interval: 3s
+ timeout: 3s
+ retries: 5
+ volumes:
+ - lmt-dev-postgres-data:/var/lib/postgresql/data
+ networks:
+ - lmt-dev
+ restart: unless-stopped
diff --git a/environment/.deployment/scripts/post-deploy-actions.sh b/environment/.deployment/scripts/post-deploy-actions.sh
new file mode 100644
index 00000000..7721d5cc
--- /dev/null
+++ b/environment/.deployment/scripts/post-deploy-actions.sh
@@ -0,0 +1,11 @@
+#!/bin/sh
+
+# -e is for "automatic error detection", tell shell to abort any time an error occurred
+set -e
+
+ARTISAN_PATH="/application/artisan"
+
+php ${ARTISAN_PATH} storage:link && \
+php ${ARTISAN_PATH} migrate --force && \
+php ${ARTISAN_PATH} optimize && \
+php ${ARTISAN_PATH} filament:optimize
diff --git a/environment/prod/deployment/scripts/version.sh b/environment/.deployment/scripts/version.sh
similarity index 100%
rename from environment/prod/deployment/scripts/version.sh
rename to environment/.deployment/scripts/version.sh
diff --git a/environment/.docker/app/Dockerfile b/environment/.docker/app/Dockerfile
new file mode 100644
index 00000000..9c3a79de
--- /dev/null
+++ b/environment/.docker/app/Dockerfile
@@ -0,0 +1,153 @@
+FROM registry.blumilk.pl/internal-public/secops-tools-bin:v1.0.0 AS secops-tools-bin
+FROM composer:2.8.6 AS composer
+FROM node:23.7.0-bookworm-slim AS node
+
+FROM php:8.3.10-fpm-bookworm AS base
+
+COPY --from=composer /usr/bin/composer /usr/bin/composer
+
+# For other versions check: http://nginx.org/packages/mainline/debian/pool/nginx/n/nginx/
+ARG NGINX_VERSION="1.25.4-1~bookworm"
+
+RUN apt-get update \
+ && apt-get install --assume-yes gpg \
+ && curl https://nginx.org/keys/nginx_signing.key | gpg --dearmour --output /etc/apt/trusted.gpg.d/apt.nginx.org.gpg > /dev/null \
+ && echo "deb https://nginx.org/packages/mainline/debian bookworm nginx" | tee /etc/apt/sources.list.d/nginx.list \
+ && apt-get update && apt-get install --assume-yes \
+ nginx=${NGINX_VERSION} \
+ libzip-dev \
+ libjpeg-dev \
+ libpng-dev \
+ libwebp-dev \
+ libpq-dev \
+ libicu-dev \
+ supervisor \
+ cron \
+ exif \
+ && docker-php-ext-configure \
+ gd --with-jpeg --with-webp \
+ && docker-php-ext-install \
+ zip \
+ gd \
+ intl \
+ exif \
+ pdo_pgsql
+
+COPY ./environment/.docker/app/entrypoint.sh /entrypoint.sh
+COPY ./environment/.docker/app/nginx.conf /etc/nginx/nginx.conf
+
+WORKDIR /application
+
+ENTRYPOINT ["/entrypoint.sh"]
+
+FROM base AS local
+
+COPY --from=secops-tools-bin /usr/local/bin/age /usr/local/bin/age-keygen /usr/local/bin/sops /usr/local/bin/
+
+RUN mv "${PHP_INI_DIR}/php.ini-development" "${PHP_INI_DIR}/php.ini"
+
+ARG USER_NAME=host-user
+ARG USER_ID=1000
+ARG PHP_FPM_GROUP=www-data
+
+RUN adduser \
+ --disabled-password \
+ --uid ${USER_ID} \
+ ${USER_NAME} \
+ && usermod \
+ --append \
+ --groups \
+ ${PHP_FPM_GROUP} \
+ ${USER_NAME}
+
+# Add node, npm, npx binaries
+COPY --from=node --chown=${USER_NAME}:root /usr/local/lib/node_modules /usr/local/lib/node_modules
+COPY --from=node --chown=${USER_NAME}:root /usr/local/bin/node /usr/local/bin/node
+RUN ln --symbolic /usr/local/lib/node_modules/npm/bin/npm-cli.js /usr/local/bin/npm \
+ && chown --no-dereference ${USER_NAME}:root /usr/local/bin/npm \
+ && ln --symbolic /usr/local/lib/node_modules/npm/bin/npx-cli.js /usr/local/bin/npx \
+ && chown --no-dereference ${USER_NAME}:root /usr/local/bin/npx
+
+# renovate: datasource=github-tags depName=xdebug/xdebug
+ARG XDEBUG_VERSION=3.4.2
+ARG INSTALL_XDEBUG=false
+
+RUN if [ ${INSTALL_XDEBUG} = true ]; then \
+ pecl install xdebug-${XDEBUG_VERSION} \
+ && docker-php-ext-enable xdebug \
+;fi
+
+FROM composer AS vendor-build
+
+WORKDIR /app_composer_dependencies
+
+COPY composer.json composer.lock ./
+
+RUN composer install \
+ --no-interaction \
+ --no-plugins \
+ --no-scripts \
+ --no-dev \
+ --prefer-dist \
+ --ignore-platform-reqs
+
+FROM node AS frontend-build
+
+ARG ENVIRONMENT
+
+WORKDIR /app_frontend_dependencies
+
+# last position is target directory
+COPY package.json \
+ package-lock.json \
+ vite.config.js \
+ ./
+
+COPY ./environment/${ENVIRONMENT}/app/vite.${ENVIRONMENT}.env .env
+
+RUN npm clean-install
+
+COPY resources/js ./resources/js/
+COPY resources/css ./resources/css/
+COPY resources/views ./resources/views/
+
+COPY --from=vendor-build /app_composer_dependencies/vendor/livewire ./vendor/livewire
+
+
+RUN npm run build
+
+FROM base AS production
+
+ARG ENVIRONMENT
+
+RUN docker-php-ext-install \
+ opcache
+
+RUN mv "${PHP_INI_DIR}/php.ini-production" "${PHP_INI_DIR}/php.ini"
+
+COPY ./environment/${ENVIRONMENT}/app/php.ini ${PHP_INI_DIR}/conf.d/zzz-overrides-php.ini
+COPY ./environment/${ENVIRONMENT}/app/php-fpm.conf /usr/local/etc/php-fpm.d/zzz-overrides.conf
+COPY ./environment/${ENVIRONMENT}/app/supervisord.conf /etc/supervisor/custom-supervisord.conf
+
+# Copy Frontend build
+COPY --chown=www-data:www-data --from=frontend-build /app_frontend_dependencies/public/build ./public/build/
+
+# Copy Composer dependencies
+COPY --chown=www-data:www-data --from=vendor-build /app_composer_dependencies/vendor ./vendor/
+
+# Copy App files
+COPY --chown=www-data:www-data . .
+
+# Remove unnecessary files
+RUN rm --recursive --force \
+ vite.config.js \
+ .dockerignore \
+ environment/.docker \
+ environment/dev
+
+RUN composer dump-autoload --optimize
+
+EXPOSE 80
+
+ARG PROJECT_BUILD_VERSION_ARG
+ENV PROJECT_BUILD_VERSION=${PROJECT_BUILD_VERSION_ARG}
diff --git a/environment/dev/app/entrypoint.sh b/environment/.docker/app/entrypoint.sh
similarity index 100%
rename from environment/dev/app/entrypoint.sh
rename to environment/.docker/app/entrypoint.sh
diff --git a/environment/dev/app/nginx.conf b/environment/.docker/app/nginx.conf
similarity index 100%
rename from environment/dev/app/nginx.conf
rename to environment/.docker/app/nginx.conf
diff --git a/environment/dev/postgres/Dockerfile b/environment/.docker/postgres/Dockerfile
similarity index 86%
rename from environment/dev/postgres/Dockerfile
rename to environment/.docker/postgres/Dockerfile
index 7c859e81..512ec714 100644
--- a/environment/dev/postgres/Dockerfile
+++ b/environment/.docker/postgres/Dockerfile
@@ -4,4 +4,4 @@ RUN localedef -i pl_PL -c -f UTF-8 -A /usr/share/locale/locale.alias pl_PL.UTF-8
ENV LANG=pl_PL.UTF-8
ENV LC_COLLATE=pl_PL.UTF-8
ENV LC_CTYPE=pl_PL.UTF-8
-ENV LC_MESSAGES=en_US.UTF-8
\ No newline at end of file
+ENV LC_MESSAGES=en_US.UTF-8
diff --git a/environment/dev/app/Dockerfile b/environment/dev/app/Dockerfile
deleted file mode 100644
index f0612d1e..00000000
--- a/environment/dev/app/Dockerfile
+++ /dev/null
@@ -1,86 +0,0 @@
-# https://hub.docker.com/_/alpine
-FROM alpine:3.21.2@sha256:56fa17d2a7e7f168a043a2712e63aed1f8543aeafdcee47c58dcffe38ed51099 AS secops-tools
-
-# https://github.com/FiloSottile/age/releases
-ARG AGE_VERSION="1.1.1"
-
-# https://github.com/getsops/sops/releases
-ARG SOPS_VERSION="3.8.1"
-
-RUN wget --output-document age.tar.gz "https://github.com/FiloSottile/age/releases/download/v${AGE_VERSION}/age-v${AGE_VERSION}-linux-amd64.tar.gz" \
- && tar --extract --file age.tar.gz \
- && mv age/age /usr/local/bin \
- && mv age/age-keygen /usr/local/bin \
- && wget --output-document /usr/local/bin/sops "https://github.com/getsops/sops/releases/download/v${SOPS_VERSION}/sops-v${SOPS_VERSION}.linux.amd64" \
- && chmod +x /usr/local/bin/sops
-
-FROM composer/composer:2.8.5-bin@sha256:f39305913df47b4de56c64f4719d35eedbd65d7d96ff554110b9e9bd0c7a18c0 AS composer-bin
-
-FROM node:23.7.0-bookworm AS node
-
-FROM php:8.3.10-fpm-bookworm
-
-COPY --from=composer-bin ./composer /usr/bin/composer
-COPY --from=secops-tools /usr/local/bin/age /usr/local/bin/age
-COPY --from=secops-tools /usr/local/bin/age-keygen /usr/local/bin/age-keygen
-COPY --from=secops-tools /usr/local/bin/sops /usr/local/bin/sops
-
-
-ARG USER_NAME=host-user
-ARG USER_ID=1000
-ARG PHP_FPM_GROUP=www-data
-
-RUN adduser \
- --disabled-password \
- --uid ${USER_ID} \
- ${USER_NAME} \
- && usermod \
- --append \
- --groups \
- ${PHP_FPM_GROUP} \
- ${USER_NAME}
-
-#Add node and npm
-COPY --from=node --chown=${USER_NAME}:root /usr/local/lib/node_modules /usr/local/lib/node_modules
-COPY --from=node --chown=${USER_NAME}:root /usr/local/bin/node /usr/local/bin/node
-RUN ln --symbolic /usr/local/lib/node_modules/npm/bin/npm-cli.js /usr/local/bin/npm \
- && chown --no-dereference ${USER_NAME}:root /usr/local/bin/npm \
- && ln --symbolic /usr/local/lib/node_modules/npm/bin/npx-cli.js /usr/local/bin/npx \
- && chown --no-dereference ${USER_NAME}:root /usr/local/bin/npx
-
-# Use the default development configuration
-RUN mv "${PHP_INI_DIR}/php.ini-development" "${PHP_INI_DIR}/php.ini"
-
-# For other versions check: http://nginx.org/packages/mainline/debian/pool/nginx/n/nginx/
-ARG NGINX_VERSION="1.25.4-1~bookworm"
-
-RUN apt-get update \
- && apt-get install --assume-yes gpg \
- && curl https://nginx.org/keys/nginx_signing.key | gpg --dearmour --output /etc/apt/trusted.gpg.d/apt.nginx.org.gpg > /dev/null \
- && echo "deb https://nginx.org/packages/mainline/debian bookworm nginx" | tee /etc/apt/sources.list.d/nginx.list \
- && apt-get update && apt-get install --assume-yes \
- nginx=${NGINX_VERSION} \
- libzip-dev \
- libjpeg-dev \
- libpng-dev \
- libwebp-dev \
- libpq-dev \
- libicu-dev \
- supervisor \
- cron \
- git \
- exif \
- && docker-php-ext-configure \
- gd --with-jpeg --with-webp \
- && docker-php-ext-install \
- zip \
- gd \
- intl \
- exif \
- pdo_pgsql
-
-COPY ./entrypoint.sh /entrypoint.sh
-
-WORKDIR /application
-
-ENTRYPOINT ["/entrypoint.sh"]
diff --git a/environment/dev/app/php-fpm.conf b/environment/dev/app/php-fpm.conf
index 883caeca..bc61b749 100644
--- a/environment/dev/app/php-fpm.conf
+++ b/environment/dev/app/php-fpm.conf
@@ -4,5 +4,3 @@ daemonize = no
[www]
listen = /run/php-fpm.sock
listen.owner = nginx
-
-user = host-user
diff --git a/environment/dev/app/php.ini b/environment/dev/app/php.ini
index 22352707..cb9dd788 100644
--- a/environment/dev/app/php.ini
+++ b/environment/dev/app/php.ini
@@ -1,4 +1,15 @@
[PHP]
memory_limit = 256M
+allow_url_fopen = 0
+expose_php = 0
+log_errors = 1
+display_startup_errors = 0
post_max_size = 30M
upload_max_filesize = 30M
+
+[opcache]
+opcache.enable = 1
+opcache.enable_cli = 1
+opcache.memory_consumption = 512
+opcache.max_accelerated_files = 20000
+opcache.interned_strings_buffer = 16
diff --git a/environment/dev/app/supervisord.conf b/environment/dev/app/supervisord.conf
index 2acd0725..828127a4 100644
--- a/environment/dev/app/supervisord.conf
+++ b/environment/dev/app/supervisord.conf
@@ -20,3 +20,12 @@ stdout_logfile = /dev/stdout
stdout_logfile_maxbytes = 0
stderr_logfile = /dev/stderr
stderr_logfile_maxbytes = 0
+
+[program:laravel-queue-worker]
+command = php /application/artisan queue:work --timeout=3600 --tries=3
+user = www-data
+stdout_logfile = /dev/stdout
+stdout_logfile_maxbytes = 0
+stderr_logfile = /dev/stderr
+stderr_logfile_maxbytes = 0
+
diff --git a/environment/dev/app/vite.dev.env b/environment/dev/app/vite.dev.env
new file mode 100644
index 00000000..3de240a7
--- /dev/null
+++ b/environment/dev/app/vite.dev.env
@@ -0,0 +1 @@
+VITE_APP_NAME="LMT DEV"
diff --git a/environment/devops-Taskfile.yml b/environment/devops-Taskfile.yml
new file mode 100644
index 00000000..c98201ed
--- /dev/null
+++ b/environment/devops-Taskfile.yml
@@ -0,0 +1,10 @@
+# https://taskfile.dev
+version: "3.42.1"
+
+silent: true
+
+tasks:
+ generate-age-keys:
+ desc: "Generate age keys"
+ cmds:
+ - cmd: docker run --rm registry.blumilk.pl/internal-public/secops-tools-bin:v1.0.0 age-keygen
diff --git a/environment/prod/app/php-fpm.conf b/environment/local/app/php-fpm.conf
similarity index 81%
rename from environment/prod/app/php-fpm.conf
rename to environment/local/app/php-fpm.conf
index bc61b749..883caeca 100644
--- a/environment/prod/app/php-fpm.conf
+++ b/environment/local/app/php-fpm.conf
@@ -4,3 +4,5 @@ daemonize = no
[www]
listen = /run/php-fpm.sock
listen.owner = nginx
+
+user = host-user
diff --git a/environment/local/app/php.ini b/environment/local/app/php.ini
new file mode 100644
index 00000000..22352707
--- /dev/null
+++ b/environment/local/app/php.ini
@@ -0,0 +1,4 @@
+[PHP]
+memory_limit = 256M
+post_max_size = 30M
+upload_max_filesize = 30M
diff --git a/environment/prod/app/supervisord.conf b/environment/local/app/supervisord.conf
similarity index 100%
rename from environment/prod/app/supervisord.conf
rename to environment/local/app/supervisord.conf
diff --git a/environment/prod/app/Dockerfile b/environment/prod/app/Dockerfile
deleted file mode 100644
index be1f3f02..00000000
--- a/environment/prod/app/Dockerfile
+++ /dev/null
@@ -1,74 +0,0 @@
-### PHP DEPENDENCIES ###
-FROM composer:2.8.5@sha256:e0c9ac329256c25b0dee572df37d986570fb26bb6baaa7d0abe69b84181701e1 AS vendor
-
-WORKDIR /app_composer_dependencies
-
-COPY composer.json composer.lock ./
-
-RUN composer install \
- --no-interaction \
- --no-plugins \
- --no-scripts \
- --prefer-dist \
- --ignore-platform-reqs
-
-### FRONTEND ###
-FROM node:21.7.3-bookworm-slim@sha256:dfc05dee209a1d7adf2ef189bd97396daad4e97c6eaa85778d6f75205ba1b0fb AS frontend
-
-WORKDIR /app_frontend_dependencies
-
-COPY package.json package-lock.json styles.css tailwind.config.js ./
-
-RUN npm clean-install
-
-COPY ./public/meetup.html ./public/meetup.html
-COPY ./public/index.html ./public/index.html
-
-RUN npx tailwindcss -i ./styles.css -o ./public/output.css
-
-### APPLICATION ###
-FROM php:8.4.3-fpm-bookworm@sha256:5148d67c6a67e00736c7a1be2e3b5287e370fd64d24f7777f5e39bf4c45b9175 AS app
-
-COPY --from=vendor /usr/bin/composer /usr/local/bin/composer
-
-# For other versions check: http://nginx.org/packages/mainline/debian/pool/nginx/n/nginx/
-ARG NGINX_VERSION="1.25.4-1~bookworm"
-
-RUN apt-get update \
- && apt-get install --assume-yes gpg \
- && curl https://nginx.org/keys/nginx_signing.key | gpg --dearmour --output /etc/apt/trusted.gpg.d/apt.nginx.org.gpg > /dev/null \
- && echo "deb https://nginx.org/packages/mainline/debian bookworm nginx" | tee /etc/apt/sources.list.d/nginx.list \
- && apt-get update && apt-get install --assume-yes \
- nginx=${NGINX_VERSION} \
- 7zip \
- libzip-dev \
- supervisor \
- cron
-
-RUN mv "${PHP_INI_DIR}/php.ini-production" "${PHP_INI_DIR}/php.ini"
-
-COPY ./environment/prod/app/php.ini "${PHP_INI_DIR}/conf.d/zzz-overrides-php.ini"
-COPY ./environment/prod/app/php-fpm.conf "/usr/local/etc/php-fpm.d/zzz-overrides.conf"
-COPY ./environment/prod/app/nginx.conf "/etc/nginx/nginx.conf"
-COPY ./environment/prod/app/supervisord.conf "/etc/supervisor/custom-supervisord.conf"
-COPY ./environment/prod/app/entrypoint.sh /entrypoint.sh
-
-WORKDIR /application
-
-# Copy Frontend build
-COPY --chown=www-data:www-data --from=frontend /app_frontend_dependencies/public/output.css ./public/output.css
-
-# Copy Composer dependencies
-COPY --chown=www-data:www-data --from=vendor /app_composer_dependencies/vendor ./vendor/
-
-# Copy App files
-COPY --chown=www-data:www-data . .
-
-RUN composer dump-autoload --optimize
-
-EXPOSE 80
-
-ENTRYPOINT ["/entrypoint.sh"]
-
-ARG DEPLOYMENT_PROJECT_VERSION_ARG
-ENV DEPLOYMENT_VERSION=${DEPLOYMENT_PROJECT_VERSION_ARG}
diff --git a/environment/prod/app/entrypoint.sh b/environment/prod/app/entrypoint.sh
deleted file mode 100755
index b951e259..00000000
--- a/environment/prod/app/entrypoint.sh
+++ /dev/null
@@ -1,12 +0,0 @@
-#!/bin/bash
-
-# -e is for "automatic error detection", tell shell to abort any time an error occurred
-set -e
-
-# bash is not responding to the sigterm and container always have 10 second timeout (when stop/restart)
-# exec is related with
-# https://docs.docker.com/compose/faq/#why-do-my-services-take-10-seconds-to-recreate-or-stop
-# https://github.com/moby/moby/issues/3766
-# https://unix.stackexchange.com/a/196053
-
-exec supervisord --configuration /etc/supervisor/custom-supervisord.conf
diff --git a/environment/prod/app/nginx.conf b/environment/prod/app/nginx.conf
deleted file mode 100644
index 0bd53da7..00000000
--- a/environment/prod/app/nginx.conf
+++ /dev/null
@@ -1,56 +0,0 @@
-daemon off;
-
-user nginx;
-worker_processes auto;
-
-error_log /var/log/nginx/error.log notice;
-pid /var/run/nginx.pid;
-
-events {
- worker_connections 1024;
-}
-
-http {
- include /etc/nginx/mime.types;
- default_type application/octet-stream;
-
- log_format main '$remote_addr - $remote_user [$time_local] "$request" '
- '$status $body_bytes_sent "$http_referer" '
- '"$http_user_agent" "$http_x_forwarded_for"';
-
- access_log /var/log/nginx/access.log main;
- sendfile on;
- keepalive_timeout 65;
-
- server {
- listen 80 default;
- server_name lmt-nginx;
-
- access_log /dev/stdout;
- error_log /dev/stderr;
-
- root /application/public;
- index index.html;
-
- location = /meetup.html {
- if ($arg_meetupId) {
- return 301 /meetup?$query_string;
- }
- return 404; # Return 404 if no meetupId is present
- }
-
- location = /meetup {
- try_files /meetup.html =404;
- }
-
- location / {
- try_files $uri $uri/ =404;
- }
-
- location ~ \.php$ {
- fastcgi_pass unix:/run/php-fpm.sock;
- fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
- include fastcgi_params;
- }
- }
-}
diff --git a/environment/prod/app/php.ini b/environment/prod/app/php.ini
deleted file mode 100644
index 39f373e4..00000000
--- a/environment/prod/app/php.ini
+++ /dev/null
@@ -1,2 +0,0 @@
-[PHP]
-memory_limit = 256M
diff --git a/environment/prod/deployment/prod/.env.prod b/environment/prod/deployment/prod/.env.prod
deleted file mode 100644
index cc054069..00000000
--- a/environment/prod/deployment/prod/.env.prod
+++ /dev/null
@@ -1,4 +0,0 @@
-APP_NAME="Legnicki Meetup Technologiczny"
-ENVIRONMENT=prod
-
-LMT_HOST_NAME=meetup.legnica.pl
diff --git a/environment/prod/deployment/prod/.env.prod.secrets b/environment/prod/deployment/prod/.env.prod.secrets
deleted file mode 100644
index cfa41420..00000000
--- a/environment/prod/deployment/prod/.env.prod.secrets
+++ /dev/null
@@ -1,12 +0,0 @@
-SMTP_HOST=ENC[AES256_GCM,data:wAn4XtrjkT1l1s9XD9Y=,iv:+I2yPi4swha2ywJYwZomVaHwuLZ/HfUvcEauen+ulIo=,tag:08RDU/6kznLb81l4r/PGXw==,type:str]
-SMTP_PORT=ENC[AES256_GCM,data:EYA9,iv:HeIQr+603f3StbGsLLeQpDINYtup1d5kQwJsauyo0oc=,tag:QqhqAn6Z8BjeYuVhz2d8cA==,type:str]
-SMTP_USERNAME=ENC[AES256_GCM,data:brnySEovpIJk3mXLQF2Gaq6zfA==,iv:g8DDoXRhRiBP72sYxGhkCM8jqvyWRJy5OMCcsJPnVeE=,tag:gZ4y7QX2q1+1PxWB2lA4oA==,type:str]
-SMTP_PASSWORD=ENC[AES256_GCM,data:1nuW3QwTlqmh2KMSRQhKVsnt0YdC,iv:+wKvBPbRlvbiPNJ8Wh8RdVqf/LsDF5lWOt2ReBTMum0=,tag:wDxrCXESHMD1l00VM662RA==,type:str]
-EMAIL_FROM=ENC[AES256_GCM,data:ucpZ2+jJwQvsWcOWzuMNow==,iv:uyjzGenqn+LGeGFQvxRtDIg1ouKPpjZrVA9zeV7m9+4=,tag:4BimPA43rilYdsCL7F5gzA==,type:str]
-REGISTRATION_NOTIFICATION_EMAIL=ENC[AES256_GCM,data:ArpgRjpKH8iWpGXeavOywcqRjcfc+nvXCc0=,iv:mqKGUB8PhCcRBCFR8j9FiahytFUoEzriFrSgMCMUowI=,tag:7+c3/Xj7E+BewgBPDdlhUw==,type:str]
-sops_age__list_0__map_enc=-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSAzQ1lRZ0ZLNzRFbHE3RVQ5\nSlZKcjBUaC9nVmNGb3lTWTR3QnRjbW5WdlhNCllaV1JDYUVUSFBtTExyVGwrL0dW\na0kxLzltS3BDOW5jd0FhTDBqK2pxMGsKLS0tIDBUZlBGc3orYlJJTTNod0dKdVRy\neC9aS3JwWXl0RzBMUk5oanRWS05rKzgKJWcyHWZY/mneQHr4Hq5LjRsiCAO04vD4\ngq0XATNraPCH/zWpX4vyLha4JXIu6zTsOaK9uScwimwRaMtIoa/NuA==\n-----END AGE ENCRYPTED FILE-----\n
-sops_age__list_0__map_recipient=age1ys9k3fkd2cxzkpllfe75gagjrfks45r6x9rhllr4lqvfxx520qaqxtj697
-sops_lastmodified=2024-03-15T07:35:20Z
-sops_mac=ENC[AES256_GCM,data:s5Gfy839w9ZB43q9o0nOngHTXUeurA5gUQG5w7orhopDu765B3OnE1KCHem9RdJkEq/mjG3y0yZvYU/x6e7ZcDQT06t7JSs0nwWc//gYuZgGpjh8Efw2f6MCoWbGJA/0qqLYKkA6sqFcM18biokfTykXi4MiWglWqAMmC1hxz8U=,iv:85HoW/cmxFxJYMbbYsX17iahBr5JivyGSrDO9FNsEfU=,tag:ggGPzsjl3IpeTvZO4wBpkg==,type:str]
-sops_unencrypted_suffix=_unencrypted
-sops_version=3.8.1
diff --git a/environment/prod/deployment/prod/Makefile b/environment/prod/deployment/prod/Makefile
deleted file mode 100644
index 29387363..00000000
--- a/environment/prod/deployment/prod/Makefile
+++ /dev/null
@@ -1,32 +0,0 @@
-export COMPOSE_DOCKER_CLI_BUILD = 1
-export DOCKER_BUILDKIT = 1
-
-MAKEFLAGS += --no-print-directory
-
-DOCKER_COMPOSE_FILENAME = docker-compose.prod.yml
-DOCKER_COMPOSE_APP_SERVICE = lmt-prod-app-container
-
-CURRENT_DIR = $(shell pwd)
-
-prod-deploy: decrypt-secrets create-deployment-file
- @docker compose --file ${DOCKER_COMPOSE_FILENAME} pull && \
- docker compose --file ${DOCKER_COMPOSE_FILENAME} up --detach
-
-SOPS_VERSION=3.8.1
-
-decrypt-secrets:
- @wget --output-document ./sops "https://github.com/getsops/sops/releases/download/v${SOPS_VERSION}/sops-v${SOPS_VERSION}.linux.amd64" \
- && chmod +x ./sops \
- && mv .env.prod .env \
- && echo "Decrypting secrets" \
- && ./sops --decrypt --input-type=dotenv --output-type=dotenv .env.prod.secrets >> .env \
- && echo "Done"
-
-DEPLOYMENT_DATETIME = $(shell TZ=Europe/Warsaw date --rfc-3339=seconds)
-
-create-deployment-file:
- @echo "\
- DEPLOY_DATE='${DEPLOYMENT_DATETIME}'\
- " > .deployment
-
-.PHONY: prod-deploy decrypt-secrets create-deployment-file
diff --git a/environment/prod/deployment/prod/docker-compose.prod.yml b/environment/prod/deployment/prod/docker-compose.prod.yml
deleted file mode 100644
index 141cb548..00000000
--- a/environment/prod/deployment/prod/docker-compose.prod.yml
+++ /dev/null
@@ -1,38 +0,0 @@
-networks:
- traefik-proxy:
- external: true
- lmt-prod:
- driver: bridge
-
-services:
- lmt-prod-app:
- image: ghcr.io/blumilksoftware/lmt:latest
- container_name: lmt-prod-app-container
- pull_policy: always
- logging:
- driver: "json-file"
- options:
- max-size: "50m"
- max-file: "5"
- deploy:
- mode: replicated
- replicas: 1
- resources:
- limits:
- memory: 1GB
- labels:
- - "traefik.enable=true"
- - "traefik.http.routers.lmt-prod-app.rule=Host(`${LMT_HOST_NAME}`)"
- - "traefik.http.routers.lmt-prod-app.entrypoints=websecure"
- - "traefik.http.routers.lmt-prod-app.tls=true"
- - "traefik.http.routers.lmt-prod-app.tls.certresolver=lets-encrypt-resolver"
- - "traefik.http.routers.lmt-prod-app.middlewares=response-gzip-compress@file"
- working_dir: /application
- volumes:
- - ./.env:/application/.env:ro
- networks:
- - lmt-prod
- - traefik-proxy
- restart: unless-stopped
- env_file:
- - .deployment
diff --git a/environment/secops-Taskfile.yml b/environment/secops-Taskfile.yml
new file mode 100644
index 00000000..2dadf17e
--- /dev/null
+++ b/environment/secops-Taskfile.yml
@@ -0,0 +1,38 @@
+# https://taskfile.dev
+version: "3.42.1"
+
+silent: true
+
+tasks:
+ encrypt-dev-secrets:
+ desc: "Encrypt app dev secrets"
+ cmds:
+ - task: _encrypt-secrets
+ vars:
+ ENVIRONMENT: dev
+
+ decrypt-dev-secrets:
+ desc: "Decrypt app dev secrets"
+ cmds:
+ - task: _decrypt-secrets
+ vars:
+ ENVIRONMENT: dev
+ AGE_SECRET_KEY: ${SOPS_AGE_DEV_SECRET_KEY}
+
+ _encrypt-secrets:
+ internal: true
+ cmds:
+ - cmd: echo "Encrypting {{ .ENVIRONMENT }} secrets"
+ - cmd: |
+ docker compose exec --user $CURRENT_USER_ID --workdir /application/environment/.deployment/{{ .ENVIRONMENT }} $DOCKER_COMPOSE_APP_CONTAINER \
+ sops --encrypt --input-type=dotenv --output-type=dotenv --output .env.{{ .ENVIRONMENT }}.secrets .env.{{ .ENVIRONMENT }}.secrets.decrypted
+ - cmd: echo "Done"
+
+ _decrypt-secrets:
+ internal: true
+ cmds:
+ - cmd: echo "Decrypting {{ .ENVIRONMENT }} secrets"
+ - cmd: |
+ docker compose exec --user $CURRENT_USER_ID --env SOPS_AGE_KEY={{ .AGE_SECRET_KEY }} --workdir /application/environment/.deployment/{{ .ENVIRONMENT }} $DOCKER_COMPOSE_APP_CONTAINER \
+ sops --decrypt --input-type=dotenv --output-type=dotenv --output .env.{{ .ENVIRONMENT }}.secrets.decrypted .env.{{ .ENVIRONMENT }}.secrets
+ - cmd: echo 'Done'
diff --git a/public/assets/meetups/2025-02-20-lmt-03/images/gallery/_DSC3958.webp b/public/assets/meetups/2025-02-20-lmt-03/images/gallery/_DSC3958.webp
deleted file mode 100644
index fa51dc23..00000000
Binary files a/public/assets/meetups/2025-02-20-lmt-03/images/gallery/_DSC3958.webp and /dev/null differ
diff --git a/public/assets/meetups/2025-02-20-lmt-03/images/gallery/_DSC4010-Enhanced-NR.webp b/public/assets/meetups/2025-02-20-lmt-03/images/gallery/_DSC4010-Enhanced-NR.webp
deleted file mode 100644
index d4506aa7..00000000
Binary files a/public/assets/meetups/2025-02-20-lmt-03/images/gallery/_DSC4010-Enhanced-NR.webp and /dev/null differ
diff --git a/public/assets/meetups/2025-02-20-lmt-03/images/gallery/_DSC4054.webp b/public/assets/meetups/2025-02-20-lmt-03/images/gallery/_DSC4054.webp
deleted file mode 100644
index 9640ad2f..00000000
Binary files a/public/assets/meetups/2025-02-20-lmt-03/images/gallery/_DSC4054.webp and /dev/null differ
diff --git a/public/assets/meetups/2025-02-20-lmt-03/images/gallery/_DSC4066.webp b/public/assets/meetups/2025-02-20-lmt-03/images/gallery/_DSC4066.webp
deleted file mode 100644
index 89cec60f..00000000
Binary files a/public/assets/meetups/2025-02-20-lmt-03/images/gallery/_DSC4066.webp and /dev/null differ
diff --git a/public/assets/meetups/2025-02-20-lmt-03/images/gallery/_DSC4074.webp b/public/assets/meetups/2025-02-20-lmt-03/images/gallery/_DSC4074.webp
deleted file mode 100644
index 12f51fcb..00000000
Binary files a/public/assets/meetups/2025-02-20-lmt-03/images/gallery/_DSC4074.webp and /dev/null differ
diff --git a/public/assets/meetups/2025-02-20-lmt-03/images/gallery/_DSC4076-Enhanced-NR.webp b/public/assets/meetups/2025-02-20-lmt-03/images/gallery/_DSC4076-Enhanced-NR.webp
deleted file mode 100644
index 17f59243..00000000
Binary files a/public/assets/meetups/2025-02-20-lmt-03/images/gallery/_DSC4076-Enhanced-NR.webp and /dev/null differ
diff --git a/public/assets/meetups/2025-02-20-lmt-03/images/gallery/_DSC4187.webp b/public/assets/meetups/2025-02-20-lmt-03/images/gallery/_DSC4187.webp
deleted file mode 100644
index 26c2e711..00000000
Binary files a/public/assets/meetups/2025-02-20-lmt-03/images/gallery/_DSC4187.webp and /dev/null differ
diff --git a/public/assets/meetups/2025-02-20-lmt-03/images/gallery/_DSC4448-Enhanced-NR-2.webp b/public/assets/meetups/2025-02-20-lmt-03/images/gallery/_DSC4448-Enhanced-NR-2.webp
deleted file mode 100644
index b721cf86..00000000
Binary files a/public/assets/meetups/2025-02-20-lmt-03/images/gallery/_DSC4448-Enhanced-NR-2.webp and /dev/null differ
diff --git a/public/assets/meetups/2025-02-20-lmt-03/images/gallery/_DSC4490.webp b/public/assets/meetups/2025-02-20-lmt-03/images/gallery/_DSC4490.webp
deleted file mode 100644
index fbdbe78f..00000000
Binary files a/public/assets/meetups/2025-02-20-lmt-03/images/gallery/_DSC4490.webp and /dev/null differ
diff --git a/public/assets/meetups/2025-02-20-lmt-03/images/gallery/_DSC4494-Enhanced-NR.webp b/public/assets/meetups/2025-02-20-lmt-03/images/gallery/_DSC4494-Enhanced-NR.webp
deleted file mode 100644
index 7093dc07..00000000
Binary files a/public/assets/meetups/2025-02-20-lmt-03/images/gallery/_DSC4494-Enhanced-NR.webp and /dev/null differ
diff --git a/public/assets/meetups/2025-02-20-lmt-03/images/gallery/_DSC4508.webp b/public/assets/meetups/2025-02-20-lmt-03/images/gallery/_DSC4508.webp
deleted file mode 100644
index cf60aebd..00000000
Binary files a/public/assets/meetups/2025-02-20-lmt-03/images/gallery/_DSC4508.webp and /dev/null differ
diff --git a/public/assets/meetups/2025-02-20-lmt-03/images/gallery/_DSC4643.webp b/public/assets/meetups/2025-02-20-lmt-03/images/gallery/_DSC4643.webp
deleted file mode 100644
index dc60c196..00000000
Binary files a/public/assets/meetups/2025-02-20-lmt-03/images/gallery/_DSC4643.webp and /dev/null differ
diff --git a/public/assets/meetups/2025-02-20-lmt-03/presentations/kamil-piech.pdf b/public/assets/meetups/2025-02-20-lmt-03/presentations/kamil-piech.pdf
deleted file mode 100644
index 49ec9428..00000000
Binary files a/public/assets/meetups/2025-02-20-lmt-03/presentations/kamil-piech.pdf and /dev/null differ
diff --git a/public/assets/meetups/2025-02-20-lmt-03/presentations/lukasz-tkacz.pdf b/public/assets/meetups/2025-02-20-lmt-03/presentations/lukasz-tkacz.pdf
deleted file mode 100644
index 6038f5e8..00000000
Binary files a/public/assets/meetups/2025-02-20-lmt-03/presentations/lukasz-tkacz.pdf and /dev/null differ
diff --git a/public/assets/meetups/2025-02-20-lmt-03/presentations/szymon-sandura.pdf b/public/assets/meetups/2025-02-20-lmt-03/presentations/szymon-sandura.pdf
deleted file mode 100644
index 3901861d..00000000
Binary files a/public/assets/meetups/2025-02-20-lmt-03/presentations/szymon-sandura.pdf and /dev/null differ
diff --git a/readme.md b/readme.md
index b1a5749e..0f833a3d 100644
--- a/readme.md
+++ b/readme.md
@@ -4,61 +4,109 @@

-### Docker environment:
+---
+## Taskfile setup
+### Linux
-Copy `.env.example` to `.env` and set your environment variables:
+If you don't have Task binary installed, you can install it by running command below. \
+If you don't want to install to `/usr/local/bin` (dir for all users in the system) change `-b` flag value. \
+Be sure that provided path is in system $PATH, that binary will be available in the terminal.
+To check system paths type `$PATH` in the terminal.
+```shell
+sudo sh -c "$(curl --location https://taskfile.dev/install.sh)" -- -d -b /usr/local/bin v3.42.1
```
-cp .env.example .env
-```
-
-Build app containers:
+_-b sets bindir or installation directory, Defaults to ./bin_ \
+_-d turns on debug logging_
-```
-make build
-```
+Other installation methods: https://taskfile.dev/installation \
+GitHub: https://github.com/go-task/task \
+Taskfile releases: https://github.com/go-task/task/releases
-Run containers:
+# Task commands
+---
+To list all task commands just run:
+```shell
+task
```
-make run
-```
-
-Enter the app container with `make shell`, then install php and node dependencies:
+### Task commands completions:
+---
+Add this line to `.bashrc` if you are using bash:
```
-composer install
-npm install
+eval "$(task --completion bash)"
```
+For other shells see: \
+https://taskfile.dev/installation/#option-1-load-the-completions-in-your-shells-startup-config-recommended
-Run `php artisan storage:link`:
+# Project initialization
+Before first use, project has to be initialized.
+
+First, prepare `.env` file
+```shell
+cp .env.example .env
```
-php artisan storage:link
+
+To initialize project run:
+```shell
+task init
```
+This command will check if `.env` file exists.
+Build and run containers. \
+Then it will:
+- install composer dependencies
+- generate `APP_KEY` if not set
+- run migrations with seed
+- link Laravel storage
+- install npm dependencies
+- create test database if not exist
-Run `make dev` to build stylesheets:
+### Develop project
+To develop project run:
+```shell
+task dev
```
-make dev
-```
+This command will run Vite development server. \
+App will be available at:
+- https://lmt.blumilk.local.env- if you ran Traefik in Blumilk environment. Don't forget to update hosts file.
+- http://\:5173 - link will be displayed in console
+
+### Running tests
-Run `make lint` to check for lint issues:
+You can run PHPUnit test cases
```
-make lint
+task test
```
-Run `make lintf` to fix lint issues:
+### Code style check
+
+You can run PHP-CS-Fixer:
```
-make lintf
+task fix
```
-The website should be available at [localhost:8051](localhost:8051) and [lmt.blumilk.localhost](lmt.blumilk.localhost)
+The website should be available at [localhost:8051](localhost:8051) and [lmt.blumilk.local.env](lmt.blumilk.local.env)
if we use a Blumilk local traefik proxy.
-| service | container name | default external port |
-|---------|---------------------------|-----------------------|
-| app | lmt-dev-app-container | 8051 |
-| mailpit | lmt-dev-mailpit-container | 8052 |
+| service | container name | default external port |
+|---------------------|-------------------------------------------------------------|--------------------------------|
+| app | [lmt-app-local](https://lmt.blumilk.local.env) | [8051](http://localhost:8051/) |
+| mailpit (dashboard) | [lmt-mailpit-local ](https://lmt-mailpit.blumilk.local.env) | [8052](http://localhost:8052/) |
+| database | lmt-db-local | 8055 |
+
+
+### Working with encrypted data
+
+To encrypt/decrypt environment secrets or json files, you can use task commands: \
+E.g.: `task secops:decrypt-dev-secrets`
+
+* secops:decrypt-dev-secrets: Decrypt app dev secrets
+* secops:encrypt-dev-secrets: Encrypt app dev secrets
+
+Remember that decryption requires private key (e.g. `SOPS_AGE_DEV_SECRET_KEY` for dev environment) which should be set in `.env` file.
+Encryption uses public key which is added in `.sops.yaml` file.
\ No newline at end of file
diff --git a/renovate.json5 b/renovate.json5
index 6a282245..1cca49a3 100644
--- a/renovate.json5
+++ b/renovate.json5
@@ -6,5 +6,7 @@
additionalReviewers: [
'Blusia', // Agnieszka Rudek
],
- ignoreDeps: ['ghcr.io/blumilksoftware/lmt'],
+ ignoreDeps: [
+ 'registry.blumilk.pl/internal-public/lmt',
+ ],
}
diff --git a/resources/views/components/partials/speakers.blade.php b/resources/views/components/partials/speakers.blade.php
index 5d200d71..aa81237c 100644
--- a/resources/views/components/partials/speakers.blade.php
+++ b/resources/views/components/partials/speakers.blade.php
@@ -48,7 +48,7 @@ class="h-full overflow-hidden"
@if ($speaker->slides)
+ href="{{ $speaker->slides->getUrl() }}">
{{ $speaker->presentation }}
@@ -90,20 +90,43 @@ class="flex h-[68px] w-[68px] cursor-pointer items-center justify-center rounded
alt="{{ $speaker->full_name }}"
>
-
-
{{ $speaker->first_name }}
-
{{ $speaker->last_name }}
-
-
- @foreach($speaker->companies as $company)
-
{{ $company['name'] }}
- @endforeach
-
-
-
- {{ $speaker->description }}
-
+
+
+
{{ $speaker->first_name }}
+
{{ $speaker->last_name }}
+
+
+ @foreach($speaker->companies as $company)
+
{{ $company['name'] }}
+ @endforeach
+
+
+
+ {{ $speaker->description }}
+
+
+
+
@endforeach
diff --git a/vite.config.js b/vite.config.js
index 4c34114d..f756b02c 100644
--- a/vite.config.js
+++ b/vite.config.js
@@ -1,7 +1,6 @@
import { defineConfig, loadEnv } from 'vite'
import laravel from 'laravel-vite-plugin'
import tailwindcss from '@tailwindcss/vite'
-import { networkInterfaces } from 'os'
export default ({ mode }) => {
process.env = { ...process.env, ...loadEnv(mode, process.cwd()) }
@@ -11,8 +10,11 @@ export default ({ mode }) => {
outDir: './public/build/',
},
server: {
- host: Object.values(networkInterfaces()).flat().find(i => i.family === 'IPv4' && !i.internal).address,
- port: process.env.VITE_PORT,
+ host: true,
+ port: 5173,
+ strictPort: true,
+ origin: 'https://' + process.env.VITE_DEV_SERVER_DOCKER_HOST_NAME,
+ cors: true, // Allow any origin
},
resolve: {
alias: {