Metadata-Version: 2.1
Name: wexample-wex-addon-services-platform
Version: 12.8.4
Summary: Adds wex service commands (install, setup, ready) for platforms like GitLab, Supabase, n8n, Odoo, and Ollama
Author-Email: weeger <contact@wexample.com>
License: MIT
Classifier: Programming Language :: Python :: 3
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Requires-Python: >=3.10
Requires-Dist: requests
Requires-Dist: wexample-wex-addon-app>=30.0.0
Requires-Dist: wexample-wex-core>=30.0.0
Provides-Extra: dev
Requires-Dist: pytest; extra == "dev"
Requires-Dist: pytest-cov; extra == "dev"
Description-Content-Type: text/markdown

# wex_addon_services_platform

Version: 12.8.4

This addon extends wex with `install`, `setup`, and `ready` lifecycle commands for self-hosted platform services: GitLab, GitLab Runner, Supabase, n8n, Odoo, Ollama, Nextcloud, RabbitMQ, SonarQube, Listmonk, Temporal, and OpenClaw. Each command handles the work its platform requires — writing service configuration into the app config, generating secrets, fetching upstream config files, or verifying that the container is healthy. It targets wex app developers who run one or more of these platforms as Docker services inside a wex-managed app.

## Table of Contents

- [Installation](#installation)
- [Quickstart](#quickstart)
- [Tests](#tests)
- [Architecture](#architecture)
- [Integration in the Suite](#integration-in-the-suite)
- [Dependencies](#dependencies)
- [Versioning & Compatibility Policy](#versioning--compatibility-policy)
- [License](#license)
- [About us](#about-us)
- [Known Limitations & Roadmap](#known-limitations--roadmap)
- [Status & Compatibility](#status--compatibility)
- [Useful Links](#useful-links)
- [Migration Notes](#migration-notes)

## Installation

```bash
pip install wexample-wex-addon-services-platform
```

Requires Python >=3.10.

## Quickstart

Install the package into the same Python environment as wex:

```bash
pip install wexample-wex-addon-services-platform
```

The package exposes one public symbol:

```python
from wexample_wex_addon_services_platform import ServicesPlatformAddonManager
```

Pass it to the kernel at startup alongside the other addon managers your wex instance loads:

```python
from wexample_wex_core.common.kernel import Kernel
from wexample_wex_core.addons.core.core_addon_manager import CoreAddonManager
from wexample_wex_addon_services_platform import ServicesPlatformAddonManager

kernel = Kernel(entrypoint_path=wex_dir)
kernel.setup(addons=[CoreAddonManager, ServicesPlatformAddonManager])
```

Once the kernel is running, add a platform service to a wex app from the app's root directory — ollama for this example:

```bash
wex service/install --service ollama
```

The command writes `service.ollama` into the app's `config.yml`, creates the `ollama/` host directory, and runs the service-specific install hook (src/wexample_wex_addon_services_platform/services/ollama/commands/service/install.py), which sets `service.ollama.host` and `service.ollama.port`. After that `wex app/start` brings the container up.

To verify the container is healthy after start:

```bash
wex @ollama::service/ready
```

The same `service/install --service <name>` call works for every platform the addon ships: `supabase`, `n8n`, `gitlab`, `gitlab_runner`, `odoo`, `nextcloud`, `rabbitmq`, `sonarqube`, `listmonk`, `temporal`, and `openclaw`. Platforms that require secrets — Supabase generates JWT keys and fetches upstream config files; n8n generates a basic-auth password — do all of that inside their own install hook with no extra input required.

## Tests

This project uses `pytest` for testing and `pytest-cov` for code coverage analysis.

### Installation

First, install the required testing dependencies:
```bash
.venv/bin/python -m pip install pytest pytest-cov
```

### Basic Usage

Run all tests with coverage:
```bash
.venv/bin/python -m pytest --cov --cov-report=html
```

### Common Commands
```bash
# Run tests with coverage for a specific module
.venv/bin/python -m pytest --cov=your_module

# Show which lines are not covered
.venv/bin/python -m pytest --cov=your_module --cov-report=term-missing

# Generate an HTML coverage report
.venv/bin/python -m pytest --cov=your_module --cov-report=html

# Combine terminal and HTML reports
.venv/bin/python -m pytest --cov=your_module --cov-report=term-missing --cov-report=html

# Run specific test file with coverage
.venv/bin/python -m pytest tests/test_file.py --cov=your_module --cov-report=term-missing
```

### Viewing HTML Reports

After generating an HTML report, open `htmlcov/index.html` in your browser to view detailed line-by-line coverage information.

### Coverage Threshold

To enforce a minimum coverage percentage:
```bash
.venv/bin/python -m pytest --cov=your_module --cov-fail-under=80
```

This will cause the test suite to fail if coverage drops below 80%.

## Architecture

The addon is a Python package that registers a collection of platform-service definitions into the wex kernel. It adds no runtime framework of its own — every piece it ships is either a service descriptor, a Docker Compose file, or a command function that runs when the user invokes a wex CLI verb.

### Addon manager

src/wexample_wex_addon_services_platform/services_platform_addon_manager.py is the single entry point the host kernel needs:

```python
from wexample_wex_addon_services_platform import ServicesPlatformAddonManager

kernel.setup(addons=[..., ServicesPlatformAddonManager])
```

`ServicesPlatformAddonManager` extends `AbstractAddonManager` from `wexample_wex_core` and implements `get_package_module()`, which returns the `wexample_wex_addon_services_platform` module object. The framework uses that to walk the package tree and auto-discover every `@command`-decorated function inside it.

### Service modules

Each platform lives under `src/wexample_wex_addon_services_platform/services/<name>/`. The layout inside that directory is:

| path | what it owns |
|---|---|
| `service.yml` | name, tags, optional `vars` block, optional `dependencies`, pointer to the Compose file |
| `docker/docker-compose.yml` | canonical container definition used by the wex runtime |
| `samples/env/{prod,dev}/docker/docker-compose.yml` | override fragments for concrete environments |
| `app_service.py` | `AppService` subclass; declares the host directory tree the container requires |
| `commands/<group>/<verb>.py` | one file per CLI command |

Services that ship today: `gitlab`, `gitlab_runner`, `supabase`, `n8n`, `odoo`, `ollama`, `openclaw`, `nextcloud`, `temporal`, `rabbitmq`, `sonarqube`, `listmonk`, `jenkins`.

### AppService subclass

Services whose containers require specific host directories or permission modes carry an `AppService` subclass that overrides `get_workdir_contribution()`. The method returns a nested dict describing the expected directory tree; the framework's filestate layer rectifies it — creating missing entries and enforcing `owner`/`permissions` — each time the app starts.

For example, src/wexample_wex_addon_services_platform/services/supabase/app_service.py declares `supabase/db/data` with `owner: 105:106, permissions: 700` (the uid:gid of the `supabase/postgres` image user), and src/wexample_wex_addon_services_platform/services/n8n/app_service.py declares `n8n/` with `owner: 1000:1000, permissions: 750` (the `node` user in the n8n image).

Services that have no special filesystem requirements — or whose container runs as root and manages its own tree — have no `AppService` subclass.

### Commands

Commands follow three lifecycle verbs:

**`service/install`** — runs once per service per app. It reads the app's `config.yml`, writes the service's required keys (host, port, credentials, generated secrets), then calls `app_workdir.get_runtime_config(rebuild=True)` to flush the cached config. Supabase's install (src/wexample_wex_addon_services_platform/services/supabase/commands/service/install.py) also generates a full JWT key set and fetches official config files from GitHub with `curl`. n8n's install (src/wexample_wex_addon_services_platform/services/n8n/commands/service/install.py) generates a random basic-auth password.

**`service/setup`** — idempotent filesystem preparation. It creates files or directories the container needs on first boot but cannot create itself (e.g., Supabase's `pgsodium_root.key`, GitLab Runner's `config.toml` stub). Unlike install it is safe to run repeatedly.

**`service/ready`** — health check. Each implementation derives the container name as `{app_project_name}_{service_name}` from the runtime config, then runs a `docker exec` against a service-specific health endpoint. Supabase checks `kong health` inside the `supabase_kong` container (src/wexample_wex_addon_services_platform/services/supabase/commands/service/ready.py); n8n curls `localhost:5678/healthz`; ollama curls `localhost:11434/api/tags`; gitlab calls `gitlab-healthcheck`.

Supabase also ships two database commands under `commands/db/`: src/wexample_wex_addon_services_platform/services/supabase/commands/db/migrate.py (applies pending migrations via `supabase db push` inside the `supabase_cli` helper container, hooked to run before `app::maintenance/disable`) and `db/reset` (drops schemas and replays migrations; tagged `DANGEROUS`).

GitLab Runner adds a `commands/runner/` group with `register`, `unregister`, and `list` verbs that call `docker exec … gitlab-runner` inside the running container.

### Domain tags

src/wexample_wex_addon_services_platform/const/tags.py defines `DomainTag` — a class of string constants (`domain:ai`, `domain:ci`, `domain:db`, `domain:git`, `domain:platform`, etc.) attached to every command via the `@command(tags=[...])` decorator. Tags allow the kernel and external tools to filter commands by functional area without inspecting their names.

### Call path

When the user runs `wex @supabase::service/install`:

1. The kernel resolves `supabase` to the service registered under that name, and `service/install` to the command file at src/wexample_wex_addon_services_platform/services/supabase/commands/service/install.py.
2. The framework constructs an `ExecutionContext` (carrying the IO layer and the kernel) and resolves the `service: AppService` parameter by looking up the app's active `supabase` service object.
3. The command function runs: it reads app config, writes keys, generates secrets, fetches files, and rebuilds the runtime config.
4. For `service/ready`, the same resolution path leads to a function that runs `docker exec` and returns a `BooleanResponse`.

Container names are always `{APP_PROJECT_NAME}_{service_name}`, where `APP_PROJECT_NAME` is the value the Docker Compose environment variable `${APP_PROJECT_NAME}` expands to at runtime. Commands that need to reach a container resolve this from `service.app_workdir.get_runtime_config().search("app.project_name").get_str()`.

## Integration in the Suite

This package is part of the Wexample Suite — a collection of high-quality, modular tools designed to work seamlessly together across multiple languages and environments.

### Related Packages

The suite includes packages for configuration management, file handling, prompts, and more. Each package can be used independently or as part of the integrated suite.

Visit the [Wexample Suite documentation](https://docs.wexample.com) for the complete package ecosystem.

## Dependencies

- requests: 
- wexample-wex-addon-app: >=30.0.0
- wexample-wex-core: >=30.0.0

## Versioning & Compatibility Policy

Wexample packages follow **Semantic Versioning** (SemVer):

- **MAJOR**: Breaking changes
- **MINOR**: New features, backward compatible
- **PATCH**: Bug fixes, backward compatible

We maintain backward compatibility within major versions and provide clear migration guides for breaking changes.

## License

This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.

Free to use in both personal and commercial projects.

## About us

[Wexample](https://wexample.com) stands as a cornerstone of the digital ecosystem — a collective of seasoned engineers, researchers, and creators driven by a relentless pursuit of technological excellence. More than a media platform, it has grown into a vibrant community where innovation meets craftsmanship, and where every line of code reflects a commitment to clarity, durability, and shared intelligence.

This packages suite embodies this spirit. Trusted by professionals and enthusiasts alike, it delivers a consistent, high-quality foundation for modern development — open, elegant, and battle-tested. Its reputation is built on years of collaboration, refinement, and rigorous attention to detail, making it a natural choice for those who demand both robustness and beauty in their tools.

Wexample cultivates a culture of mastery. Each package, each contribution carries the mark of a community that values precision, ethics, and innovation — a community proud to shape the future of digital craftsmanship.

## Known Limitations & Roadmap

Current limitations and planned features are tracked in the GitHub issues.

See the [project roadmap](https://github.com/wexample/python-wex_addon_services_platform/issues) for upcoming features and improvements.

## Status & Compatibility

**Maturity**: Production-ready

**Python Support**: >=3.10

**OS Support**: Linux, macOS, Windows

**Status**: Actively maintained

## Useful Links

- **Homepage**: https://github.com/wexample/python-wex-addon-services-platform
- **Documentation**: [docs.wexample.com](https://docs.wexample.com)
- **Issue Tracker**: https://github.com/wexample/python-wex-addon-services-platform/issues
- **Discussions**: https://github.com/wexample/python-wex-addon-services-platform/discussions
- **PyPI**: [pypi.org/project/wexample-wex-addon-services-platform](https://pypi.org/project/wexample-wex-addon-services-platform/)

## Migration Notes

When upgrading between major versions, refer to the migration guides in the documentation.

Breaking changes are clearly documented with upgrade paths and examples.
