Skip to main content

Dashtro

CI Version Docker image npm @dashtro/client npm @dashtro/mcp License: MIT

A self-hosted CMS with a project → workspace → collection → document model, a FastAPI backend, and a React/TypeScript frontend. Ships as a single Docker image, published to atharvad216/dashtro. This repo only builds and publishes that image — running it in production (nginx, tunnel/domain routing, etc.) is owned by the consuming project (e.g. the portfolio site that embeds Dashtro as its admin/CMS backend).

Contents

Structure

Path What it is
cms_backend/ FastAPI backend — API, auth, schema engine, data clients. See its README.
cms-frontend/ React + TypeScript + Vite frontend. See its README.
cms_mcp/ MCP server exposing Dashtro operations to MCP-compatible clients over /api/sdk/* (Python, console script dashtro-mcp, API-key auth).
sdk/js/ @dashtro/client — JS/TS client SDK for /api/sdk/*.
sdk/python/ dashtro-client — Python client SDK for /api/sdk/*, released in lockstep with sdk/js/.
sdk/mcp/ @dashtro/mcp — npx-runnable MCP server (Node/TS port of cms_mcp/) for consuming projects; talks to /api/sdk/* over HTTP with an API key, no Python required.
nginx/ Reverse proxy config for local dev only.

Packages

Everything this repo publishes, and what it's for:

Package Registry Install What it's for
atharvad216/dashtro Docker Hub docker pull atharvad216/dashtro The CMS itself — backend + built frontend in one image. See Running the image elsewhere.
@dashtro/client npm npm install @dashtro/client JS/TS client SDK for /api/sdk/* — read/write a project's documents and RTDB from an external app.
dashtro-client PyPI pip install dashtro-client Python equivalent of @dashtro/client, released in lockstep with it.
@dashtro/mcp npm npx @dashtro/mcp init npx-runnable MCP server — lets Claude/other MCP clients read and write your CMS content. Node port of cms_mcp/, no Python needed.
dashtro PyPI pip install dashtro The dashtro backup/restore CLI (cms_backend/scripts/cms_schema.py, see Backup / restore CLI). Also installs dashtro-mcp (direct-database-access MCP server) — use @dashtro/mcp instead unless you specifically need that.

Architecture

flowchart LR
    Browser["Browser SPA\n(cms-frontend)"] -->|"/api/*"| Backend["FastAPI backend\n(cms_backend)"]
    Backend --> DB[("sqlite / postgres")]
    ExternalApp["External app"] -->|"/api/sdk/*"| Backend
    ExternalApp -.->|uses| ClientSDK["@dashtro/client\ndashtro-client"]
    MCPClient["MCP client\n(Claude, etc.)"] -->|stdio, npx| MCPNode["@dashtro/mcp\n(Node)"]
    MCPNode -->|"/api/sdk/*"| Backend
    MCPClient -.->|stdio, local install| MCPPy["dashtro-mcp\n(cms_mcp, Python)"]
    MCPPy -->|"/api/sdk/*"| Backend

Everything ultimately talks to the same FastAPI backend — the frontend over its own JWT-authenticated API, and everything else (external apps via either client SDK, and MCP clients via either MCP server) over the API-key-scoped /api/sdk/* surface only. MCP clients never see a user's JWT — what an MCP client can do is exactly what its configured API key is scoped to (project/collections, read vs. write). Pick @dashtro/mcp for a zero-install npx setup, or cms_mcp/dashtro-mcp if you're already in a Python environment.

Data backends

DB_TYPE selects the storage backend, defaulting to sqlite:

  • sqlite — single-file DB, zero external dependencies. Default.
  • postgres — set DB_HOST/DB_PORT/DB_NAME/DB_USER/DB_PASSWORD. An optional bundled postgres compose service is available (see below) if you don't want to point at an external instance.

Both backends implement the same interface (get_data_client() / get_auth_client() / get_audit_client() in cms_backend/api/utils/__init__.py), so routers don't change depending on which one is active.

Running locally (dev)

Hot-reloading, separate frontend/backend containers, Cloudflare tunnel support:

cp .env.example .env   # fill in real values
npm run dev             # docker compose -f docker-compose.dev.yml up --build
npm run dev:down

Optional local Postgres instead of an external one:

docker compose -f docker-compose.dev.yml --profile postgres up

Running the image elsewhere

The published image serves both the API and the built SPA on port 7312, and reads its config from env vars (see below) — no other dependency beyond whichever DB_TYPE backend you point it at:

dashtro:
  image: atharvad216/dashtro:latest
  environment:
    JWT_SECRET_KEY: ...
    CORS_ORIGINS: ...
    CMS_PUBLIC_URL: ...
    DB_TYPE: sqlite
    # ...see .env.example for the full list
  volumes:
    - uploads_data:/app/uploads

Put it behind whatever reverse proxy/tunnel the consuming project already uses to route a subdomain (e.g. admin.example.com) to it.

Environment variables

See .env.example for the full list (DB_TYPE, JWT_SECRET_KEY, CORS_ORIGINS, CMS_PUBLIC_URL, etc.).

Backup / restore CLI

cms_backend/scripts/cms_schema.py (installed as the dashtro console script) exports/imports schemas, documents, and media to/from a backup/ directory.

Local (direct database access)

# Export
dashtro export schema --project-id <id>
dashtro export documents --project-id <id> --workspace <name>
dashtro export media

# Import
dashtro import schema --project-id <id>
dashtro import documents --project-id <id> --workspace <name>
dashtro import media

Scope to specific schemas, collections, or documents with --schema-name, --collection, and --document-id (each repeatable; --document-id requires exactly one --collection, since ids are only unique within a collection):

dashtro export schema --project-id <id> --schema-name BlogPost
dashtro export documents --project-id <id> --workspace <name> --collection articles
dashtro export documents --project-id <id> --workspace <name> --collection articles --document-id abc123

Run against a running container:

docker exec <container> dashtro export schema --project-id <id> --backup-dir /app/backup
docker exec <container> dashtro import schema --project-id <id> --backup-dir /app/backup

Remote (HTTP API with authentication)

Use --base-url to export/import from/to a remote Dashtro instance. Requires an API key generated in the CMS settings.

Via command line:

# Export from remote
dashtro export schema --project-id <id> --base-url https://your-cms.com --api-key <api-key>
dashtro export documents --project-id <id> --workspace <name> --base-url https://your-cms.com --api-key <api-key>
dashtro export media --base-url https://your-cms.com --api-key <api-key>

# Import to remote
dashtro import schema --project-id <id> --base-url https://your-cms.com --api-key <api-key>
dashtro import documents --project-id <id> --workspace <name> --base-url https://your-cms.com --api-key <api-key>
dashtro import media --base-url https://your-cms.com --api-key <api-key>

Via environment variable (recommended):

export CMS_API_KEY=<api-key>
dashtro export schema --project-id <id> --base-url https://your-cms.com
dashtro import documents --project-id <id> --workspace <name> --base-url https://your-cms.com

Full backup/restore workflow

Export must run in order: schema → documents → media. Restore uses the same order:

# Backup from source instance
dashtro export schema --project-id abc123 --base-url https://source.com --api-key <key>
dashtro export documents --project-id abc123 --workspace production --base-url https://source.com --api-key <key>
dashtro export media --base-url https://source.com --api-key <key>

# Restore to destination instance
dashtro import schema --project-id abc123 --base-url https://dest.com --api-key <key>
dashtro import documents --project-id abc123 --workspace production --base-url https://dest.com --api-key <key>
dashtro import media --base-url https://dest.com --api-key <key>

Options:

Flag Meaning
--backup-dir Backup directory location (default: ./backup/)
--base-url Remote API URL (if omitted, uses direct database access)
--api-key API key for authentication (or set CMS_API_KEY env var)
--merge Merge documents instead of replacing (local mode only)

CI/CD

.github/workflows/build-image.yml runs on every push to main (or manually via workflow_dispatch):

  1. lint — frontend npm run lint + backend isort/black/ruff --check. Must pass before anything builds.
  2. build-and-push — builds Dockerfile.dashtro, pushes to atharvad216/dashtro on Docker Hub, tagged latest and the commit SHA.

That's it — this repo doesn't deploy anywhere itself. Whatever consumes the image (e.g. the portfolio project) is responsible for pulling and running it.

Tests

npm test                              # everything: frontend, backend + cms_mcp, sdk/mcp

npm run test:frontend                 # cms-frontend (vitest)
npm run test:backend                  # cms_backend + cms_mcp (pytest, SQLite by default)
TEST_DB_TYPE=postgres pytest          # cms_backend, against a reachable Postgres
npm run test:mcp                      # sdk/mcp — @dashtro/mcp (vitest)

License

MIT

Metadata

Release files for dashtro 0.26.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 dashtro 0.26.0
File Size Uploaded Provenance Actions
dashtro-0.26.0.tar.gz 68.8 kB With provenance Details for dashtro-0.26.0.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for dashtro 0.26.0
File Interpreter ABI Platform Actions
dashtro-0.26.0-py3-none-any.whl Python 3 none any Details for dashtro-0.26.0-py3-none-any.whl

Total release size: 143.0 kB

Release files / dashtro-0.26.0.tar.gz

Download URL dashtro-0.26.0.tar.gz
Size 68.8 kB
Tags Source
SHA-256 checksum
How to use checksums
166117fbffd25cd1ddb667742e13f3480f3d9db28a019fd57e3c76dc7020b714
BLAKE2b-256 checksum
How to use checksums
736a194d5fd1842663b405da070aab3239e4d3d83644e3c94fa7000bb9423b92
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 Oct 8, 2026.

Transparency log

Release files / dashtro-0.26.0-py3-none-any.whl

Download URL dashtro-0.26.0-py3-none-any.whl
Size 74.2 kB
Tags Python 3
SHA-256 checksum
How to use checksums
b07afb1b518fa9e26fa4d681eab37bb4cc47c0f361d2293390a7c7272489c383
BLAKE2b-256 checksum
How to use checksums
e2c312bf20b9af2cfd9ca4faf783636c3e6e321d414f606230994bb84bdbbb07
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 Oct 8, 2026.

Transparency log

Security for dashtro 0.26.0

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.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for dashtro-0.26.0.tar.gz

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 Oct 8, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

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