RepoPilot

meolu/walle-web

walle - 瓦力 Devops开源项目代码部署平台

Mixed

Stale — last commit 4y ago

HealthyDependency

Permissive license, no critical CVEs, actively maintained — safe to depend on.

HealthyFork & modify

Has a license, tests, and CI — clean foundation to fork and modify.

HealthyLearn from

Documented and popular — useful reference codebase to read through.

MixedDeploy as-is

last commit was 4y ago; Scorecard "Branch-Protection" is 0/10…

  • Stale — last commit 4y ago
  • Scorecard: marked unmaintained (0/10)
  • Scorecard: default branch unprotected (0/10)
  • 14 active contributors
  • Distributed ownership (top contributor 41% of recent commits)
  • Apache-2.0 licensed
  • CI configured
  • Tests present

What would improve this?

  • Deploy as-is MixedHealthy if: 1 commit in the last 180 days; bring "Branch-Protection" to ≥3/10 (see scorecard report)

Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests + OpenSSF Scorecard

Informational only. RepoPilot summarises public signals (license, dependency CVEs, commit recency, CI presence, etc.) at the time of analysis. Signals can be incomplete or stale. Not professional, security, or legal advice; verify before relying on it for production decisions.

Embed the "Safe to depend on" badge

Paste into your README — live-updates from the latest cached analysis.

