Metadata-Version: 2.4
Name: stapel-docs
Version: 0.2.4
Summary: Documents: storage, revisions and per-type editors for the Stapel framework
License: MIT
Project-URL: Homepage, https://github.com/usestapel/stapel-docs
Project-URL: Repository, https://github.com/usestapel/stapel-docs
Project-URL: Documentation, https://github.com/usestapel/stapel-docs#readme
Project-URL: Changelog, https://github.com/usestapel/stapel-docs/blob/main/CHANGELOG.md
Project-URL: Issues, https://github.com/usestapel/stapel-docs/issues
Keywords: django,stapel,docs
Classifier: Development Status :: 4 - Beta
Classifier: Framework :: Django
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Typing :: Typed
Requires-Python: >=3.11
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: stapel-core<1.0,>=0.27.0
Provides-Extra: s3
Requires-Dist: boto3>=1.26; extra == "s3"
Provides-Extra: pdf
Requires-Dist: fpdf2>=2.8; extra == "pdf"
Provides-Extra: all
Requires-Dist: boto3>=1.26; extra == "all"
Requires-Dist: fpdf2>=2.8; extra == "all"
Dynamic: license-file

<!-- Generated by stapel-readme from docs/readme.md + docs/*.json. Do not edit this file; edit docs/readme.md and re-run `make readme`. -->

# stapel-docs

[![CI](https://img.shields.io/github/actions/workflow/status/usestapel/stapel-docs/ci.yml?branch=main&logo=github&label=CI)](https://github.com/usestapel/stapel-docs/actions/workflows/ci.yml?query=branch%3Amain)
[![coverage](https://img.shields.io/codecov/c/github/usestapel/stapel-docs?branch=main&logo=codecov&label=coverage)](https://app.codecov.io/gh/usestapel/stapel-docs)
[![pypi](https://img.shields.io/pypi/v/stapel-docs?logo=pypi&logoColor=white&label=pypi)](https://pypi.org/project/stapel-docs/)
[![downloads](https://static.pepy.tech/badge/stapel-docs/month)](https://pepy.tech/project/stapel-docs)
[![python](https://img.shields.io/pypi/pyversions/stapel-docs?logo=python&logoColor=white)](https://pypi.org/project/stapel-docs/)
[![license](https://img.shields.io/github/license/usestapel/stapel-docs)](https://github.com/usestapel/stapel-docs/blob/main/LICENSE)
[![llms.txt](https://img.shields.io/badge/llms.txt-blue)](https://github.com/usestapel/stapel-docs/blob/main/docs/llms.txt)

> Google-Drive-style workspace documents: a folder tree, one-entity-per-type documents over an open type registry, content-addressed snapshot storage with an update journal and revision history, optimistic-lock editing (v1), trash with irreversible purge, a swappable object-storage seam, comm ingest (docs.create_document) and registry-driven export (PDF built in).

Part of the [Stapel framework](https://github.com/usestapel) — composable Django apps that deploy as a monolith or as microservices without changing module code.

## Install

```bash
pip install stapel-docs
```

## At a glance

| Fact | Value |
|---|---|
| Version | `0.2.4` |
| Python | `>=3.11` (3.11, 3.12, 3.13) |
| HTTP operations | 27 |
| Config axes | 1 |
| Usage surface | 54 |
| Extension points | 7 |
| Error codes | 74 |
| Fleet dependencies | [`stapel-auth`](https://github.com/usestapel/stapel-auth) (optional) · [`stapel-core`](https://github.com/usestapel/stapel-core) · [`stapel-workspaces`](https://github.com/usestapel/stapel-workspaces) (optional) |

## Documentation

[OpenAPI](https://github.com/usestapel/stapel-docs/blob/main/docs/schema.json) · [capabilities.json](https://github.com/usestapel/stapel-docs/blob/main/docs/capabilities.json) · [llms.txt (for agents)](https://github.com/usestapel/stapel-docs/blob/main/docs/llms.txt)

## What this is

Google-Drive-style **workspace documents**: a folder tree, documents that are
each ONE entity with a `type` from an open registry (`txt` / `md` / `csv` /
opaque `file` built in), a journal + revision versioning substrate, trash with
irreversible purge, and registry-driven export (PDF built in).

The versioning substrate is decided for both collaboration disciplines:
**snapshot** types save whole states under optimistic lock (`If-Match` carries
the client's `head_seq` — v1's editing model), **crdt** types accumulate an
append-only update journal between snapshots with chat-pattern replay/resync.
Which discipline applies is a property of the *type*, not the request.

Object storage is content-addressed and goes through a swappable seam
(`STORAGE`); the library is **body-blind** — the storage substrate never
parses a document body, only a type's own `text_extractor` may.

## Quick start

The base install rides Django's `default_storage`; add extras for the
boto3 S3/MinIO backend and the PDF exporter:

```bash
pip install "stapel-docs[s3,pdf]"
```

```python
INSTALLED_APPS = [
    # ...
    "stapel_docs",
]

# urls.py
path("docs/", include("stapel_docs.urls"))   # -> /docs/api/v1/...
```

Authorization asks the `workspaces.check_capability` comm Function
(fail-closed, deny-by-default) — install stapel-workspaces or provide that
Function for any HTTP request to be allowed.

## An open type registry, not an enum

```python
STAPEL_DOCS = {
    # Add or replace document types ({slug: dotted-path | None removes}):
    "DOC_TYPES": {"sheet": "myproject.docs.SHEET_SPEC"},
    # Add export formats over the built-in pdf:
    "EXPORTERS": {"docx": "myproject.docs.DocxExporter"},
    # Event-driven ingest without writing a subscriber:
    "INGEST": {"meeting.summarized": "myproject.docs.map_summary"},
    # Swap the object store:
    "STORAGE": "stapel_docs.storage.S3Backend",
}
```

A type whose spec vanishes from the registry degrades to `file` behavior —
read-only, never unreadable: revisions still list, snapshots still download,
trash/purge/export still work.

## Ingest

Product glue dumps content in with one comm call — no HTTP, no import:

```python
call("docs.create_document", {
    "workspace_id": ws_id, "type": "md", "title": "Weekly sync",
    "body": summary_text, "folder_path": "/Meetings/2026-08",
})
```

`folder_path` materializes folders idempotently; an unknown `type` refuses
loudly so content never silently lands under a mistyped slug.

## Sharing (v1: closed by default)

The sharing axis (`SHARING`: whitelist / link modes) ships its config surface
with **closed defaults** — v1 implements exactly the immutable workspace
baseline, and opening any sharing knob before the mechanism exists is a loud
system-check error (`stapel_docs.E010-E013`), never a silent no-op.

## Settings

All configuration lives in the `STAPEL_DOCS` namespace (dict setting, flat
setting, or env var — resolved lazily). Full table in
[CONFIG.MD](https://github.com/usestapel/stapel-docs/blob/main/CONFIG.MD);
seam semantics in
[MODULE.md](https://github.com/usestapel/stapel-docs/blob/main/MODULE.md).
Highlights: `STORAGE`, `DOC_TYPES`, `EXPORTERS`, `INGEST`, `REPLAY_WINDOW`,
`AUTO_REVISION_INTERVAL_SECONDS`, `TRASH_RETENTION_DAYS`, `SHARING`.

## comm surface

| Kind | Name | Contract |
|---|---|---|
| Function (provides) | `docs.create_document` | `schemas/functions/docs.create_document.json` |
| Action (emit) | `document.created`, `document.updated`, `document.deleted`, `document.storage_changed` | `schemas/emits/*.json` |
| Action (consume) | `user.deleted` | GDPR anonymize (authorship nulled, content survives) |
| Function (call) | `workspaces.check_capability` | provided by stapel-workspaces |

## Operations

```bash
python manage.py docs_purge_expired   # purge trash older than TRASH_RETENTION_DAYS
```

## Development

```bash
pip install -e . && pip install pytest pytest-django ruff jsonschema djangorestframework
./setup-hooks.sh
pytest tests/
```

## License

MIT — see [LICENSE](https://github.com/usestapel/stapel-docs/blob/main/LICENSE).

---

<sub>This page is assembled by `stapel-readme` from `docs/readme.md` plus the contract artifacts in `docs/`. Edit the prose in `docs/readme.md`; the badges, facts and links above and below it are generated — do not hand-edit `README.md`.</sub>
