A Dockerized service providing a REST API interface to leverage StrictDoc's functionality for documentation and requirements management.
Built on Red Hat Universal Base Image (UBI) for enterprise-grade security, stability, and OpenShift compatibility.
- Simple REST API to access StrictDoc (version pinned in
pyproject.toml) - Red Hat UBI 9 base image - Enterprise-grade security and OpenShift compatibility
- Fast builds - Pre-compiled wheels, millisecond dependency installation with uv
- Prometheus metrics - Built-in monitoring with dedicated metrics endpoint (port 9183)
- Compatible with amd64 and arm64 architectures
- Easily deployable via Docker or Docker Compose
- Configurable port and logging level
- Support for multiple export formats:
- HTML (default) - Web-based documentation
- JSON - Structured data for programmatic access
- Excel - Native Microsoft Excel format
- ReqIF/ReqIFZ - Requirements Interchange Format (XML/compressed)
- RST - ReStructured Text for documentation
- SDOC - StrictDoc native format
- PDF - Not available (requires Chromium/ChromeDriver, which significantly increases image size)
To install the latest version of the StrictDoc Service, run the following command:
docker pull ghcr.io/schweizerischebundesbahnen/strictdoc-service:latestTo start the StrictDoc service container, execute:
docker run --detach \
--init \
--publish 9083:9083 \
--publish 9183:9183 \
--name strictdoc-service \
ghcr.io/schweizerischebundesbahnen/strictdoc-service:latestThe service will be accessible on port 9083, with Prometheus metrics on port 9183.
A production-ready docker-compose.yml file is provided with the repository. To use it:
# Start the service
docker-compose up -d
# Check logs
docker-compose logs -f
# Stop the service
docker-compose downYou can customize the environment variables by creating a .env file:
# .env example
APP_VERSION=1.0.0
LOG_LEVEL=DEBUGTo extend or customize the service, use it as a base image in the Dockerfile:
FROM ghcr.io/schweizerischebundesbahnen/strictdoc-service:latestThis project uses uv for fast and modern Python dependency management.
Install uv:
curl -LsSf https://astral.sh/uv/install.sh | sh-
Clone the repository:
git clone https://github.com/SchweizerischeBundesbahnen/strictdoc-service.git cd strictdoc-service -
Install dependencies:
uv sync --all-groups
-
Run the service locally:
uv run python -m app.strictdoc_service_application --port 9083
# Format and lint code
uv run ruff format
uv run ruff check
# Type checking
uv run mypy .
# Run all linting
uv run tox -e lint# Run all tests with coverage
uv run pytest --cov=app tests/ --cov-report=term-missing
# Run tests with tox
uv run toxSee tests/README.md for detailed test organization and instructions.
IMPORTANT: Always use Docker BuildKit for optimal build performance:
# Enable BuildKit for cache mount support (REQUIRED)
DOCKER_BUILDKIT=1 docker build \
--build-arg APP_IMAGE_VERSION=0.0.0 \
--tag strictdoc-service:0.0.0 .Replace 0.0.0 with the desired version number.
This service uses Red Hat Universal Base Image (UBI) 9 Minimal for optimal performance and compatibility:
- Image size: ~604MB (optimized for enterprise deployment)
- Python installation: Python 3.13 via uv (installed to
/opt/pythonfor non-root access) - Dependency management: Ultra-fast installation with pre-compiled wheels (milliseconds vs minutes)
- Security: Regular security updates from Red Hat, enterprise-grade support
- Compatibility: OpenShift ready, glibc-based for maximum package compatibility
Why not Alpine? While Alpine Linux produces smaller images, it uses musl libc which causes compilation issues with some Python packages (tree-sitter) on arm64 architecture. UBI provides the best balance of size, speed, and compatibility.
To start the Docker container with your custom-built image:
docker run --detach \
--init \
--publish 9083:9083 \
--publish 9183:9183 \
--name strictdoc-service \
strictdoc-service:0.0.0To stop the running container, execute:
docker container stop strictdoc-serviceStrictDoc Service provides the following endpoints:
GET /version
HTTP code Content-Type Response 200application/json{ "python": "3.13.7", "strictdoc": "0.14.0", "strictdocService": "0.0.0", "timestamp": "2025-10-08T12:23:09Z" }
curl -X GET -H "Content-Type: application/json" http://localhost:9083/version
The service exposes Prometheus-compatible metrics for comprehensive monitoring and observability through Grafana dashboards.
Metrics Endpoint: /metrics on port 9183 (dedicated metrics port)
Security: The metrics endpoint is served on a separate port (9183) from the main API (9083). This allows network-level isolation using security groups or firewall rules to restrict metrics access to your Prometheus server only.
Available Metrics:
Export Metrics:
strictdoc_exports_total{format}- Total successful exports (labeled by format: html, json, excel, etc.)strictdoc_export_failures_total{format}- Total failed exports (labeled by format)strictdoc_export_error_rate_percent- Export error rate as percentage
Performance Metrics:
strictdoc_export_duration_seconds{format}- Export duration histogram (labeled by format)avg_strictdoc_export_time_seconds- Average export time in secondsstrictdoc_request_body_bytes- Input document size histogramstrictdoc_response_body_bytes- Output document size histogram
Service Metrics:
uptime_seconds- Service uptimeactive_exports- Current number of active export operationsstrictdoc_info{version, service_version}- Version information
HTTP Metrics (via prometheus-fastapi-instrumentator):
http_request_duration_seconds- HTTP request duration histogramhttp_requests_total- Total HTTP requestshttp_requests_inprogress- Current in-progress requests
Prometheus Configuration Example:
scrape_configs:
- job_name: 'strictdoc-service'
static_configs:
- targets: ['strictdoc-service:9183'] # Metrics on dedicated port
metrics_path: '/metrics'
scrape_interval: 15s
scrape_timeout: 10sGrafana Dashboard Queries:
# Export rate by format (requests per second)
sum(rate(strictdoc_exports_total[5m])) by (format)
# Error rate percentage
strictdoc_export_error_rate_percent
# 95th percentile export duration
histogram_quantile(0.95, rate(strictdoc_export_duration_seconds_bucket[5m]))
# Average export time
avg_strictdoc_export_time_seconds
Docker Compose Example with Prometheus & Grafana:
services:
strictdoc-service:
image: ghcr.io/schweizerischebundesbahnen/strictdoc-service:latest
init: true
ports:
- "9083:9083" # Main API
- "9183:9183" # Metrics endpoint
prometheus:
image: prom/prometheus:latest
ports:
- "9090:9090"
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml
- prometheus-data:/prometheus
grafana:
image: grafana/grafana:latest
ports:
- "3000:3000"
volumes:
- grafana-data:/var/lib/grafana
environment:
- GF_SECURITY_ADMIN_PASSWORD=admin
volumes:
prometheus-data:
grafana-data:Quick Start with Monitoring Stack:
A complete monitoring setup is provided in the monitoring/ directory:
# Start StrictDoc service with Prometheus and Grafana
./monitoring/start-monitoring.sh
# Generate test load
./monitoring/generate-load.sh 100 20
# Stop monitoring stack
./monitoring/stop-monitoring.shAccess URLs:
| Service | URL | Credentials |
|---|---|---|
| StrictDoc Service | http://localhost:9083 | - |
| API Docs | http://localhost:9083/docs | - |
| Raw Metrics | http://localhost:9183/metrics | - |
| Prometheus | http://localhost:9090 | - |
| Grafana Dashboard | http://localhost:3000/d/strictdoc-service | admin/admin |
See monitoring/README.md for detailed setup instructions.
POST /export
Content-Type: application/json
Field Type Data type Description content required object (dict) Map of .sdocfilename(s) to their text content, e.g.{"doc.sdoc": "[DOCUMENT]\n..."}. Supports multiple files.format required string Export format: html,html2pdf,rst,json,excel,reqif-sdoc,reqifz-sdoc,sdoc,doxygen,spdxfile_name required string Base name for the output file (without extension)
Note on PDF Export: The html2pdf format is currently not available in this service. PDF generation requires Chromium/ChromeDriver, which would increase the Docker image size by ~300MB+. If you need PDF output, consider:
- Using the
htmlformat and converting to PDF externally - Using a separate PDF conversion service
- Building a custom image with Chromium installed
Note on HTML Export: The html format returns a ZIP archive containing the full HTML site.
Note on Multi-Document Export: When content contains more than one document, the response is always a ZIP archive regardless of the requested format.
HTTP code Content-Type Response 200Varies by export format Exported document (single file, or ZIP for HTML/multi-doc) 400application/jsonInvalid request (bad format, missing [DOCUMENT], etc.)422application/jsonValidation error 500application/jsonInternal server error
Single document export to ReqIF:
curl -X POST \ -H "Content-Type: application/json" \ --data '{"content": {"requirements.sdoc": "[DOCUMENT]\nTITLE: My Requirements\n"}, "format": "reqif-sdoc", "file_name": "requirements"}' \ "http://localhost:9083/export" \ --output requirements.reqif
Multiple documents export (returns ZIP):
curl -X POST \ -H "Content-Type: application/json" \ --data '{"content": {"doc1.sdoc": "[DOCUMENT]\nTITLE: Doc 1\n", "doc2.sdoc": "[DOCUMENT]\nTITLE: Doc 2\n"}, "format": "json", "file_name": "export"}' \ "http://localhost:9083/export" \ --output export.zip