|
| 1 | +# CLAUDE.md |
| 2 | + |
| 3 | +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. |
| 4 | + |
| 5 | +## Project Overview |
| 6 | + |
| 7 | +`sbxpy` is a Python SDK for the SBXCloud BaaS (Backend as a Service) platform. It provides async HTTP clients (via aiohttp) for CRUD operations, querying, event handling, workflow management, and optional Redis caching. Published to PyPI as `sbxpy`. |
| 8 | + |
| 9 | +## Build & Development |
| 10 | + |
| 11 | +- **Package manager**: uv |
| 12 | +- **Python**: >= 3.12 (pyproject.toml) / >= 3.13 (README target) |
| 13 | +- **Install dependencies**: `uv sync` |
| 14 | +- **Add dependency**: `uv add <package>` |
| 15 | +- **Run a script**: `uv run <script.py>` |
| 16 | +- **Build package**: `python setup.py sdist bdist_wheel` |
| 17 | +- **No test suite exists** — test manually via scripts with env vars configured |
| 18 | + |
| 19 | +## Environment Variables |
| 20 | + |
| 21 | +Required for SBXCloud connection: |
| 22 | +- `SBX_DOMAIN` — domain ID |
| 23 | +- `SBX_APP_KEY` — application key |
| 24 | +- `SBX_TOKEN` — auth token |
| 25 | +- `SBX_HOST` — base URL (e.g., `https://sbxcloud.com/api`) |
| 26 | + |
| 27 | +Optional for Redis caching: |
| 28 | +- `REDIS_HOST`, `REDIS_PORT`, `REDIS_USER`, `REDIS_PASSWORD` |
| 29 | + |
| 30 | +## Architecture |
| 31 | + |
| 32 | +All library code lives in `sbxpy/`. The `build/` directory contains stale build artifacts. |
| 33 | + |
| 34 | +### `sbxpy/__init__.py` — Core module (majority of the library) |
| 35 | + |
| 36 | +Contains multiple client classes, each following the same pattern: initialize with domain/credentials, build queries, execute async HTTP requests via aiohttp. |
| 37 | + |
| 38 | +- **`SbxCore`** — Main SBXCloud client. Handles auth, CRUD (`upsert`, `login`), cloudscript management (`run`, `create_cloudscript`, `list_cloudscripts`, `get_cloudscript`, `update_cloudscript`), model/field management (`create_model`, `create_field`, `list_domain`), and creates `Find` query objects via `with_model()`. |
| 39 | +- **`Find`** — Fluent query builder for find/delete operations. Supports `and_where_*`/`or_where_*` conditions, `fetch_models` (JOINs), pagination, `find_all()` with concurrent page fetching via semaphore-limited `asyncio.gather`. |
| 40 | +- **`SbxEvent` / `EventQuery`** — Client for the SBXCloud event service (separate base URL, uses `sbx-secret` header). |
| 41 | +- **`SbxWorkflow` / `WorkflowQuery`** — Client for workflow/process execution API. |
| 42 | +- **`SbxCRMUser` / `UserQuery`** — Client for CRM user management API. |
| 43 | +- **`ReferenceJoin` / `FilterJoin`** — Reference join query helpers. |
| 44 | + |
| 45 | +### `sbxpy/QueryBuilder.py` |
| 46 | + |
| 47 | +Low-level query JSON builder. Constructs the `where`, `rows`, `fetch`, `order_by`, and `page`/`size` parameters sent to the SBXCloud API. |
| 48 | + |
| 49 | +### `sbxpy/domain/__init__.py` |
| 50 | + |
| 51 | +- **`SBXModel`** — Pydantic BaseModel base class for all domain models. Maps `_KEY` to `key` field. Hashable by key. |
| 52 | +- **`@sbx(model="name")`** — Decorator that binds a model class to an SBXCloud model name (stored as `cls._model`). |
| 53 | +- **`MetaModel`** — Timestamps sub-model (`created_time`, `updated_time`). |
| 54 | + |
| 55 | +### `sbxpy/sbx/__init__.py` |
| 56 | + |
| 57 | +- **`SBX`** — Singleton accessor for `SbxCore`, reads credentials from env vars. |
| 58 | +- **`SBXService`** — Abstract base with `find()`, `get_by_key()`, `list_all()` convenience methods. |
| 59 | +- **`SBXResponse`** — Pydantic model wrapping API responses. Key methods: `all(Type)`, `first(Type)`, `get_ref(model, key, Type)`, `merge()`, `has_results()`. |
| 60 | + |
| 61 | +### `sbxpy/cache/__init__.py` |
| 62 | + |
| 63 | +- **`RedisService`** — Async Redis client (via `redis.asyncio`) for caching Pydantic objects as JSON. Supports get/set/mget/mset with optional TTL, plus key index management. |
| 64 | + |
| 65 | +### `sbxpy/service/__init__.py` |
| 66 | + |
| 67 | +- **`SBXCachedService`** — Extends `SBXService` with Redis cache-through pattern for `get()` and `list()` operations. |
| 68 | + |
| 69 | +## API Endpoints Used |
| 70 | + |
| 71 | +### Data |
| 72 | +- `POST /data/v1/row` — insert records |
| 73 | +- `POST /data/v1/row/update` — update records |
| 74 | +- `POST /data/v1/row/find` — query records |
| 75 | +- `POST /data/v1/row/delete` — delete records |
| 76 | + |
| 77 | +### Models & Fields |
| 78 | +- `GET /data/v1/row/model/list?domain={id}` — list models (`list_domain()`) |
| 79 | +- `POST /data/v1/row/model?domain={id}&name={name}` — create model (`create_model()`) |
| 80 | +- `POST /data/v1/field/model?domain={id}&name={name}&row_model_id={id}&type={type}` — create field (`create_field()`). Field types: `STRING`, `INT`, `FLOAT`, `BOOLEAN`, `TEXT`, `REFERENCE`. For `REFERENCE`, pass `reference_type=target_model_id`. |
| 81 | + |
| 82 | +### CloudScripts |
| 83 | +- `POST /cloudscript/v1/run` — execute a cloudscript (`run()`) |
| 84 | +- `POST /cloudscript/v1.5/{domain_id}` — create cloudscript (`create_cloudscript()`) |
| 85 | +- `GET /cloudscript/v1.5/{domain_id}?page=N` — list cloudscripts (`list_cloudscripts()`) |
| 86 | +- `GET /cloudscript/v1.5/{domain_id}/{key}` — get cloudscript (`get_cloudscript()`) |
| 87 | +- `PUT /cloudscript/v1.5/{domain_id}/{key}/script` — update cloudscript (`update_cloudscript()`) |
| 88 | + |
| 89 | +## Key Conventions |
| 90 | + |
| 91 | +- All API calls are async (use `await`). The library uses `aiohttp.ClientSession` per request. |
| 92 | +- `upsert()` separates items with `_KEY` (updates) from those without (inserts) and sends them to different endpoints (`/data/v1/row/update` vs `/data/v1/row`). |
| 93 | +- Maximum 1000 records per upsert call. |
| 94 | +- `find_all()` fetches the first page, reads `total_pages`, then fetches remaining pages concurrently with semaphore-limited parallelism (default 2). |
| 95 | +- Dates in SBXCloud are often stored as `int` in `YYYYMMDD` format. |
| 96 | +- Domain models use Pydantic v2 with `populate_by_name=True` to handle the `_KEY` alias. |
0 commit comments