stapel-listings
Listings and catalog vertical: a Listing core (owner, opaque category, typed attribute values, price + price_base, inventory) with a draft/publish lifecycle including the moderation takedown state 'blocked', an independent moderation status, a value-validation pipeline delegated to stapel-attributes against a category schema fetched over comm, a publish service, first-class favorites, and the two pull seams its consumers read it through — listings.search_documents / listings.search_export for an indexer and listings.moderation_content for a moderation queue.
Part of the Stapel framework — composable Django apps that deploy as a monolith or as microservices without changing module code.
Install
pip install stapel-listings
At a glance
| Fact | Value |
|---|---|
| Version | 0.6.2 |
| Python | >=3.11 (3.11, 3.12, 3.13, 3.14) |
| Django | djangorestframework>=3.14 |
| HTTP operations | 16 |
| Config axes | 2 |
| Usage surface | 7 |
| Extension points | 6 |
| Error codes | 63 |
| Fleet dependencies | stapel-attributes · stapel-categories (optional) · stapel-core |
Documentation
OpenAPI · capabilities.json · llms.txt (for agents)
What this is
Listing is the marketplace core: an owner, an opaque category, typed
attribute values, a two-machine lifecycle + moderation status, a publish
pipeline, and first-class favorites. It consumes stapel-categories (feature
schema, over comm) and stapel-attributes (value validation), and stays
decoupled from search, moderation and currencies (see the boundaries below).
Quick start
INSTALLED_APPS = [
# ...
"stapel_listings",
]
# urls.py — this module's own urls.py bakes in only `v1/`; the host
# contributes `api/`, giving the canonical `/listings/api/v1/...` prefix.
path("listings/api/", include("stapel_listings.urls"))
Requires a categories.features comm Function provider (stapel-categories) for
value validation against a category's schema.
Settings
All configuration lives in the STAPEL_LISTINGS namespace (dict setting, flat
setting, or env var — resolved lazily). Full table with seam semantics in
MODULE.md.
| Key | Default | Meaning |
|---|---|---|
CATEGORY_FEATURES_FUNCTION |
"categories.features" |
comm Function resolving a category's feature schema. |
PRICE_BASE_CONVERTER |
identity | Dotted-path (amount, currency, base) -> Decimal. |
AUTO_APPROVE_ON_PUBLISH |
False |
Publish immediately when no moderation module is installed. |
REQUIRE_IMAGE_ON_PUBLISH |
True |
Require ≥1 image to publish. |
MODERATION_TARGET_TYPE |
"listing" |
target_type this module answers to in moderation.completed. |
LISTING_URL_TEMPLATE |
"" |
Public URL template ({listing_id}) for the moderator's card. |
DEFAULT_LISTING_TTL_DAYS |
30 |
Days until a published listing expires. |
comm surface
Emits (Actions): listing.submitted (moderation boundary),
listing.published / listing.updated / listing.removed (search boundary).
Consumes: category.changed, moderation.completed, user.deleted.
Provides Functions: listings.status, listings.search_documents,
listings.search_export, listings.moderation_content.
Calls: categories.features.
Boundaries: search/filtering is a separate stapel-search module; this
module builds features_search, signals with the listing.* events and hands
over the document through listings.search_documents (keyed batch) and
listings.search_export (cursor snapshot), but exposes no search endpoints —
the events carry identity, so no listing content rides the durable bus and no
indexer reads this database. Moderation is a separate stapel-moderation
module: this module emits listing.submitted, serves the content over
listings.moderation_content and applies the target-generic
moderation.completed verdict (including the published → blocked takedown),
but runs no moderation pipeline. Re-moderating an edit of a live listing is
post-moderation: the lifecycle stays published, moderation_status goes to
pending, the edit is visible immediately, and a rejecting verdict removes it
through the takedown edge.
Contract
docs/{schema,flows,errors}.json are emitted from a single-module
{listings + core} Django instance mounted at the canonical
/listings/api/v1 prefix (make contract / make contract-check; see
_codegen.py) — the same mechanism stapel-search, stapel-chat and
stapel-forms already use. docs/flows.json is []: no flow is declared via
@flow yet, same state as every other contract-complete module today.
Delta note — one field stays untyped on purpose. features_search
(ListingDetailSerializer) is a flattened per-category search index: one
dynamic key per feature slug, shaped by whatever category schema a given
listing happens to carry. There is no fixed property set to declare, so the
schema types it as a bare object rather than fake a closed shape that would
go stale the moment any category adds a feature. Every other field that used
to fall back to an untyped blob this way — images / images_draft, both
lists of opaque <type>/<hash> CDN refs (models.py "Opaque list of CDN image
references") — is now typed as array[string], and the ten polymorphic
attribute-value shapes (FeatureDto/FeatureDao) are a proper
discriminated oneOf keyed by type, contributed by stapel-attributes.
Extension points
See MODULE.md — the agent-facing map of every fork-free seam (settings, serializer seams, comm surface, GDPR provider).
Development
pip install -e . && pip install pytest pytest-django ruff
./setup-hooks.sh
pytest tests/
License
MIT — see LICENSE.
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.
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 stapel_listings-0.6.2.tar.gz.
File metadata
- Download URL: stapel_listings-0.6.2.tar.gz
- Upload date:
- Size: 83.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0098ba9695135bd0d12b6fa4ebd8a28f69889511e8fb595a84c427e023b7aeca
|
|
| MD5 |
b7a6053a18bc27c62ebd8e0c59d31f1e
|
|
| BLAKE2b-256 |
32c979498281e7dc0bf8f959781a3684899765f65a84bd2c60c75cb919df8462
|
Provenance
The following attestation bundles were made for stapel_listings-0.6.2.tar.gz:
Publisher:
publish.yml on usestapel/stapel-listings
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
stapel_listings-0.6.2.tar.gz -
Subject digest:
0098ba9695135bd0d12b6fa4ebd8a28f69889511e8fb595a84c427e023b7aeca - Sigstore transparency entry: 2557695465
- Sigstore integration time:
-
Permalink:
usestapel/stapel-listings@5a6fdd7394b8ef8f64a880839598e461bad5dc7f -
Branch / Tag:
refs/tags/v0.6.2 - Owner: https://github.com/usestapel
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@5a6fdd7394b8ef8f64a880839598e461bad5dc7f -
Trigger Event:
push
-
Statement type:
File details
Details for the file stapel_listings-0.6.2-py3-none-any.whl.
File metadata
- Download URL: stapel_listings-0.6.2-py3-none-any.whl
- Upload date:
- Size: 79.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
dee438de3d3f4f1e8409186b409633eb832d67be0829ab7f31ed3c966840df0e
|
|
| MD5 |
3787c4a8f6a2b84c62b54ea564c66e58
|
|
| BLAKE2b-256 |
e02c0ba0c095f9948498d5d839f286cd8f109c22a1b1c99beb857cbc1f64fc46
|
Provenance
The following attestation bundles were made for stapel_listings-0.6.2-py3-none-any.whl:
Publisher:
publish.yml on usestapel/stapel-listings
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
stapel_listings-0.6.2-py3-none-any.whl -
Subject digest:
dee438de3d3f4f1e8409186b409633eb832d67be0829ab7f31ed3c966840df0e - Sigstore transparency entry: 2557695520
- Sigstore integration time:
-
Permalink:
usestapel/stapel-listings@5a6fdd7394b8ef8f64a880839598e461bad5dc7f -
Branch / Tag:
refs/tags/v0.6.2 - Owner: https://github.com/usestapel
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@5a6fdd7394b8ef8f64a880839598e461bad5dc7f -
Trigger Event:
push
-
Statement type: