sinpapel
v0.8.2 — Versioned state machines, immutable audit trail, and pluggable electronic signatures for Django.
Why sinpapel?
Building paperless processes in Django usually means stitching together a state-machine library, an audit framework, a signing layer, and a forms toolkit. sinpapel ships them as one coherent package: declarative versioned workflows, immutable history, pluggable e-signature backends, schema-based metadata capture, transition predicates, SLA timers, and custom domain signals — designed to be adopted incrementally in any Django 5+ project.
Features
- Workflow Engine — versioned state machines via
VersionFlujo+ConfiguracionTransicion, with permission groups, document-requirement gates, and aWorkflowEngineservice. Convenience methods (available_transitions,can_transition_to,transition,preview_transition) are injected onto every@workflow_enabledmodel. - Document Requirements — both a coarse per-state flag (
Estado.expediente_obligatorio) and fine-grained per-type rules (RequisitoEstadoDocumento: document type + minimum completion percentage) are enforced on every transition; system-generated documents (auto_carga=True) do not block. - Transition Predicates — Python paths, restricted JSON Logic, and Django-ORM-backed predicates, ordered per transition.
- Structured Metadata Capture —
MetadatosCapturablesmixin with schema-declaredCampoMetadatofields, validated at save. - Dynamic Forms & Serializers —
MetaFormFactorybuilds Django Forms from metadata schema; DRF Serializer mode also supported. - Pluggable Signing Backends —
SignatureBackendstrategy interface plus reference backends:FakeBackend(tests),ManualBackend(default), andFielBackend(FIEL/SAT, RSA-SHA256 + X.509). - Immutable Audit Trail —
Trazablemixin,SeguimientoWorkflowhistory,RegistroFirma, plusdjango-simple-historyintegration. - SLA Timers & Preview Transitions —
SLAConfiguracionmodels per-state time limits (measured as time-in-state since the last transition) andSLAEngineexecutes the configured actions on breach: notify (viaSINPAPEL_SLA_NOTIFY_HANDLER), escalate/reject (automatic transition by theSINPAPEL_SLA_SYSTEM_USER), or flag (persisted). Wire the cron with thesinpapel_verificar_slascommand (--dry-runsupported).preview_transition()returns an impact report (blocking reasons, missing documents, failed predicates, whether signature is required) without mutating state. SINPAPEL_ENFORCE_ESTADO_ACTIVO = False # reject transitions into Estado.activo=False - Custom Domain Signals —
predicate_failed,sla_breached,sla_action_executed,transition_preview_requestedfor observability and side-effect wiring.
Installation
pip install sinpapel
Requires Python 3.10+ and Django 5.0+.
Add to INSTALLED_APPS:
INSTALLED_APPS = [
# ...
"simple_history",
"sinpapel",
"my_app", # your app that defines workflow-enabled models
]
Run migrations:
python manage.py migrate sinpapel
Quick Start
Declare a workflow-enabled model:
from decimal import Decimal
from django.db import models
from sinpapel import workflow_enabled
from sinpapel.mixins import CampoMetadato, MetadatosCapturables, Trazable
@workflow_enabled(state_field="estado", workflow_key="solicitud")
class Solicitud(MetadatosCapturables, Trazable):
folio = models.CharField(max_length=20, unique=True)
estado = models.ForeignKey("sinpapel.Estado", on_delete=models.PROTECT)
SCHEMA_METADATOS = [
CampoMetadato("monto", Decimal, requerido=True),
CampoMetadato("rfc", str, requerido=True),
]
def resolve_workflow_version(self):
from sinpapel.models import VersionFlujo
return VersionFlujo.objects.get(nombre="solicitudes", activo=True)
Drive a state transition through the methods injected on the instance:
# Preview before committing (no mutation, returns an impact report)
preview = solicitud.preview_transition("APROBADA", user=request.user)
if not preview["permitido"]:
# razones_bloqueo aggregates permission, predicate and document failures;
# documentos_faltantes lists missing per-type requirements, e.g.
# {"tipo": "requisito_documento", "tipo_documento": "INE",
# "porcentaje_requerido": 100, "porcentaje_actual": 0, "mensaje": "..."}
raise ValueError(preview["razones_bloqueo"][0]["mensaje"])
# Execute the transition (validates, creates audit row, fires signals).
# Raises PermissionError if validation (groups, predicates, documents) fails.
solicitud.transition("APROBADA", user=request.user, comentarios="Cumple requisitos")
The same logic is also reachable through the WorkflowEngine service directly
(WorkflowEngine().preview_transition(solicitud, "APROBADA", user) /
.cambiar_estado(...)) when you need it outside a model instance.
Subscribe to a custom signal:
from django.dispatch import receiver
from sinpapel.signals import sla_breached
@receiver(sla_breached)
def on_sla_breach(sender, instance, sla, **kwargs):
notify_team(instance, sla)
Full end-to-end examples, schema seeding, predicate cookbook, signing backend setup, and admin integration live in docs/usage/en.md.
What's Inside
| Subsystem | Module | Docs |
|---|---|---|
| Workflow Engine | sinpapel.services.workflow_engine |
USAGE §State Transitions |
| Predicates | sinpapel.services.predicate_engine |
USAGE §Transition Predicates |
| Metadata | sinpapel.mixins |
USAGE §Metadata |
| Forms Factory | sinpapel.forms |
USAGE §Forms |
| Signing | sinpapel.signing |
USAGE §Signing |
| Audit Trail | sinpapel.models + sinpapel.mixins.Trazable |
USAGE §Audit |
| SLA Engine | sinpapel.services.sla_engine |
USAGE §SLA |
| Custom Signals | sinpapel.signals |
USAGE §Signals |
| Schema Export/Import | sinpapel.schemas + management commands |
USAGE §Schema |
Configuration
Optional Django settings:
# settings.py
# Dotted path to the signature backend (default: ManualBackend).
SINPAPEL_SIGNATURE_BACKEND = "sinpapel.signing.backends.fiel.FielBackend"
SINPAPEL_ALLOW_SERVER_SIGNING = False # gate FIEL server-side signing (legal review)
SINPAPEL_EMIT_PREVIEW_EVENTS = False # set True to fire transition_preview_requested signal
# Trusted SAT CA bundle for FIEL chain-of-trust (PEM path or list of paths).
# Without it, FIEL signatures are stored as VALIDA_SIN_CADENA.
SINPAPEL_FIEL_TRUSTED_CA_BUNDLE = "/etc/ssl/sat/acs.pem"
SINPAPEL_SLA_SYSTEM_USER = "sla-bot" # user for automatic SLA transitions
SINPAPEL_SLA_NOTIFY_HANDLER = "myapp.notify.sla_handler" # SLA notification hook
See USAGE §Settings for the full reference.
Compatibility
| Python | Django |
|---|---|
| 3.10, 3.11, 3.12, 3.13 | 5.0 – 6.0 (CI: 5.0, 5.2 LTS, 6.0) |
CI runs the test suite across the full matrix.
Documentation
- Usage Guide — full reference (EN)
- Guía de Uso — full reference (ES)
- Changelog
- Contributing
- Code of Conduct
Versioning & Stability
sinpapel follows Semantic Versioning. The current release is v0.8.0 (Beta). The stable public surface is defined explicitly in docs/development/api-publica.md. Pre-1.0 contract: minor releases may include breaking changes (each one documented in the upgrade guide and the changelog); patch releases are fixes only. Pin the minor (sinpapel~=0.8.0) until 1.0.0.
Contributing
Pull requests are welcome. Please read docs/development/contributing.md for development setup, commit conventions, and the Developer Certificate of Origin (DCO) sign-off requirement.
License
Copyright (C) 2024-2026 Julio Adrián.
sinpapel is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
sinpapel is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
Metadata
Release files for sinpapel 0.8.4
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| sinpapel-0.8.4.tar.gz | 81.4 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| sinpapel-0.8.4-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 175.7 kB
Release files / sinpapel-0.8.4.tar.gz
| Download URL | sinpapel-0.8.4.tar.gz |
|---|---|
| Size | 81.4 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
581f2d8e91d8691fd1ca1735ff90b655a80cf35139d5ee54d1929465c818fa2b
|
|
BLAKE2b-256 checksum How to use checksums |
0511532d61da1a5cc00553644005d60a50a5b5b8358fbbbb65662ea77f57b456
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.13
|
Release files / sinpapel-0.8.4-py3-none-any.whl
| Download URL | sinpapel-0.8.4-py3-none-any.whl |
|---|---|
| Size | 94.2 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
75484e04bbb255e8497ef06757812cafb9cc227583ff40316f1d797aa43ce54d
|
|
BLAKE2b-256 checksum How to use checksums |
c248a4d2b09eb64ba693bde057b045d60b61a61336b3ae61460f081eaa5cd94a
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.13
|