Skip to main content

stapel-classified

CI coverage pypi downloads python license llms.txt

Composite for location-bound classified ads: the stapel-shop composite (categories + listings + reviews) plus stapel-geo, stapel-search and stapel-moderation, and the cross-domain declarations no member is allowed to write — the listing search source, the listing/review/seller/chat_message moderation target policies, the marketplace reason taxonomy, and (since 0.3.2) the listing subject type stapel-chat's registry ships empty of. Its own HTTP surface is a conversation HEADER, assembled from three modules that may not know about each other: chat says who is in the thread and what it is about, listings answers the short card (title, price, the photo gallery with CDN render metadata, and a state that says available, unavailable or gone — exactly the answer a public read cannot give), profiles answers the counterparty. It owns NO table: the binding it kept from 0.2.0 to 0.3.1 existed only because chat could not tell two threads about two listings apart, and it was deleted rather than kept in sync the release chat could. It enforces no block of its own: stapel-chat 0.6.1 holds both write doors (opening a direct thread, sending into one) at the one point every client passes, and this composite's whole contribution is the value required it sets on chat's BLOCK_ENFORCEMENT axis in the preset. The pre-creation door it kept until 0.3.x was deleted in 0.4.0, and a deployment that still declares the old STAPEL_CLASSIFIED keys is told so at boot (E003) rather than silently inheriting chat's default.

Part of the Stapel framework — composable Django apps that deploy as a monolith or as microservices without changing module code.

Install

pip install stapel-classified

At a glance

Fact Value
Version 0.11.0
Python >=3.11 (3.11, 3.12, 3.13, 3.14)
HTTP operations 3
Config axes 3
Usage surface 10
Extension points 3
Error codes 46
Fleet dependencies stapel-attributes · stapel-categories · stapel-cdn (optional) · stapel-chat · stapel-geo · stapel-listings · stapel-moderation · stapel-notifications (optional) · stapel-profiles (optional) · stapel-reviews · stapel-search

Documentation

OpenAPI · capabilities.json · llms.txt (for agents)

Assemble (one line)

pip install stapel-tools
stapel-assemble myads --libs classified
cd myads && make test

That expands classified through the STAPEL_LIBS requires closure and wires every member module into INSTALLED_APPS, requirements.txt, urls.py and CONFIG.MD, then runs the verify gates.

Manual wiring (no scaffold)

# settings.py
from stapel_classified import preset

INSTALLED_APPS = [
    # ... django/stapel-core baseline (incl. stapel_core.django.projections)
    *preset.INSTALLED_APPS,
]
for _k, _v in preset.SETTINGS_DEFAULTS.items():
    globals().setdefault(_k, _v)

# urls.py
from django.urls import include, path

from stapel_classified import preset

urlpatterns = [
    path(prefix, include(module)) for prefix, module in preset.URL_INCLUDES
]

Mount from preset.URL_INCLUDES rather than by hand: stapel-classified (its own conversation surface), stapel-categories and stapel-listings contribute only the v1/ segment and belong under <mod>/api/, while reviews, geo, search and moderation bake api/v1/ in themselves. Both end at /<mod>/api/v1/..., and getting it wrong is a stapel_core.mounts.E004 refusal to boot, not a cosmetic difference.

