Multi-service FastAPI application that generates Android WebView app bundles (APK/AAB) for user-supplied URLs. Includes authentication, role-based authorization, keystore approvals, and a background builder that auto-bootstraps the Android toolchain to produce signed Gradle builds.
- User authentication & roles: JWT-based login/registration with
adminanduserroles. - App projects: Create, list, view, update, and upload icons for WebView-based Android apps (package name, URL, SDK targets, versioning).
- Keystore lifecycle: Per-project keystore generation with admin-gated download approvals and secure file serving when allowed.
- Build jobs: Trigger build jobs per app, monitor status/logs, and download signed APK/AAB artifacts after success.
- Admin workflows: Approve or reject keystore download requests via dedicated admin endpoints and pages.
- Web UI: Basic Jinja2 templates for login, registration, dashboard, app detail, and admin keystore request review.
- webapp (FastAPI): Serves APIs and HTML pages, manages JWT auth, CRUD for app projects/keystores/builds. Uses SQLAlchemy ORM and Alembic migrations against MySQL. Static assets and templates live under
webapp/app/staticandwebapp/app/templates. - builder (worker): Polling worker that processes pending
BuildJobrecords, scaffolds Android projects, invokes Gradle to build signed APK/AAB outputs, and updates job logs/statuses. - database: MySQL 8 instance shared by both services.
- Shared volumes:
/data/keystores,/data/artifacts, and/data/iconsmounted to persist generated keystores, build outputs, and uploaded icons.
.
├── docker-compose.yml
├── alembic/ # Alembic migration environment and versions
├── webapp/ # FastAPI service (APIs, templates, static assets)
│ ├── app/
│ │ ├── main.py # App factory & router registration
│ │ ├── models.py # SQLAlchemy models for users, projects, keystores, builds, requests
│ │ ├── auth.py # JWT utilities and password hashing helpers
│ │ ├── routers/ # Auth, app, keystore, admin, and build routes
│ │ ├── templates/ # Jinja2 templates (login, register, dashboard, app detail, admin)
│ │ └── static/ # CSS and other assets
│ └── requirements.txt
└── builder/ # Background build worker
├── main.py # Polling loop to process pending BuildJobs
└── requirements.txt
- Ensure Docker and Docker Compose are installed.
- Build and start the stack:
docker-compose up --build
- The FastAPI app is available on http://localhost:8000. MySQL is exposed on port 3306 for debugging.
- Data volumes are stored under
./data/keystores,./data/artifacts, and./data/iconson the host.
Environment variables used in docker-compose.yml (override as needed):
DATABASE_URL: MySQL connection string for SQLAlchemy.JWT_SECRET,JWT_ALGORITHM: JWT signing configuration for the webapp.KEYSTORE_DIR,ARTIFACT_DIR,ICON_DIR: Mounted storage paths for keystores, build artifacts, and uploaded icons.ANDROID_CMDLINE_URL,ANDROID_PACKAGES: Builder toolchain bootstrap controls; downloads occur inside each build's working directory.GRADLE_VERSION: Version for the portable Gradle distribution the builder downloads inside each build's working directory.BUILD_WORK_DIR: Root directory where per-build working directories (including toolchain caches) are created and persisted.
Alembic is configured at the repository root. The webapp container runs with SQLAlchemy models creating tables on startup; you can run migrations locally with:
alembic upgrade headEnsure DATABASE_URL is set in the environment when running Alembic commands.
- The builder bootstraps the Android command-line tools and required SDK packages inside each build's working directory (downloading commandline-tools zip and running
sdkmanagerforplatform-tools,platforms;android-34, andbuild-tools;34.0.0). - A portable Gradle distribution is downloaded alongside each build in the working directory before running
gradle wrapperand subsequent./gradlew assembleRelease bundleRelease; the installation persists within that build folder. - Keystore generation is stubbed and stores passwords in plain text pending integration with secure storage/encryption.