From c158b826f0443eaa5a139b959b46806195f6ddf1 Mon Sep 17 00:00:00 2001
From: okxlin <61420215+okxlin@users.noreply.github.com>
Date: Tue, 28 Jul 2026 19:16:33 +0800
Subject: [PATCH] feat: add Flagsmith app
---
apps/flagsmith/2.257.0/.env.sample | 13 ++
apps/flagsmith/2.257.0/data.yml | 208 ++++++++++++++++++++
apps/flagsmith/2.257.0/data/.gitkeep | 1 +
apps/flagsmith/2.257.0/docker-compose.yml | 104 ++++++++++
apps/flagsmith/2.257.0/scripts/init.sh | 67 +++++++
apps/flagsmith/2.257.0/scripts/uninstall.sh | 8 +
apps/flagsmith/2.257.0/scripts/upgrade.sh | 5 +
apps/flagsmith/README.md | 52 +++++
apps/flagsmith/data.yml | 33 ++++
apps/flagsmith/latest/.env.sample | 13 ++
apps/flagsmith/latest/data.yml | 208 ++++++++++++++++++++
apps/flagsmith/latest/data/.gitkeep | 1 +
apps/flagsmith/latest/docker-compose.yml | 104 ++++++++++
apps/flagsmith/latest/scripts/init.sh | 67 +++++++
apps/flagsmith/latest/scripts/uninstall.sh | 8 +
apps/flagsmith/latest/scripts/upgrade.sh | 5 +
apps/flagsmith/logo.png | Bin 0 -> 6805 bytes
17 files changed, 897 insertions(+)
create mode 100644 apps/flagsmith/2.257.0/.env.sample
create mode 100644 apps/flagsmith/2.257.0/data.yml
create mode 100644 apps/flagsmith/2.257.0/data/.gitkeep
create mode 100644 apps/flagsmith/2.257.0/docker-compose.yml
create mode 100755 apps/flagsmith/2.257.0/scripts/init.sh
create mode 100755 apps/flagsmith/2.257.0/scripts/uninstall.sh
create mode 100755 apps/flagsmith/2.257.0/scripts/upgrade.sh
create mode 100644 apps/flagsmith/README.md
create mode 100644 apps/flagsmith/data.yml
create mode 100644 apps/flagsmith/latest/.env.sample
create mode 100644 apps/flagsmith/latest/data.yml
create mode 100644 apps/flagsmith/latest/data/.gitkeep
create mode 100644 apps/flagsmith/latest/docker-compose.yml
create mode 100755 apps/flagsmith/latest/scripts/init.sh
create mode 100755 apps/flagsmith/latest/scripts/uninstall.sh
create mode 100755 apps/flagsmith/latest/scripts/upgrade.sh
create mode 100644 apps/flagsmith/logo.png
diff --git a/apps/flagsmith/2.257.0/.env.sample b/apps/flagsmith/2.257.0/.env.sample
new file mode 100644
index 000000000..451b1f4d9
--- /dev/null
+++ b/apps/flagsmith/2.257.0/.env.sample
@@ -0,0 +1,13 @@
+CONTAINER_NAME="flagsmith"
+PANEL_APP_BIND_ADDRESS="127.0.0.1"
+PANEL_APP_PORT_HTTP="8000"
+PANEL_DB_TYPE="postgresql"
+PANEL_DB_HOST="postgresql"
+PANEL_DB_PORT="5432"
+PANEL_DB_NAME="flagsmith"
+PANEL_DB_USER="flagsmith"
+PANEL_DB_USER_PASSWORD="change-me"
+DJANGO_SECRET_KEY="generate"
+FLAGSMITH_DOMAIN="localhost:8000"
+FLAGSMITH_ALLOWED_HOSTS="*"
+PREVENT_SIGNUP="false"
diff --git a/apps/flagsmith/2.257.0/data.yml b/apps/flagsmith/2.257.0/data.yml
new file mode 100644
index 000000000..ab06122ed
--- /dev/null
+++ b/apps/flagsmith/2.257.0/data.yml
@@ -0,0 +1,208 @@
+additionalProperties:
+ formFields:
+ - default: 127.0.0.1
+ edit: true
+ envKey: PANEL_APP_BIND_ADDRESS
+ labelEn: Bind Address
+ labelZh: 绑定地址
+ label:
+ en: Bind Address
+ zh: 绑定地址
+ zh-Hant: 綁定位址
+ ja: バインドアドレス
+ ko: 바인드 주소
+ ru: Адрес привязки
+ ms: Alamat ikatan
+ pt-br: Endereco de vinculacao
+ required: true
+ type: text
+ - default: 8000
+ edit: true
+ envKey: PANEL_APP_PORT_HTTP
+ labelEn: HTTP Port
+ labelZh: HTTP 端口
+ label:
+ en: HTTP Port
+ zh: HTTP 端口
+ zh-Hant: HTTP 連接埠
+ ja: HTTP ポート
+ ko: HTTP 포트
+ ru: HTTP-порт
+ ms: Port HTTP
+ pt-br: Porta HTTP
+ required: true
+ rule: paramPort
+ type: number
+ - default: postgresql
+ envKey: PANEL_DB_TYPE
+ labelEn: Database Runtime
+ labelZh: 数据库运行环境
+ label:
+ en: Database Runtime
+ zh: 数据库运行环境
+ zh-Hant: 資料庫執行環境
+ ja: データベース実行環境
+ ko: 데이터베이스 런타임
+ ru: Среда базы данных
+ ms: Masa jalan pangkalan data
+ pt-br: Ambiente de banco de dados
+ required: true
+ type: apps
+ values:
+ - label: PostgreSQL
+ value: postgresql
+ child:
+ default: ""
+ envKey: PANEL_DB_HOST
+ labelEn: PostgreSQL Service
+ labelZh: PostgreSQL 服务
+ label:
+ en: PostgreSQL Service
+ zh: PostgreSQL 服务
+ zh-Hant: PostgreSQL 服務
+ ja: PostgreSQL サービス
+ ko: PostgreSQL 서비스
+ ru: Сервис PostgreSQL
+ ms: Perkhidmatan PostgreSQL
+ pt-br: Servico PostgreSQL
+ required: true
+ type: service
+ - default: 5432
+ edit: true
+ envKey: PANEL_DB_PORT
+ labelEn: Database Port
+ labelZh: 数据库端口
+ label:
+ en: Database Port
+ zh: 数据库端口
+ zh-Hant: 資料庫連接埠
+ ja: データベースポート
+ ko: 데이터베이스 포트
+ ru: Порт базы данных
+ ms: Port pangkalan data
+ pt-br: Porta do banco de dados
+ required: true
+ rule: paramPort
+ type: number
+ - default: flagsmith
+ edit: true
+ envKey: PANEL_DB_NAME
+ labelEn: Database Name
+ labelZh: 数据库名称
+ label:
+ en: Database Name
+ zh: 数据库名称
+ zh-Hant: 資料庫名稱
+ ja: データベース名
+ ko: 데이터베이스 이름
+ ru: Имя базы данных
+ ms: Nama pangkalan data
+ pt-br: Nome do banco de dados
+ random: true
+ required: true
+ rule: paramCommon
+ type: text
+ - default: flagsmith
+ edit: true
+ envKey: PANEL_DB_USER
+ labelEn: Database User
+ labelZh: 数据库用户
+ label:
+ en: Database User
+ zh: 数据库用户
+ zh-Hant: 資料庫使用者
+ ja: データベースユーザー
+ ko: 데이터베이스 사용자
+ ru: Пользователь базы данных
+ ms: Pengguna pangkalan data
+ pt-br: Usuario do banco de dados
+ random: true
+ required: true
+ rule: paramCommon
+ type: text
+ - default: ""
+ edit: true
+ envKey: PANEL_DB_USER_PASSWORD
+ labelEn: Database Password
+ labelZh: 数据库密码
+ label:
+ en: Database Password
+ zh: 数据库密码
+ zh-Hant: 資料庫密碼
+ ja: データベースパスワード
+ ko: 데이터베이스 비밀번호
+ ru: Пароль базы данных
+ ms: Kata laluan pangkalan data
+ pt-br: Senha do banco de dados
+ required: true
+ rule: paramComplexity
+ type: password
+ - default: generate
+ edit: true
+ envKey: DJANGO_SECRET_KEY
+ labelEn: Application Secret
+ labelZh: 应用密钥
+ label:
+ en: Application Secret
+ zh: 应用密钥
+ zh-Hant: 應用程式密鑰
+ ja: アプリケーションシークレット
+ ko: 애플리케이션 비밀 키
+ ru: Секрет приложения
+ ms: Rahsia aplikasi
+ pt-br: Segredo do aplicativo
+ required: true
+ type: password
+ - default: localhost:8000
+ edit: true
+ envKey: FLAGSMITH_DOMAIN
+ labelEn: Public Host
+ labelZh: 公开访问主机
+ label:
+ en: Public Host
+ zh: 公开访问主机
+ zh-Hant: 公開存取主機
+ ja: 公開ホスト
+ ko: 공개 호스트
+ ru: Публичный хост
+ ms: Hos awam
+ pt-br: Host publico
+ required: true
+ type: text
+ - default: "*"
+ edit: true
+ envKey: FLAGSMITH_ALLOWED_HOSTS
+ labelEn: Allowed Hosts
+ labelZh: 允许的主机
+ label:
+ en: Allowed Hosts
+ zh: 允许的主机
+ zh-Hant: 允許的主機
+ ja: 許可するホスト
+ ko: 허용된 호스트
+ ru: Разрешенные хосты
+ ms: Hos yang dibenarkan
+ pt-br: Hosts permitidos
+ required: true
+ type: text
+ - default: "false"
+ edit: true
+ envKey: PREVENT_SIGNUP
+ labelEn: Prevent New Signups
+ labelZh: 禁止新用户注册
+ label:
+ en: Prevent New Signups
+ zh: 禁止新用户注册
+ zh-Hant: 禁止新使用者註冊
+ ja: 新規登録を禁止
+ ko: 신규 가입 방지
+ ru: Запретить новые регистрации
+ ms: Halang pendaftaran baharu
+ pt-br: Impedir novos cadastros
+ required: true
+ type: select
+ values:
+ - label: "false"
+ value: "false"
+ - label: "true"
+ value: "true"
diff --git a/apps/flagsmith/2.257.0/data/.gitkeep b/apps/flagsmith/2.257.0/data/.gitkeep
new file mode 100644
index 000000000..8b1378917
--- /dev/null
+++ b/apps/flagsmith/2.257.0/data/.gitkeep
@@ -0,0 +1 @@
+
diff --git a/apps/flagsmith/2.257.0/docker-compose.yml b/apps/flagsmith/2.257.0/docker-compose.yml
new file mode 100644
index 000000000..3b8c38dd3
--- /dev/null
+++ b/apps/flagsmith/2.257.0/docker-compose.yml
@@ -0,0 +1,104 @@
+services:
+ flagsmith-migrate:
+ image: "flagsmith/flagsmith:2.257.0@sha256:e3b2cfca0dd268cc7af320becfd3a3ed928a58ae424c5c69b00a600bdf2a36b3"
+ container_name: ${CONTAINER_NAME}-migrate
+ restart: unless-stopped
+ entrypoint: ["/bin/sh", "-c"]
+ command:
+ - flagsmith migrate && touch /tmp/flagsmith-migration-complete && exec sleep infinity
+ networks:
+ - 1panel-network
+ environment:
+ DJANGO_DB_HOST: ${PANEL_DB_HOST}
+ DJANGO_DB_PORT: ${PANEL_DB_PORT}
+ DJANGO_DB_NAME: ${PANEL_DB_NAME}
+ DJANGO_DB_USER: ${PANEL_DB_USER}
+ DJANGO_DB_PASSWORD: ${PANEL_DB_USER_PASSWORD}
+ USE_POSTGRES_FOR_ANALYTICS: "true"
+ ENVIRONMENT: production
+ DJANGO_ALLOWED_HOSTS: ${FLAGSMITH_ALLOWED_HOSTS}
+ FLAGSMITH_DOMAIN: ${FLAGSMITH_DOMAIN}
+ DJANGO_SECRET_KEY: ${DJANGO_SECRET_KEY}
+ PREVENT_SIGNUP: ${PREVENT_SIGNUP}
+ TASK_RUN_METHOD: TASK_PROCESSOR
+ PROMETHEUS_ENABLED: "true"
+ healthcheck:
+ test: ["CMD-SHELL", "test -f /tmp/flagsmith-migration-complete"]
+ interval: 5s
+ timeout: 2s
+ start_period: 20s
+ retries: 60
+ security_opt:
+ - no-new-privileges:true
+ labels:
+ createdBy: "Apps"
+
+ flagsmith:
+ image: "flagsmith/flagsmith:2.257.0@sha256:e3b2cfca0dd268cc7af320becfd3a3ed928a58ae424c5c69b00a600bdf2a36b3"
+ container_name: ${CONTAINER_NAME}
+ restart: unless-stopped
+ command: ["serve"]
+ depends_on:
+ flagsmith-migrate:
+ condition: service_healthy
+ networks:
+ - 1panel-network
+ ports:
+ - "${PANEL_APP_BIND_ADDRESS}:${PANEL_APP_PORT_HTTP}:8000"
+ environment:
+ DJANGO_DB_HOST: ${PANEL_DB_HOST}
+ DJANGO_DB_PORT: ${PANEL_DB_PORT}
+ DJANGO_DB_NAME: ${PANEL_DB_NAME}
+ DJANGO_DB_USER: ${PANEL_DB_USER}
+ DJANGO_DB_PASSWORD: ${PANEL_DB_USER_PASSWORD}
+ USE_POSTGRES_FOR_ANALYTICS: "true"
+ ENVIRONMENT: production
+ DJANGO_ALLOWED_HOSTS: ${FLAGSMITH_ALLOWED_HOSTS}
+ FLAGSMITH_DOMAIN: ${FLAGSMITH_DOMAIN}
+ DJANGO_SECRET_KEY: ${DJANGO_SECRET_KEY}
+ PREVENT_SIGNUP: ${PREVENT_SIGNUP}
+ TASK_RUN_METHOD: TASK_PROCESSOR
+ PROMETHEUS_ENABLED: "true"
+ healthcheck:
+ test: ["CMD", "flagsmith", "healthcheck", "tcp"]
+ interval: 10s
+ timeout: 5s
+ start_period: 60s
+ retries: 6
+ security_opt:
+ - no-new-privileges:true
+ labels:
+ createdBy: "Apps"
+
+ flagsmith-task-processor:
+ image: "flagsmith/flagsmith:2.257.0@sha256:e3b2cfca0dd268cc7af320becfd3a3ed928a58ae424c5c69b00a600bdf2a36b3"
+ container_name: ${CONTAINER_NAME}-task-processor
+ restart: unless-stopped
+ command: ["run-task-processor"]
+ depends_on:
+ flagsmith-migrate:
+ condition: service_healthy
+ networks:
+ - 1panel-network
+ environment:
+ DJANGO_DB_HOST: ${PANEL_DB_HOST}
+ DJANGO_DB_PORT: ${PANEL_DB_PORT}
+ DJANGO_DB_NAME: ${PANEL_DB_NAME}
+ DJANGO_DB_USER: ${PANEL_DB_USER}
+ DJANGO_DB_PASSWORD: ${PANEL_DB_USER_PASSWORD}
+ USE_POSTGRES_FOR_ANALYTICS: "true"
+ ENVIRONMENT: production
+ DJANGO_ALLOWED_HOSTS: ${FLAGSMITH_ALLOWED_HOSTS}
+ FLAGSMITH_DOMAIN: ${FLAGSMITH_DOMAIN}
+ DJANGO_SECRET_KEY: ${DJANGO_SECRET_KEY}
+ PREVENT_SIGNUP: ${PREVENT_SIGNUP}
+ TASK_RUN_METHOD: TASK_PROCESSOR
+ PROMETHEUS_ENABLED: "true"
+ security_opt:
+ - no-new-privileges:true
+ labels:
+ createdBy: "Apps"
+
+networks:
+ 1panel-network:
+ external: true
diff --git a/apps/flagsmith/2.257.0/scripts/init.sh b/apps/flagsmith/2.257.0/scripts/init.sh
new file mode 100755
index 000000000..3f3cb2225
--- /dev/null
+++ b/apps/flagsmith/2.257.0/scripts/init.sh
@@ -0,0 +1,67 @@
+#!/usr/bin/env bash
+set -euo pipefail
+
+ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd -P)"
+ENV_FILE="${ENV_FILE:-${ROOT_DIR}/.env}"
+
+fail() {
+ printf '%s\n' "$1" >&2
+ exit 1
+}
+
+read_env_value() {
+ local key="$1"
+ local value=""
+ value="$(sed -n "s/^${key}=//p" "$ENV_FILE" | tail -n 1)"
+ case "$value" in
+ \"*\") value="${value#\"}"; value="${value%\"}" ;;
+ \'*\') value="${value#\'}"; value="${value%\'}" ;;
+ esac
+ printf '%s\n' "$value"
+}
+
+set_env_value() {
+ local key="$1"
+ local value="$2"
+ local temp_file
+ temp_file="$(mktemp "${ROOT_DIR}/.flagsmith-env.tmp.XXXXXX")"
+ awk -v key="$key" -v value="$value" '
+ BEGIN { written = 0 }
+ $0 ~ "^" key "=" {
+ if (!written) {
+ print key "=" value
+ written = 1
+ }
+ next
+ }
+ { print }
+ END {
+ if (!written) print key "=" value
+ }
+ ' "$ENV_FILE" > "$temp_file"
+ chmod 600 "$temp_file"
+ mv -f -- "$temp_file" "$ENV_FILE"
+}
+
+[[ -f "$ENV_FILE" ]] || fail "$ENV_FILE not found"
+[[ ! -L "$ENV_FILE" ]] || fail "$ENV_FILE must not be a symbolic link"
+
+domain="$(read_env_value FLAGSMITH_DOMAIN)"
+[[ "$domain" =~ ^[A-Za-z0-9._:-]+$ ]] || fail "FLAGSMITH_DOMAIN must be a host with an optional port and no scheme or path"
+
+allowed_hosts="$(read_env_value FLAGSMITH_ALLOWED_HOSTS)"
+[[ "$allowed_hosts" =~ ^[A-Za-z0-9.*_:-]+(,[A-Za-z0-9.*_:-]+)*$ ]] || fail "FLAGSMITH_ALLOWED_HOSTS must be a comma-separated host list"
+
+prevent_signup="$(read_env_value PREVENT_SIGNUP)"
+[[ "$prevent_signup" == "true" || "$prevent_signup" == "false" ]] || fail "PREVENT_SIGNUP must be true or false"
+
+secret="$(read_env_value DJANGO_SECRET_KEY)"
+if [[ -z "$secret" || "$secret" == "generate" ]]; then
+ command -v openssl >/dev/null 2>&1 || fail "openssl is required to generate DJANGO_SECRET_KEY"
+ secret="$(openssl rand -hex 32)"
+fi
+[[ ${#secret} -ge 50 ]] || fail "DJANGO_SECRET_KEY must contain at least 50 characters"
+[[ "$secret" =~ ^[A-Za-z0-9._~!@%+=:,/-]+$ ]] || fail "DJANGO_SECRET_KEY contains unsupported dotenv characters"
+
+chmod 600 "$ENV_FILE"
+set_env_value DJANGO_SECRET_KEY "$secret"
diff --git a/apps/flagsmith/2.257.0/scripts/uninstall.sh b/apps/flagsmith/2.257.0/scripts/uninstall.sh
new file mode 100755
index 000000000..5c199242b
--- /dev/null
+++ b/apps/flagsmith/2.257.0/scripts/uninstall.sh
@@ -0,0 +1,8 @@
+#!/usr/bin/env bash
+set -euo pipefail
+
+if command -v docker-compose >/dev/null 2>&1; then
+ docker-compose down --remove-orphans
+else
+ docker compose down --remove-orphans
+fi
diff --git a/apps/flagsmith/2.257.0/scripts/upgrade.sh b/apps/flagsmith/2.257.0/scripts/upgrade.sh
new file mode 100755
index 000000000..593b31667
--- /dev/null
+++ b/apps/flagsmith/2.257.0/scripts/upgrade.sh
@@ -0,0 +1,5 @@
+#!/usr/bin/env bash
+set -euo pipefail
+
+SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd -P)"
+exec bash "${SCRIPT_DIR}/init.sh"
diff --git a/apps/flagsmith/README.md b/apps/flagsmith/README.md
new file mode 100644
index 000000000..842a3a04f
--- /dev/null
+++ b/apps/flagsmith/README.md
@@ -0,0 +1,52 @@
+# Flagsmith
+
+## 产品介绍
+
+Flagsmith 是开源的功能标志与远程配置平台,可集中管理功能开关、环境、身份和分段规则,并通过 SDK 或 API 向应用提供配置。
+
+## 主要功能
+
+- 为多个项目和环境管理功能标志
+- 按身份、特征和分段规则逐步发布功能
+- 通过客户端、服务端 SDK 和 REST API 获取标志
+- 记录标志分析数据并运行后台任务
+
+## 访问说明
+
+- 安装前需在 1Panel 中准备一个正在运行的 PostgreSQL 服务,并在表单中选择它。1Panel 会创建并关联 Flagsmith 使用的数据库和用户。
+- 安装后访问 `http://<服务器 IP>:8000`,实际端口以 `PANEL_APP_PORT_HTTP` 为准,然后创建首个账户。
+- `FLAGSMITH_DOMAIN` 填写浏览器实际访问的主机和可选端口,不包含 `http://` 或路径。例如 `flags.example.com` 或 `192.0.2.10:8000`。
+- 公网部署应通过 HTTPS 反向代理访问,并将 `FLAGSMITH_ALLOWED_HOSTS` 限制为实际域名。
+
+## 拓扑和数据
+
+本包保留官方 Compose 的完整应用拓扑:独立数据库迁移门禁、Web/API 主服务和独立任务处理器。三个角色使用同一官方镜像,迁移成功后门禁容器进入空闲状态,另外两个服务才会启动。迁移容器保持运行是为了兼容 1Panel 将成功退出的一次性容器仍标记为异常的状态模型;它不对外提供服务或重复执行任务。Redis 仅用于可选的高级缓存或事件摄取配置,不是官方基础 Compose 的必需依赖。
+
+业务数据保存在所选 PostgreSQL 服务中。升级或卸载前请备份该数据库;卸载应用不会删除外部 PostgreSQL 服务本身。1Panel 当前可能将关联 PostgreSQL 用户创建为超级用户,因此共享实例上的关联用户不是强隔离边界。面向不受信任用户或高价值数据时,应使用专用 PostgreSQL 实例。
+
+## 安全说明
+
+- `DJANGO_SECRET_KEY` 在首次安装时生成并保存在应用 `.env` 中,升级时保持不变。不要提交或共享安装后的 `.env`。
+- 默认允许首个及后续用户注册。完成管理员初始化后,可将 `PREVENT_SIGNUP` 改为 `true`。
+- Google OAuth、SAML、SMTP、Webhook 和其他外部集成均为可选功能。启用时应使用最小权限凭据,并在升级前重新检查镜像安全公告。
+- 应用镜像以非 root 用户运行,只有 Web/API 主服务向主机发布端口;迁移和任务处理器不发布主机端口。
+
+## Introduction
+
+Flagsmith is an open-source feature flag and remote configuration platform. This package preserves the official migration gate, Web/API service, and task-processor topology while using a 1Panel-managed PostgreSQL service. The migration container stays idle after a successful migration because 1Panel otherwise treats a successfully exited one-shot Compose container as unhealthy.
+
+## Features
+
+- Manage feature flags across projects and environments
+- Target identities and segments for gradual releases
+- Serve configuration through client SDKs, server SDKs, and REST APIs
+- Store flag analytics and process background tasks
+
+Choose a running PostgreSQL service during installation. Back up the linked database before upgrades or uninstalling. A 1Panel-linked PostgreSQL role may currently be a superuser, so use a dedicated PostgreSQL instance where stronger isolation is required. Set `FLAGSMITH_DOMAIN` to the public host with an optional port, and use an HTTPS reverse proxy for Internet-facing deployments.
+
+## References
+
+- Website:
+- Source:
+- Documentation:
+- License: BSD-3-Clause
diff --git a/apps/flagsmith/data.yml b/apps/flagsmith/data.yml
new file mode 100644
index 000000000..ae41e635a
--- /dev/null
+++ b/apps/flagsmith/data.yml
@@ -0,0 +1,33 @@
+name: Flagsmith
+tags:
+ - 开发工具
+ - 项目管理
+title: 开源功能标志和远程配置平台
+description: 开源功能标志和远程配置平台
+additionalProperties:
+ key: flagsmith
+ name: Flagsmith
+ tags:
+ - DevTool
+ - Tool
+ shortDescZh: 开源功能标志和远程配置平台
+ shortDescEn: Open-source feature flag and remote configuration platform
+ description:
+ en: Open-source feature flag and remote configuration platform
+ zh: 开源功能标志和远程配置平台
+ zh-Hant: 開源功能旗標與遠端設定平台
+ ja: オープンソースの機能フラグおよびリモート設定プラットフォーム
+ ko: 오픈 소스 기능 플래그 및 원격 구성 플랫폼
+ ru: Платформа с открытым исходным кодом для флагов функций и удаленной конфигурации
+ ms: Platform sumber terbuka untuk bendera ciri dan konfigurasi jauh
+ pt-br: Plataforma de codigo aberto para sinalizadores de recursos e configuracao remota
+ type: tool
+ crossVersionUpdate: true
+ limit: 0
+ recommend: 0
+ website: https://www.flagsmith.com/
+ github: https://github.com/Flagsmith/flagsmith
+ document: https://docs.flagsmith.com/deployment-self-hosting/hosting-guides/docker
+ architectures:
+ - amd64
+ - arm64
diff --git a/apps/flagsmith/latest/.env.sample b/apps/flagsmith/latest/.env.sample
new file mode 100644
index 000000000..451b1f4d9
--- /dev/null
+++ b/apps/flagsmith/latest/.env.sample
@@ -0,0 +1,13 @@
+CONTAINER_NAME="flagsmith"
+PANEL_APP_BIND_ADDRESS="127.0.0.1"
+PANEL_APP_PORT_HTTP="8000"
+PANEL_DB_TYPE="postgresql"
+PANEL_DB_HOST="postgresql"
+PANEL_DB_PORT="5432"
+PANEL_DB_NAME="flagsmith"
+PANEL_DB_USER="flagsmith"
+PANEL_DB_USER_PASSWORD="change-me"
+DJANGO_SECRET_KEY="generate"
+FLAGSMITH_DOMAIN="localhost:8000"
+FLAGSMITH_ALLOWED_HOSTS="*"
+PREVENT_SIGNUP="false"
diff --git a/apps/flagsmith/latest/data.yml b/apps/flagsmith/latest/data.yml
new file mode 100644
index 000000000..ab06122ed
--- /dev/null
+++ b/apps/flagsmith/latest/data.yml
@@ -0,0 +1,208 @@
+additionalProperties:
+ formFields:
+ - default: 127.0.0.1
+ edit: true
+ envKey: PANEL_APP_BIND_ADDRESS
+ labelEn: Bind Address
+ labelZh: 绑定地址
+ label:
+ en: Bind Address
+ zh: 绑定地址
+ zh-Hant: 綁定位址
+ ja: バインドアドレス
+ ko: 바인드 주소
+ ru: Адрес привязки
+ ms: Alamat ikatan
+ pt-br: Endereco de vinculacao
+ required: true
+ type: text
+ - default: 8000
+ edit: true
+ envKey: PANEL_APP_PORT_HTTP
+ labelEn: HTTP Port
+ labelZh: HTTP 端口
+ label:
+ en: HTTP Port
+ zh: HTTP 端口
+ zh-Hant: HTTP 連接埠
+ ja: HTTP ポート
+ ko: HTTP 포트
+ ru: HTTP-порт
+ ms: Port HTTP
+ pt-br: Porta HTTP
+ required: true
+ rule: paramPort
+ type: number
+ - default: postgresql
+ envKey: PANEL_DB_TYPE
+ labelEn: Database Runtime
+ labelZh: 数据库运行环境
+ label:
+ en: Database Runtime
+ zh: 数据库运行环境
+ zh-Hant: 資料庫執行環境
+ ja: データベース実行環境
+ ko: 데이터베이스 런타임
+ ru: Среда базы данных
+ ms: Masa jalan pangkalan data
+ pt-br: Ambiente de banco de dados
+ required: true
+ type: apps
+ values:
+ - label: PostgreSQL
+ value: postgresql
+ child:
+ default: ""
+ envKey: PANEL_DB_HOST
+ labelEn: PostgreSQL Service
+ labelZh: PostgreSQL 服务
+ label:
+ en: PostgreSQL Service
+ zh: PostgreSQL 服务
+ zh-Hant: PostgreSQL 服務
+ ja: PostgreSQL サービス
+ ko: PostgreSQL 서비스
+ ru: Сервис PostgreSQL
+ ms: Perkhidmatan PostgreSQL
+ pt-br: Servico PostgreSQL
+ required: true
+ type: service
+ - default: 5432
+ edit: true
+ envKey: PANEL_DB_PORT
+ labelEn: Database Port
+ labelZh: 数据库端口
+ label:
+ en: Database Port
+ zh: 数据库端口
+ zh-Hant: 資料庫連接埠
+ ja: データベースポート
+ ko: 데이터베이스 포트
+ ru: Порт базы данных
+ ms: Port pangkalan data
+ pt-br: Porta do banco de dados
+ required: true
+ rule: paramPort
+ type: number
+ - default: flagsmith
+ edit: true
+ envKey: PANEL_DB_NAME
+ labelEn: Database Name
+ labelZh: 数据库名称
+ label:
+ en: Database Name
+ zh: 数据库名称
+ zh-Hant: 資料庫名稱
+ ja: データベース名
+ ko: 데이터베이스 이름
+ ru: Имя базы данных
+ ms: Nama pangkalan data
+ pt-br: Nome do banco de dados
+ random: true
+ required: true
+ rule: paramCommon
+ type: text
+ - default: flagsmith
+ edit: true
+ envKey: PANEL_DB_USER
+ labelEn: Database User
+ labelZh: 数据库用户
+ label:
+ en: Database User
+ zh: 数据库用户
+ zh-Hant: 資料庫使用者
+ ja: データベースユーザー
+ ko: 데이터베이스 사용자
+ ru: Пользователь базы данных
+ ms: Pengguna pangkalan data
+ pt-br: Usuario do banco de dados
+ random: true
+ required: true
+ rule: paramCommon
+ type: text
+ - default: ""
+ edit: true
+ envKey: PANEL_DB_USER_PASSWORD
+ labelEn: Database Password
+ labelZh: 数据库密码
+ label:
+ en: Database Password
+ zh: 数据库密码
+ zh-Hant: 資料庫密碼
+ ja: データベースパスワード
+ ko: 데이터베이스 비밀번호
+ ru: Пароль базы данных
+ ms: Kata laluan pangkalan data
+ pt-br: Senha do banco de dados
+ required: true
+ rule: paramComplexity
+ type: password
+ - default: generate
+ edit: true
+ envKey: DJANGO_SECRET_KEY
+ labelEn: Application Secret
+ labelZh: 应用密钥
+ label:
+ en: Application Secret
+ zh: 应用密钥
+ zh-Hant: 應用程式密鑰
+ ja: アプリケーションシークレット
+ ko: 애플리케이션 비밀 키
+ ru: Секрет приложения
+ ms: Rahsia aplikasi
+ pt-br: Segredo do aplicativo
+ required: true
+ type: password
+ - default: localhost:8000
+ edit: true
+ envKey: FLAGSMITH_DOMAIN
+ labelEn: Public Host
+ labelZh: 公开访问主机
+ label:
+ en: Public Host
+ zh: 公开访问主机
+ zh-Hant: 公開存取主機
+ ja: 公開ホスト
+ ko: 공개 호스트
+ ru: Публичный хост
+ ms: Hos awam
+ pt-br: Host publico
+ required: true
+ type: text
+ - default: "*"
+ edit: true
+ envKey: FLAGSMITH_ALLOWED_HOSTS
+ labelEn: Allowed Hosts
+ labelZh: 允许的主机
+ label:
+ en: Allowed Hosts
+ zh: 允许的主机
+ zh-Hant: 允許的主機
+ ja: 許可するホスト
+ ko: 허용된 호스트
+ ru: Разрешенные хосты
+ ms: Hos yang dibenarkan
+ pt-br: Hosts permitidos
+ required: true
+ type: text
+ - default: "false"
+ edit: true
+ envKey: PREVENT_SIGNUP
+ labelEn: Prevent New Signups
+ labelZh: 禁止新用户注册
+ label:
+ en: Prevent New Signups
+ zh: 禁止新用户注册
+ zh-Hant: 禁止新使用者註冊
+ ja: 新規登録を禁止
+ ko: 신규 가입 방지
+ ru: Запретить новые регистрации
+ ms: Halang pendaftaran baharu
+ pt-br: Impedir novos cadastros
+ required: true
+ type: select
+ values:
+ - label: "false"
+ value: "false"
+ - label: "true"
+ value: "true"
diff --git a/apps/flagsmith/latest/data/.gitkeep b/apps/flagsmith/latest/data/.gitkeep
new file mode 100644
index 000000000..8b1378917
--- /dev/null
+++ b/apps/flagsmith/latest/data/.gitkeep
@@ -0,0 +1 @@
+
diff --git a/apps/flagsmith/latest/docker-compose.yml b/apps/flagsmith/latest/docker-compose.yml
new file mode 100644
index 000000000..de86bfbd0
--- /dev/null
+++ b/apps/flagsmith/latest/docker-compose.yml
@@ -0,0 +1,104 @@
+services:
+ flagsmith-migrate:
+ image: "flagsmith/flagsmith:latest@sha256:e3b2cfca0dd268cc7af320becfd3a3ed928a58ae424c5c69b00a600bdf2a36b3"
+ container_name: ${CONTAINER_NAME}-migrate
+ restart: unless-stopped
+ entrypoint: ["/bin/sh", "-c"]
+ command:
+ - flagsmith migrate && touch /tmp/flagsmith-migration-complete && exec sleep infinity
+ networks:
+ - 1panel-network
+ environment:
+ DJANGO_DB_HOST: ${PANEL_DB_HOST}
+ DJANGO_DB_PORT: ${PANEL_DB_PORT}
+ DJANGO_DB_NAME: ${PANEL_DB_NAME}
+ DJANGO_DB_USER: ${PANEL_DB_USER}
+ DJANGO_DB_PASSWORD: ${PANEL_DB_USER_PASSWORD}
+ USE_POSTGRES_FOR_ANALYTICS: "true"
+ ENVIRONMENT: production
+ DJANGO_ALLOWED_HOSTS: ${FLAGSMITH_ALLOWED_HOSTS}
+ FLAGSMITH_DOMAIN: ${FLAGSMITH_DOMAIN}
+ DJANGO_SECRET_KEY: ${DJANGO_SECRET_KEY}
+ PREVENT_SIGNUP: ${PREVENT_SIGNUP}
+ TASK_RUN_METHOD: TASK_PROCESSOR
+ PROMETHEUS_ENABLED: "true"
+ healthcheck:
+ test: ["CMD-SHELL", "test -f /tmp/flagsmith-migration-complete"]
+ interval: 5s
+ timeout: 2s
+ start_period: 20s
+ retries: 60
+ security_opt:
+ - no-new-privileges:true
+ labels:
+ createdBy: "Apps"
+
+ flagsmith:
+ image: "flagsmith/flagsmith:latest@sha256:e3b2cfca0dd268cc7af320becfd3a3ed928a58ae424c5c69b00a600bdf2a36b3"
+ container_name: ${CONTAINER_NAME}
+ restart: unless-stopped
+ command: ["serve"]
+ depends_on:
+ flagsmith-migrate:
+ condition: service_healthy
+ networks:
+ - 1panel-network
+ ports:
+ - "${PANEL_APP_BIND_ADDRESS}:${PANEL_APP_PORT_HTTP}:8000"
+ environment:
+ DJANGO_DB_HOST: ${PANEL_DB_HOST}
+ DJANGO_DB_PORT: ${PANEL_DB_PORT}
+ DJANGO_DB_NAME: ${PANEL_DB_NAME}
+ DJANGO_DB_USER: ${PANEL_DB_USER}
+ DJANGO_DB_PASSWORD: ${PANEL_DB_USER_PASSWORD}
+ USE_POSTGRES_FOR_ANALYTICS: "true"
+ ENVIRONMENT: production
+ DJANGO_ALLOWED_HOSTS: ${FLAGSMITH_ALLOWED_HOSTS}
+ FLAGSMITH_DOMAIN: ${FLAGSMITH_DOMAIN}
+ DJANGO_SECRET_KEY: ${DJANGO_SECRET_KEY}
+ PREVENT_SIGNUP: ${PREVENT_SIGNUP}
+ TASK_RUN_METHOD: TASK_PROCESSOR
+ PROMETHEUS_ENABLED: "true"
+ healthcheck:
+ test: ["CMD", "flagsmith", "healthcheck", "tcp"]
+ interval: 10s
+ timeout: 5s
+ start_period: 60s
+ retries: 6
+ security_opt:
+ - no-new-privileges:true
+ labels:
+ createdBy: "Apps"
+
+ flagsmith-task-processor:
+ image: "flagsmith/flagsmith:latest@sha256:e3b2cfca0dd268cc7af320becfd3a3ed928a58ae424c5c69b00a600bdf2a36b3"
+ container_name: ${CONTAINER_NAME}-task-processor
+ restart: unless-stopped
+ command: ["run-task-processor"]
+ depends_on:
+ flagsmith-migrate:
+ condition: service_healthy
+ networks:
+ - 1panel-network
+ environment:
+ DJANGO_DB_HOST: ${PANEL_DB_HOST}
+ DJANGO_DB_PORT: ${PANEL_DB_PORT}
+ DJANGO_DB_NAME: ${PANEL_DB_NAME}
+ DJANGO_DB_USER: ${PANEL_DB_USER}
+ DJANGO_DB_PASSWORD: ${PANEL_DB_USER_PASSWORD}
+ USE_POSTGRES_FOR_ANALYTICS: "true"
+ ENVIRONMENT: production
+ DJANGO_ALLOWED_HOSTS: ${FLAGSMITH_ALLOWED_HOSTS}
+ FLAGSMITH_DOMAIN: ${FLAGSMITH_DOMAIN}
+ DJANGO_SECRET_KEY: ${DJANGO_SECRET_KEY}
+ PREVENT_SIGNUP: ${PREVENT_SIGNUP}
+ TASK_RUN_METHOD: TASK_PROCESSOR
+ PROMETHEUS_ENABLED: "true"
+ security_opt:
+ - no-new-privileges:true
+ labels:
+ createdBy: "Apps"
+
+networks:
+ 1panel-network:
+ external: true
diff --git a/apps/flagsmith/latest/scripts/init.sh b/apps/flagsmith/latest/scripts/init.sh
new file mode 100755
index 000000000..3f3cb2225
--- /dev/null
+++ b/apps/flagsmith/latest/scripts/init.sh
@@ -0,0 +1,67 @@
+#!/usr/bin/env bash
+set -euo pipefail
+
+ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd -P)"
+ENV_FILE="${ENV_FILE:-${ROOT_DIR}/.env}"
+
+fail() {
+ printf '%s\n' "$1" >&2
+ exit 1
+}
+
+read_env_value() {
+ local key="$1"
+ local value=""
+ value="$(sed -n "s/^${key}=//p" "$ENV_FILE" | tail -n 1)"
+ case "$value" in
+ \"*\") value="${value#\"}"; value="${value%\"}" ;;
+ \'*\') value="${value#\'}"; value="${value%\'}" ;;
+ esac
+ printf '%s\n' "$value"
+}
+
+set_env_value() {
+ local key="$1"
+ local value="$2"
+ local temp_file
+ temp_file="$(mktemp "${ROOT_DIR}/.flagsmith-env.tmp.XXXXXX")"
+ awk -v key="$key" -v value="$value" '
+ BEGIN { written = 0 }
+ $0 ~ "^" key "=" {
+ if (!written) {
+ print key "=" value
+ written = 1
+ }
+ next
+ }
+ { print }
+ END {
+ if (!written) print key "=" value
+ }
+ ' "$ENV_FILE" > "$temp_file"
+ chmod 600 "$temp_file"
+ mv -f -- "$temp_file" "$ENV_FILE"
+}
+
+[[ -f "$ENV_FILE" ]] || fail "$ENV_FILE not found"
+[[ ! -L "$ENV_FILE" ]] || fail "$ENV_FILE must not be a symbolic link"
+
+domain="$(read_env_value FLAGSMITH_DOMAIN)"
+[[ "$domain" =~ ^[A-Za-z0-9._:-]+$ ]] || fail "FLAGSMITH_DOMAIN must be a host with an optional port and no scheme or path"
+
+allowed_hosts="$(read_env_value FLAGSMITH_ALLOWED_HOSTS)"
+[[ "$allowed_hosts" =~ ^[A-Za-z0-9.*_:-]+(,[A-Za-z0-9.*_:-]+)*$ ]] || fail "FLAGSMITH_ALLOWED_HOSTS must be a comma-separated host list"
+
+prevent_signup="$(read_env_value PREVENT_SIGNUP)"
+[[ "$prevent_signup" == "true" || "$prevent_signup" == "false" ]] || fail "PREVENT_SIGNUP must be true or false"
+
+secret="$(read_env_value DJANGO_SECRET_KEY)"
+if [[ -z "$secret" || "$secret" == "generate" ]]; then
+ command -v openssl >/dev/null 2>&1 || fail "openssl is required to generate DJANGO_SECRET_KEY"
+ secret="$(openssl rand -hex 32)"
+fi
+[[ ${#secret} -ge 50 ]] || fail "DJANGO_SECRET_KEY must contain at least 50 characters"
+[[ "$secret" =~ ^[A-Za-z0-9._~!@%+=:,/-]+$ ]] || fail "DJANGO_SECRET_KEY contains unsupported dotenv characters"
+
+chmod 600 "$ENV_FILE"
+set_env_value DJANGO_SECRET_KEY "$secret"
diff --git a/apps/flagsmith/latest/scripts/uninstall.sh b/apps/flagsmith/latest/scripts/uninstall.sh
new file mode 100755
index 000000000..5c199242b
--- /dev/null
+++ b/apps/flagsmith/latest/scripts/uninstall.sh
@@ -0,0 +1,8 @@
+#!/usr/bin/env bash
+set -euo pipefail
+
+if command -v docker-compose >/dev/null 2>&1; then
+ docker-compose down --remove-orphans
+else
+ docker compose down --remove-orphans
+fi
diff --git a/apps/flagsmith/latest/scripts/upgrade.sh b/apps/flagsmith/latest/scripts/upgrade.sh
new file mode 100755
index 000000000..593b31667
--- /dev/null
+++ b/apps/flagsmith/latest/scripts/upgrade.sh
@@ -0,0 +1,5 @@
+#!/usr/bin/env bash
+set -euo pipefail
+
+SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd -P)"
+exec bash "${SCRIPT_DIR}/init.sh"
diff --git a/apps/flagsmith/logo.png b/apps/flagsmith/logo.png
new file mode 100644
index 0000000000000000000000000000000000000000..4749009862848e097801ffc9014a2a94965e8384
GIT binary patch
literal 6805
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 #AReuWMp! |