Config checklist (fill these, in the generated project's CONFIG.MD too)

Key Note
STAPEL_REVIEWS["TARGET_TYPES"] prefilled by the preset (targets listing)
STAPEL_SEARCH["SOURCES"] prefilled by the preset (the listing source)
STAPEL_MODERATION["TARGET_TYPES"] prefilled by the preset (listing pre-publication, review/seller/chat_message post)
STAPEL_CHAT["BLOCK_ENFORCEMENT"] prefilled required by the preset — the ONE block switch, and it is stapel-chat's. Chat holds both doors (opening a direct thread, sending into one) and says at every boot which state you are in. A key of this name under STAPEL_CLASSIFIED moved here in 0.4.0 and is a boot error (stapel_classified.E003).
STAPEL_ACCESS["ROLES"] yours — the moderation console is staff-only; preset.RECOMMENDED_ACCESS_ROLES shows the shape
STAPEL_GDPR["DATA_OWNERS"] yours — must list "moderation", or erasure never closes over complaint data
STAPEL_MODERATION["APPEAL_URL_TEMPLATE"] yours — an empty appeal link is what DSA Art. 17 notices
STAPEL_SEARCH["BACKEND"] defaults to Postgres; name naive or meili if that is not your engine
STAPEL_LISTINGS["BASE_CURRENCY"] default USD — set your currency
STAPEL_GEO[...] geocoder provider/keys — see stapel-geo CONFIG.MD
listing coordinates lat/lon are LISTING fields (no projection needed) — see stapel-listings

Glue

Two members ship deliberately empty registries, because neither may know what a listing is. This package is the one place that knows both sides:

  • STAPEL_SEARCH["SOURCES"]["listing"] → stapel_classified.search_sources.listing_source. Pulls documents through listings.search_documents / listings.search_export, invalidated by listing.published / listing.updated / listing.removed. Registering it is also what wires the subscribers — you write no signal handler. Facets are built from listings' features_search (stapel-search's declared lossy fallback: attribute range filters do not work until listings serves DAOs).
  • STAPEL_MODERATION["TARGET_TYPES"] → listing (pre-publication: listing.submitted opens the case and nothing is public until the verdict) and review (post: live on arrival, a verdict is a takedown).

Coordinates need no glue at all: they are the listing's OWN fields (lat/lon on the listing), not a foreign aggregate.

The conversation header (0.2.0)

A chat in a classified marketplace is always ABOUT something and BETWEEN two identified people. Neither fact belongs to the messaging engine, so this composite owns the join and serves the header:

POST /classified/api/v1/conversations           bind a chat thread to a listing
GET  /classified/api/v1/conversations/{id}      one header
POST /classified/api/v1/conversations/contexts  a page of them, for the inbox

A header carries the short listing card — title, price, the photo gallery with CDN render metadata over every frame, and a state of available / unavailable (sold, paused, expired) / gone, which is the answer a public listing read cannot give and exactly the case a buyer is most confused by — plus the counterparty's public seller card. Never more of a person than their public profile.

docs/frontend-contract.md is the document the default skins build against: every payload, every refusal, and the six things the fleet does not serve yet with what the UI does about each in the meantime.

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.

Metadata

Release files for stapel-classified 0.11.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for stapel-classified 0.11.0
File Size Uploaded
stapel_classified-0.11.0.tar.gz 159.0 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for stapel-classified 0.11.0
File Interpreter ABI Platform
stapel_classified-0.11.0-py3-none-any.whl Python 3 none any Details

Total release size: 324.2 kB

Release files / stapel_classified-0.11.0.tar.gz

Download URL stapel_classified-0.11.0.tar.gz
Size 159.0 kB
Tags Source
SHA-256 checksum
How to use checksums
8deada80d12cc4fa959d9af2b228ab905d193815f358d33148dd92cf1b731d41
BLAKE2b-256 checksum
How to use checksums
a540a8b03dbafbece249c9eb856f6a7b4802815f892126ef782dcda951842191
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 13, 2026.

Transparency log

Release files / stapel_classified-0.11.0-py3-none-any.whl

Download URL stapel_classified-0.11.0-py3-none-any.whl
Size 165.2 kB
Tags Python 3
SHA-256 checksum
How to use checksums
c871e0fb5813dff93eb23c12d92e5cf128e9572200d2f711a9fab043f0efd47f
BLAKE2b-256 checksum
How to use checksums
5270c8ca2225e6ef174a4ac18ebaa5253304dc223c809f6a84908259a0377e0e
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 13, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.11.0 This release

2 release files

0.9.5

2 release files

0.9.4

2 release files

0.9.3

2 release files

0.9.1

2 release files

0.9.0

2 release files

0.8.7

2 release files

0.8.6

2 release files

0.8.5

2 release files

0.8.4

2 release files

0.8.3

2 release files

0.8.1

2 release files

0.8.0

2 release files

0.7.2

2 release files

0.7.1

2 release files

0.7.0

2 release files

0.6.2

2 release files

0.6.0

2 release files

0.5.4

2 release files

0.4.3

2 release files

0.4.2

2 release files

0.4.1

2 release files

0.4.0

2 release files

0.3.3

2 release files

0.2.1

2 release files

0.2.0

2 release files

0.1.8

2 release files

0.1.7

2 release files

0.1.5

2 release files

0.1.4

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page