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.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file sinpapel-0.8.2.tar.gz.
File metadata
- Download URL: sinpapel-0.8.2.tar.gz
- Upload date:
- Size: 81.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/6.2.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
9d67986f71e42612db5289fa4de7bcc87ca708514e875ae33d8c834ea82bce98
|
|
| MD5 |
19323d44ed404e53a209464bec954974
|
|
| BLAKE2b-256 |
8cfab59f21d80f7c6585698beac153fc908288837615bf1da45550f74a1aeb5b
|
File details
Details for the file sinpapel-0.8.2-py3-none-any.whl.
File metadata
- Download URL: sinpapel-0.8.2-py3-none-any.whl
- Upload date:
- Size: 93.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/6.2.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
38d6d12053ca1de977c4292ada2aad545c5f344fcba9a330db2c140f50d2d5be
|
|
| MD5 |
b69212c43e424c9e693771a567c4bf41
|
|
| BLAKE2b-256 |
53f6aa66df013d6570a9fe77ea2ee129c1cf6172faaa886b190ae8aea6099879
|