Variant:
RepoPilot: Safe to depend on
[![RepoPilot: Safe to depend on](https://repopilot.app/api/badge/meolu/walle-web?axis=dependency)](https://repopilot.app/r/meolu/walle-web)

Paste at the top of your README.md — renders inline like a shields.io badge.

Preview social card

This card auto-renders when someone shares https://repopilot.app/r/meolu/walle-web on X, Slack, or LinkedIn.

Ask AI about meolu/walle-web

Grounded in the actual source code. Pick a starter question or write your own.

Or write your own question →

Onboarding doc

Onboarding: meolu/walle-web

Generated by RepoPilot · 2026-06-20 · Source

🎯Verdict

WAIT — Stale — last commit 4y ago

  • 14 active contributors
  • Distributed ownership (top contributor 41% of recent commits)
  • Apache-2.0 licensed
  • CI configured
  • Tests present
  • ⚠ Stale — last commit 4y ago
  • ⚠ Scorecard: marked unmaintained (0/10)
  • ⚠ Scorecard: default branch unprotected (0/10)

<sub>Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests + OpenSSF Scorecard</sub>

TL;DR

Walle (瓦力) is an open-source DevOps deployment platform that enables one-click code deployment and rollback for multiple languages (PHP, Java, Python, Go) across multiple environments and servers via a web UI. It replaces Jenkins for teams needing Git-based deployment with real-time WebSocket console output, canary/gray deployments, and post-deployment hooks. Monorepo structure: backend is Python (309KB) in the root; frontend (fe/) is Node.js with static assets in fe/static (compiled JS/CSS bundles); deployment logic uses Shell scripts (6.8KB); containerized via Dockerfile and docker-compose.yml. RESTful API backend with GitLab-like permission model.

👥Who it's for

DevOps engineers and deployment teams at companies using multiple tech stacks who need a user-friendly alternative to Jenkins for managing releases across development, staging, and production environments without CLI expertise.

🌱Maturity & risk

Production-ready: version 2.0.0 released Dec 2018 with significant effort, has Travis CI setup (.travis.yml), Docker support (Dockerfile, docker-compose.yml), and multiple stable releases (2.0.1 shipped Jan 2019). However, the project appears to have slowed—latest visible milestone (2.1.0, March 2019) lacks evidence of recent commits in the file structure provided.

Single-maintainer project (meolu) with unclear current activity level; the 2018–2019 roadmap completion date suggests potential maintenance gaps. No test directory visible in top 60 files, raising code quality concerns. Chinese-language documentation may limit non-Mandarin contributor onboarding. Breaking change between v1.x and v2.0 warns against casual upgrades.

Active areas of work

No clear active development signals in provided file list. Roadmap shows v2.1.0 targeted for March 2019 (Dashboard, admin perms) but no evidence of completion. Last documented release was 2.0.1 (Jan 2019). Project likely in maintenance mode or dormant.

🚀Get running

git clone https://github.com/meolu/walle-web.git
cd walle-web
docker-compose up
# or without Docker: install Python 3.7+, then see admin.sh for local setup

Refer to README.md for detailed installation and 快速安装 for step-by-step guide.

Daily commands: Docker (recommended): docker-compose up starts all services. Local dev: admin.sh script suggests python admin.sh for setup; inspect that file for virtualenv and dependency install. Frontend dev: likely npm install && npm run dev in fe/ directory (inferred from .eslintrc and static assets).

🗺️Map of the codebase

  • requirements/prod.txt — Production dependencies defining the Flask/SQLAlchemy stack and all backend runtime requirements; critical for understanding the tech stack.
  • migrations/alembic.ini — Alembic database migration configuration; essential for understanding data model evolution and how schema changes are managed.
  • fe/index.html — Frontend entry point and Vue.js application bootstrap; all frontend UI loads through this file.
  • docker-compose.yml — Complete local development and production environment orchestration; defines all service dependencies and networking.
  • Dockerfile — Container image definition for the entire Walle deployment; critical for understanding deployment infrastructure.
  • .travis.yml — CI/CD pipeline configuration; shows automated testing and build process for every commit.
  • README.md — Project overview, features, and high-level architecture; foundational context for all contributors.

🛠️How to make changes

Add a New Database Entity/Table

  1. Define SQLAlchemy model in the backend models module (not shown in file list, typically in app/models/) ((backend models module))
  2. Create an Alembic migration script using alembic revision --autogenerate -m 'description' (migrations/versions/*.py)
  3. Run migration with alembic upgrade head to apply schema changes to database (migrations/alembic.ini)
  4. Add corresponding REST API endpoints in Flask blueprint (backend routes, not in file list) ((backend routes module))

Add a New Frontend Page/Component

  1. Create Vue.js component file in frontend source (structure compiled into fe/static/js/) (fe/index.html)
  2. Configure ESLint rules to validate code style compliance (fe/.eslintrc)
  3. Import and register component in main Vue app entry point (fe/index.html)
  4. Ensure Nginx routes requests to SPA which handles client-side routing (gateway/nginx/default.conf)

Deploy Walle to Production

  1. Build Docker image containing Python backend using multi-stage build (Dockerfile)
  2. Define all production services (backend, Nginx, database) and their networking (docker-compose.yml)
  3. Configure SSL certificates in Nginx gateway layer (gateway/nginx/ssl/.gitignore)
  4. Ensure Nginx correctly routes API requests to backend and serves static frontend (gateway/nginx/default.conf)
  5. Install production dependencies from locked requirements file (requirements/prod.txt)

🔧Why these technologies

  • Flask (Python) — Lightweight web framework ideal for RESTful APIs; supports rapid iteration and integration with DevOps tooling (Ansible, Shell, Git)
  • SQLAlchemy + Alembic — ORM abstracts database operations; Alembic manages schema migrations in version control, enabling safe database evolution
  • Vue.js Frontend — Reactive SPA framework provides responsive UI for complex deployment workflows; component-based architecture supports maintainability
  • Nginx Gateway — Reverse proxy handles SSL termination, static asset serving, and API routing; decouples frontend from backend
  • Docker + Docker Compose — Containerization ensures reproducible environments across dev/staging/production; Compose orchestrates multi-service deployments
  • Redis — In-memory cache reduces database load for frequently accessed resources (projects, tasks, user sessions)

⚖️Trade-offs already made

  • Monolithic backend with Vue.js SPA frontend (vs. microservices)

    • Why: Simpler deployment model, easier debugging, and faster time-to-feature for a DevOps platform
    • Consequence: Scaling individual components requires refactoring; tight coupling between frontend and backend API contracts
  • Nginx reverse proxy layer (vs. backend serving static files directly)

    • Why: Nginx is highly optimized for static asset delivery and SSL termination; separates concerns
    • Consequence: Additional deployment layer to configure and troubleshoot; adds one hop to every request
  • Alembic migrations in Python code (vs. database-first approach)

    • Why: Migrations live in version control; enables reproducible schema evolution and rollback capability
    • Consequence: Developers must write migration scripts; potential for migration order conflicts in team environments
  • RESTful API without GraphQL (vs. GraphQL)

    • Why: RESTful is simpler to implement and reason about; matches GitLab API pattern mentioned in README
    • Consequence: Over-fetching and under-fetching of related resources; frontend may need multiple requests for complex views

🚫Non-goals (don't propose these)

  • Real-time collaborative editing (code or config changes are not synchronized live across users)
  • Support for Windows-based deployment targets (Git, shell scripts assume Unix/Linux environment)
  • Built-in secret management or encryption at rest (passwords/tokens stored in database without explicit encryption layer)
  • Multi-tenancy at the database level (all workspaces share same database; isolation is logical/permission-based only)
  • Horizontal scaling of backend service (designed for single-instance deployment; no load balancer configuration shown)

🪤Traps & gotchas

Database initialization: admin.sh likely requires database connectivity; check for environment variables (DB_HOST, DB_USER, DB_PASS). Python 3.7+ requirement: version 2.0.1 explicitly added Python 3.7+ compatibility—don't run on Python 2.x. WebSocket server: real-time console requires WebSocket support (likely gevent or similar)—ensure reverse proxy (nginx) passes Upgrade headers. Git SSH keys: deployment agents need SSH access to repos; pre-configure git credentials or SSH keys on target servers. Space/Project hierarchy: permission model is strict; tasks can only execute in authorized environments per Space and Project bindings.

🏗️Architecture

💡Concepts to learn

  • Gray Deployment / Canary Release — Walle's headline feature (added in v2.0) for rolling out code to a subset of servers; essential to understand failure isolation and gradual rollout patterns when designing deployments
  • WebSocket (Real-time Console) — Walle streams live shell output during deployment via WebSocket instead of polling; affects how the backend manages long-lived connections and message buffering
  • Deployment Hook (Pre/Post Hook) — Walle allows custom shell scripts before and after deployment; critical for cache invalidation, health checks, and database migrations—understand hook execution order and failure handling
  • Role-Based Access Control (RBAC) — Walle's permission model mirrors GitLab's (Space → Project → Environment → User Groups); must understand how permissions cascade to write authorization checks and audit logs
  • Space (Multi-tenancy Boundary) — Unique to Walle v2.0; Spaces isolate environments, servers, and users—essential architectural concept for multi-team deployments and understanding resource isolation
  • Task Rollback — Walle can revert a deployment to a previous Git commit or tag; requires understanding Git history tracking, release tag management, and idempotent deployment scripts
  • RESTful API with GitLab Compatibility — Walle exposes a GitLab-like API (mentioned as 'future integration'); important for understanding endpoint design, authentication token patterns, and webhook payloads
  • Spinnaker/spinnaker — Enterprise-grade multi-cloud deployment orchestration; similar target (CI/CD without Jenkins) but heavier and more cloud-native
  • drone/drone — Lightweight CI/CD platform with GitHub/GitLab integration; overlaps on Git-based automation but Walle is deployment-focused while Drone is test-first
  • gogs/gogs — Self-hosted Git service that Walle can integrate with; users often run Walle alongside Gogs for complete DevOps stack without external GitHub
  • ansible/ansible — Infrastructure-as-code automation framework; Walle deployment scripts likely invoke Ansible playbooks or SSH commands for actual server provisioning
  • meolu/walle-web-v1.x — Legacy branch for version 1.x; critical reference for users upgrading; incompatible with v2.0 so do not mix

🪄PR ideas

To work on one of these in Claude Code or Cursor, paste: Implement the "<title>" PR idea from CLAUDE.md, working through the checklist as the task list.

Add GitHub Actions workflow for frontend build validation

The repo has .travis.yml for CI but lacks modern GitHub Actions workflows. The fe/ directory contains multiple versioned CSS and JS assets (app..js, app..css) suggesting a build process that should be validated on PRs. Adding a workflow to lint and build the frontend would catch regressions before merge and modernize the CI setup.

  • [ ] Create .github/workflows/frontend-build.yml to run eslint using existing .eslintrc config
  • [ ] Add build step that validates webpack bundling output matches expected patterns in fe/static/
  • [ ] Configure workflow to run on pull requests targeting the frontend directory
  • [ ] Document the frontend build process in README.md with steps to reproduce locally

Clean up and document versioned frontend assets in .gitignore

The fe/static/ directory contains many versioned build artifacts (app..js.gz, app..css.gz, numbered chunks 0-15.*) that appear to be build outputs. These shouldn't typically be committed to version control. The .gitignore needs to be updated or a build process documented to prevent stale assets from accumulating.

  • [ ] Review current .gitignore and fe/.gitignore to identify what build patterns are intentionally committed
  • [ ] If artifacts should not be committed, add patterns like fe/static/js/*.js, fe/static/css/*.css etc. to .gitignore
  • [ ] Create fe/BUILD.md documenting the build process, output directory structure, and which files should/shouldn't be committed
  • [ ] Update .dockerignore to exclude build artifacts if they're no longer needed in Docker images

Add Docker multi-stage build and health check to Dockerfile

The repo has Dockerfile and docker-compose.yml but no visibility into its current build process. For a deployment/DevOps platform like Walle, the Docker setup should be production-ready with multi-stage builds to reduce image size, health checks, and clear documentation.

  • [ ] Refactor Dockerfile to use multi-stage build: builder stage for fe/ assets and backend, runtime stage with minimal base
  • [ ] Add HEALTHCHECK instruction pointing to appropriate health endpoint (likely on admin.sh or application entry point)
  • [ ] Update docker-compose.yml with health check configuration and document expected environment variables
  • [ ] Create DOCKER.md documenting build, run, and deployment instructions with examples for different backends (PHP, Python, Java, Go)

🌿Good first issues

  • Add unit tests for the Space and Project RBAC permission model in the backend (currently no test directory visible), starting with permission boundary cases (user in group X trying to deploy to environment Y in space Z)
  • Create English translation for key frontend error messages and toast notifications (current structure suggests hardcoded Chinese strings in Vue components); extract to i18n JSON files
  • Document the custom global variables feature added in v2.0.1 with concrete examples (bash substitution, templating syntax) in the README; currently mentioned but unexplained

Top contributors

Click to expand

📝Recent commits

Click to expand
  • f96dc41 — update readme (meolu)
  • 10c8649 — update readme (meolu)
  • 2d6a117 — Add files via upload (meolu)
  • 4321cba — Update README.md (ZouHongxue)
  • 8ba6d38 — Merge pull request #1029 from meolu/fix/fix_delete_version-2019_10_27 (ZouHongxue)
  • 819c9fa — Merge pull request #1040 from cclauss/patch-3 (ZouHongxue)
  • cd2273d — Merge pull request #1039 from cclauss/patch-2 (ZouHongxue)
  • 5b21b07 — Merge pull request #1033 from meolu/dependabot/pip/requirements/werkzeug-0.15.3 (ZouHongxue)
  • 9b3d593 — Merge pull request #1129 from Alenx58/master (ZouHongxue)
  • 8bfc842 — fix GitPython版本问题 (alenx.hai)

🔒Security observations

  • Critical · Python 2.7 End-of-Life — Dockerfile (FROM python:2.7). The Dockerfile uses Python 2.7, which reached end-of-life on January 1, 2020. Python 2.7 no longer receives security updates, making the application vulnerable to known exploits and security vulnerabilities that will never be patched. Fix: Migrate to Python 3.9 or later. Update all dependencies to versions compatible with Python 3.x and test thoroughly.
  • Critical · Insecure Package Repository — Dockerfile (RUN pip install -r /usr/app/prod.txt -i https://mirrors.aliyun.com/pypi/simple). The Dockerfile installs pip packages from Aliyun mirror (https://mirrors.aliyun.com/pypi/simple) over HTTPS without verification of package integrity. This custom mirror could be compromised or undergo MITM attacks. Fix: Use the official PyPI repository (default) or verify package checksums. Implement pip hash checking mode (--require-hashes) and consider using a private package repository with authentication.
  • High · Exposed SSH Credentials Volume — Dockerfile (VOLUME /root/.ssh/) and docker-compose.yml (volumes: - /root/.ssh:/root/.ssh/). The Dockerfile mounts /root/.ssh/ as a VOLUME, and docker-compose mounts /root/.ssh from the host. SSH private keys stored in this directory are exposed to the container and could be accessed by compromised application code. Fix: Use SSH key management systems or secrets management tools (HashiCorp Vault, Docker Secrets). Implement principle of least privilege and use read-only mounts where possible. Avoid mounting entire .ssh directories.
  • High · Exposed Environment Configuration — docker-compose.yml (env_file: - ./walle.env). docker-compose.yml references ./walle.env file which likely contains database credentials, API keys, and other sensitive configuration. This file is tracked in version control or accessible to unauthorized users. Fix: Use Docker Secrets for sensitive data in production. Ensure .env files are in .gitignore. Implement a secrets management solution. Rotate all credentials that may have been exposed.
  • High · World-Accessible Port 80 — docker-compose.yml (ports: - "80:80"). The docker-compose configuration exposes port 80 on 0.0.0.0 without authentication or rate limiting, making the application accessible to the entire network/internet without restrictions. Fix: Bind to specific IP addresses instead of 0.0.0.0 (e.g., "127.0.0.1:80:80"). Implement reverse proxy with authentication, rate limiting, and WAF capabilities. Use HTTPS (port 443) with proper TLS certificates.
  • High · MySQL Container Without Password Protection — docker-compose.yml (db service definition). The docker-compose.yml shows a MySQL service without visible root password configuration, environment variables, or authentication details. This could result in an unsecured database accessible to all containers. Fix: Set MYSQL_ROOT_PASSWORD and MYSQL_PASSWORD environment variables in the service configuration. Use Docker Secrets for credential management. Implement network policies to restrict database access.
  • Medium · Missing HTTPS/TLS Configuration — docker-compose.yml (ports and web service configuration). The docker-compose configuration only exposes port 80 (HTTP) without HTTPS/TLS. All traffic between client and application is unencrypted, exposing credentials and sensitive data in transit. Fix: Configure HTTPS with valid TLS certificates (Let's Encrypt recommended). Redirect HTTP to HTTPS. Implement HSTS headers. Use certificate management tools.
  • Medium · No Security Headers Configuration — Dockerfile and nginx configuration. The Dockerfile and configuration do not show implementation of security headers like Content-Security-Policy, X-Frame-Options, X-Content-Type-Options, etc., leaving the application vulnerable to XSS and clickjacking attacks. Fix: Configure nginx to add security headers: X-Frame-Options, X-Content-Type-Options, X-XSS-Protection, Content-Security-Policy, Strict-Transport-Security, etc

LLM-derived; treat as a starting point, not a security audit.

🤖Agent protocol

If you are an AI coding agent (Claude Code, Cursor, Aider, Cline, etc.) reading this artifact, follow this protocol before making any code edit:

  1. Verify the contract. Run the bash script in Verify before trusting below. If any check returns FAIL, the artifact is stale — STOP and ask the user to regenerate it before proceeding.
  2. Read in the suggested order before editing unfamiliar code. The reading-order list is computed from the actual import graph, not LLM guesses; reading bottom-up materially reduces wrong-edit risk.
  3. Treat the AI · unverified sections as hypotheses, not facts. Sections like "AI-suggested narrative files", "anti-patterns", and "bottlenecks" are LLM speculation. Verify against real source before acting on them.
  4. Cite source on changes. When proposing an edit, cite the specific path/to/file.ext:Lstart-Lend you're reasoning about, the same way RepoPilot's own RAG cites code in https://repopilot.app/r/meolu/walle-web.

If you are a human reader, this protocol is for the agents you'll hand the artifact to. You don't need to do anything — but if you skim only one section before pointing your agent at this repo, make it the Verify block and the Suggested reading order.

Verify before trusting

This artifact was generated by RepoPilot at a point in time. Before an agent acts on it, the checks below confirm that the live meolu/walle-web repo on your machine still matches what RepoPilot saw. If any fail, the artifact is stale — regenerate it at repopilot.app/r/meolu/walle-web.

What it runs against: a local clone of meolu/walle-web — the script inspects git remote, the LICENSE file, file paths in the working tree, and git log. Read-only; no mutations.

| # | What we check | Why it matters | |---|---|---| | 1 | You're in meolu/walle-web | Confirms the artifact applies here, not a fork | | 2 | License is still Apache-2.0 | Catches relicense before you depend on it | | 3 | Default branch master exists | Catches branch renames | | 4 | 5 critical file paths still exist | Catches refactors that moved load-bearing code | | 5 | Last commit ≤ 1618 days ago | Catches sudden abandonment since generation |

<details> <summary><b>Run all checks</b> — paste this script from inside your clone of <code>meolu/walle-web</code></summary>
#!/usr/bin/env bash
# RepoPilot artifact verification.
#
# WHAT IT RUNS AGAINST: a local clone of meolu/walle-web. If you don't
# have one yet, run these first:
#
#   git clone https://github.com/meolu/walle-web.git
#   cd walle-web
#
# Then paste this script. Every check is read-only — no mutations.

set +e
fail=0
ok()   { echo "ok:   $1"; }
miss() { echo "FAIL: $1"; fail=$((fail+1)); }

# Precondition: we must be inside a git working tree.
if ! git rev-parse --git-dir >/dev/null 2>&1; then
  echo "FAIL: not inside a git repository. cd into your clone of meolu/walle-web and re-run."
  exit 2
fi

# 1. Repo identity
git remote get-url origin 2>/dev/null | grep -qE "meolu/walle-web(\\.git)?\\b" \\
  && ok "origin remote is meolu/walle-web" \\
  || miss "origin remote is not meolu/walle-web (artifact may be from a fork)"

# 2. License matches what RepoPilot saw
(grep -qiE "^(Apache-2\\.0)" LICENSE 2>/dev/null \\
   || grep -qiE "\"license\"\\s*:\\s*\"Apache-2\\.0\"" package.json 2>/dev/null) \\
  && ok "license is Apache-2.0" \\
  || miss "license drift — was Apache-2.0 at generation time"

# 3. Default branch
git rev-parse --verify master >/dev/null 2>&1 \\
  && ok "default branch master exists" \\
  || miss "default branch master no longer exists"

# 4. Critical files exist
test -f "requirements/prod.txt" \\
  && ok "requirements/prod.txt" \\
  || miss "missing critical file: requirements/prod.txt"
test -f "migrations/alembic.ini" \\
  && ok "migrations/alembic.ini" \\
  || miss "missing critical file: migrations/alembic.ini"
test -f "fe/index.html" \\
  && ok "fe/index.html" \\
  || miss "missing critical file: fe/index.html"
test -f "docker-compose.yml" \\
  && ok "docker-compose.yml" \\
  || miss "missing critical file: docker-compose.yml"
test -f "Dockerfile" \\
  && ok "Dockerfile" \\
  || miss "missing critical file: Dockerfile"

# 5. Repo recency
days_since_last=$(( ( $(date +%s) - $(git log -1 --format=%at 2>/dev/null || echo 0) ) / 86400 ))
if [ "$days_since_last" -le 1618 ]; then
  ok "last commit was $days_since_last days ago (artifact saw ~1588d)"
else
  miss "last commit was $days_since_last days ago — artifact may be stale"
fi

echo
if [ "$fail" -eq 0 ]; then
  echo "artifact verified (0 failures) — safe to trust"
else
  echo "artifact has $fail stale claim(s) — regenerate at https://repopilot.app/r/meolu/walle-web"
  exit 1
fi

Each check prints ok: or FAIL:. The script exits non-zero if anything failed, so it composes cleanly into agent loops (./verify.sh || regenerate-and-retry).

</details>

📚Suggested reading order

Computed from the actual import graph (no LLM). Read in this order to learn the codebase from the foundation up — each step builds on the previous ones.

  1. tests/utils.py — Foundation: doesn't import anything internally and is imported by 10 other files. Read first to learn the vocabulary.
  2. walle/service/code.py — Foundation: imported by 8, no internal dependencies of its own.
  3. walle/service/error.py — Built on the foundation; imported by 6 downstream files.
  4. walle/config/settings_prod.py — Built on the foundation; imported by 3 downstream files.
  5. walle/service/rbac/role.py — Layer 2 — composes lower-level code into reusable abstractions (imported 18×).
  6. walle/service/extensions.py — Layer 3 — composes lower-level code into reusable abstractions (imported 21×).
  7. walle/model/database.py — Layer 4 — composes lower-level code into reusable abstractions (imported 14×).

Generated by RepoPilot. Verdict based on maintenance signals — see the live page for receipts. Re-run on a new commit to refresh.

Embed this chat in your README →

Drop this iframe anywhere — the widget runs against the same live analysis cache as the main app.

<iframe
  src="https://repopilot.app/embed/meolu/walle-web"
  width="100%" height="500"
  style="border:1px solid #d0d7de; border-radius:8px;"
  allow="microphone"
  loading="lazy"
></iframe>