Metadata-Version: 2.1
Name: wexample-wex-addon-services-collab
Version: 11.8.4
Summary: Extends wex with install and configuration commands for self-hosted collaboration services — Nextcloud, OnlyOffice, Synapse, and Rocket.Chat
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: 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_collab

Version: 11.8.4

This addon extends wex with install and configuration commands for self-hosted collaboration services — Nextcloud, OnlyOffice, Synapse, and Rocket.Chat. Each command writes service defaults (credentials, host, port) into the app config and rebuilds the runtime, giving wex-managed apps a consistent, command-driven setup path for their collaboration stack.

## 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-collab
```

Requires Python >=3.10.

## Quickstart

Install the package:

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

Register `ServicesCollabAddonManager` when you set up your wex kernel:

```python
from pathlib import Path

from wexample_wex_core.addons.core.core_addon_manager import CoreAddonManager
from wexample_wex_core.common.kernel import Kernel
from wexample_wex_addon_services_collab import ServicesCollabAddonManager

kernel = Kernel(entrypoint_path=Path(".wex"))
kernel.setup(addons=[CoreAddonManager, ServicesCollabAddonManager])
```

Once the kernel is set up, three service commands are available in any wex app that declares a matching service:

| Command | Effect |
|---|---|
| `@nextcloud::service/install` | Writes `admin.user` and a random `admin.password` into the app config and rebuilds the runtime |
| `@synapse::service/install` | Writes `host` and `port` (8008) into the app config and rebuilds the runtime |
| `@synapse::service/ready` | Curls `http://localhost:8008/health` inside the Synapse container and returns a boolean |

These commands are of type `service`: they resolve against the active app's services and are invoked inside a wex-managed app, not standalone.

## 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 single Python package (`wexample_wex_addon_services_collab`) that plugs into a wex kernel. It owns three things: an addon manager that tells the framework where to look, a constants module that names its domain tags, and a set of service sub-packages — one per collaboration service — each containing commands and, where needed, a service class.

### Entry point

src/wexample_wex_addon_services_collab/services_collab_addon_manager.py is the only object the outside world imports. `ServicesCollabAddonManager` extends `AbstractAddonManager` from `wexample_wex_core` and implements one method:

```python
@classmethod
def get_package_module(cls) -> Any:
    import wexample_wex_addon_services_collab
    return wexample_wex_addon_services_collab
```

The framework calls `get_package_module()` during kernel setup and scans the returned package for every function decorated with `@command`. No explicit registration is needed for individual commands.

### Domain tags

src/wexample_wex_addon_services_collab/const/tags.py declares `DomainTag.COLLAB` (`"domain:collab"`) and `DomainTag.SERVICE` (`"domain:service"`). Every command in the addon tags itself with both, alongside the standard `wexample_cli` tags (`EffectTag`, `AudienceTag`, `ScopeTag`) that the framework uses for filtering and safety checks.

### Service sub-packages

Under `src/wexample_wex_addon_services_collab/services/` there is one sub-package per supported service. Nextcloud and Synapse have commands; OnlyOffice and Rocket.Chat have namespace packages only (empty `__init__.py`).

#### Nextcloud

src/wexample_wex_addon_services_collab/services/nextcloud/commands/service/install.py — `nextcloud__service__install` writes `admin.user` (fixed as `"admin"`) and a random `admin.password` into the app config, then rebuilds the runtime:

```python
config.set_by_path(f"service.{service_name}.admin.user", "admin")
config.set_by_path(f"service.{service_name}.admin.password", string_random_token())
config_file.write_config(config)
service.app_workdir.get_runtime_config(rebuild=True)
```

#### Synapse

src/wexample_wex_addon_services_collab/services/synapse/commands/service/install.py — `synapse__service__install` derives the Docker hostname from the app name and writes `host` and `port` (8008) into the app config:

```python
config.set_by_path(f"{svc_prefix}.host", f"{app_name}_{svc_name}")
config.set_by_path(f"{svc_prefix}.port", 8008)
```

src/wexample_wex_addon_services_collab/services/synapse/commands/service/ready.py — `synapse__service__ready` checks liveness by running `curl -sf http://localhost:8008/health` inside the service's Docker container and returns a `BooleanResponse`:

```python
result = subprocess.run(
    ["docker", "exec", container_name, "curl", "-sf", "http://localhost:8008/health"],
    stdout=subprocess.DEVNULL,
    stderr=subprocess.DEVNULL,
)
return BooleanResponse(kernel=context.kernel, content=result.returncode == 0)
```

src/wexample_wex_addon_services_collab/services/synapse/app_service.py is not a command — it is a service class that overrides `get_workdir_contribution()` to declare the `synapse/data/` directory with owner `991:991` and permissions `755`. The framework calls this method when building the app workdir tree, so the correct ownership is applied before the container starts.

### Call path through a command

1. The caller invokes a service command (e.g., `@nextcloud::service/install`).
2. The framework resolves the command function discovered from the package and injects `ExecutionContext` and the matching `AppService`.
3. The command reads the current app config via `service.app_workdir.get_config_file().read_config()`.
4. It mutates the config with `config.set_by_path(...)` and writes it back.
5. It calls `app_workdir.get_runtime_config(rebuild=True)` so the live runtime reflects the change.
6. It logs a confirmation through `context.io.log(...)`.

The `ready` command skips config mutation and instead shells out to Docker, returning a typed boolean rather than logging.

## 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

- 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_collab/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-collab
- **Documentation**: [docs.wexample.com](https://docs.wexample.com)
- **Issue Tracker**: https://github.com/wexample/python-wex-addon-services-collab/issues
- **Discussions**: https://github.com/wexample/python-wex-addon-services-collab/discussions
- **PyPI**: [pypi.org/project/wexample-wex-addon-services-collab](https://pypi.org/project/wexample-wex-addon-services-collab/)

## 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.
