reports#

Crime & safety data products by neighbourhood with tiered access (snapshot, subscription, premium, professional), Stripe checkout, token-based downloads, and dataset management.

Models#

Model

Description

CrimeDataPurchase

One-time or subscription purchase granting crime data access

StripeWebhookEvent

Idempotency record for reports-specific Stripe webhooks

Dataset

Purchasable dataset with R2 storage path and Stripe product/price mappings

DatasetAccess

Grants a user/email access to a specific dataset

URL Routes#

Path

View

Description

/reports/crime/

crime_reports_index

Index of available crime reports

/reports/crime/<slug>/

crime_report_detail

Full crime dashboard (requires access)

/reports/crime/<slug>/map/

crime_report_map

Interactive crime map

/reports/crime/<slug>/statistics/

crime_report_statistics

Detailed statistics

/reports/crime/<slug>/incidents/

crime_report_incidents

Incident listing

/reports/crime/<slug>/safety/

crime_report_safety

Safety guide

/reports/crime/<slug>/api/

crime_data_api

Free preview JSON (limited)

/reports/crime/<slug>/pricing/

get_pricing_options

GET pricing options

/reports/crime/<slug>/checkout/

create_checkout_session

POST create Stripe checkout

/reports/crime/<slug>/success/

purchase_success

Post-purchase success

/reports/crime/<slug>/access/

check_access

Check current access status

/reports/crime/download/<token>/

download_crime_data

Token-based data download

/reports/crime/manage-subscription/

manage_subscription

Manage data subscription

Management Commands#

Command

Description

create_dataset

Create new crime dataset records

update_dataset

Update dataset pricing, status, or metadata

migrate_purchases_to_dataset_access

Migrate legacy CrimeDataPurchase to DatasetAccess

Access Model#

flowchart TD USER[User/Guest] -->|checkout| STRIPE[Stripe] STRIPE -->|webhook| DA[DatasetAccess] DA -->|access_token| DOWNLOAD[download_crime_data] DOWNLOAD --> R2[Cloudflare R2] USER -->|subscription| TIER[SubscriptionTier] TIER -->|includes_data| DA

Data Taxonomy System#

The reports app includes a data taxonomy that provides machine-readable metadata for all data products. Each product is described by a DataProductManifest containing one or more DatasetMetadata sub-datasets.

Data Class Taxonomy#

Class ID

Colour

Description

EVT_DAILY

🟢 Green

Event / incident data (daily cadence)

AGG_QUARTERLY

🔵 Blue

Aggregated official statistics (quarterly)

REF_SLOW

⚪ Grey

Slow-changing reference data (yearly+)

DER_ROLLING

🟡 Amber

Derived rolling-window metrics

DER_QUARTERLY

🟡 Amber

Derived quarterly calculations

DER_CUMULATIVE

🟡 Amber

Derived cumulative KPIs

SNAP_COMPOSITE

🟣 Purple

Assembled composite of sub-datasets

SNAP_WEEKLY

🟣 Purple

Weekly point-in-time snapshot

LIVE_STATUS

🟢 Green

Near-real-time status feed

LIVE_HISTORY

🔵 Blue

Time-series history of live data

AGG_MARKET

🔵 Blue

Aggregated market data

Registered Products#

Product

Slug

Registry file

Sub-datasets

Sea Point Crime & Safety

sea-point

sea_point_registry.py

7

Cape Town Dam Levels

dam-levels

dam_levels_registry.py

4

SA Loadshedding Status

loadshedding

loadshedding_registry.py

5

Cape Town Ward Crime & Safety

crime-safety

crime_safety_registry.py

7

Cape Town Housing Market

housing

housing_registry.py

7

Architecture#

flowchart TD REG[manifest_registry.py] -->|lazy import| SP[sea_point_registry.py] REG --> DL[dam_levels_registry.py] REG --> LS[loadshedding_registry.py] REG --> CS[crime_safety_registry.py] REG --> HSG[housing_registry.py] REG --> VIEW[Admin Taxonomy View] VIEW --> IDX[taxonomy_index_view\ncard grid] VIEW --> DET[taxonomy_detail_view\nper-product dashboard]

Each registry file defines:

  • Identity — name, slug, source, description

  • Classification — DataClassID enum value

  • Update schedule — cadence, staleness threshold, cache TTL

  • Refresh mechanics — incremental vs full, lookback window, backfill policy

  • Dependencies — other sub-datasets that must run first (topological sort)

  • Storage paths — R2 key, R2 history path, local fallback path

  • Pipeline integration — management command to run

Adding a new product#

  1. Create reports/<slug>_registry.py with DatasetMetadata instances and a DataProductManifest

  2. Register it in reports/manifest_registry.py → _build_registry()

  3. The admin taxonomy page automatically discovers it

Key Design Decisions#

  • Dataset stores dual Stripe IDs (test/live) and R2 bucket/path for direct cloud access.

  • DatasetAccess unifies one-time purchases and subscription-based access behind a single token-based download mechanism.

  • Legacy migration: CrimeDataPurchase is the original model; Dataset + DatasetAccess are the newer abstraction. The migration command bridges the two.

  • Free preview: The /api/ endpoint returns limited data without authentication, encouraging conversion to paid access.