docs: add CONTRIBUTING.md — dev workflow, CI/CD, architecture, conventions

小橘 🍊(NEKO Team)
This commit is contained in:
小橘 2026-04-13 09:28:59 +00:00
parent 5d2ece9f80
commit 8e0f1e3a28

215
CONTRIBUTING.md Normal file
View File

@ -0,0 +1,215 @@
# Contributing to OGraph
## Project Structure
```
packages/
engine/ # CF Worker — API + Engine logic + UI
src/
index.ts # Hono routes + middleware
engine.ts # Core engine functions (CRUD, projections, reactions)
types.ts # TypeScript interfaces
ui.html # Built UI (committed, auto-generated)
ui/ # React SPA (Vite + Tailwind + headless-ui)
src/
App.tsx
api.ts
components/
wrangler.toml
cli/ # CLI client (@uncaged/ograph-cli)
src/
client.ts # HTTP client for OGraph API
commands/ # CLI commands (events, projections, reactions, etc.)
dispatcher/ # Local daemon — polls projections, notifies Agent
board/ # (experimental) Kanban board UI
```
## Prerequisites
- Node.js 22+
- npm (workspaces)
- Cloudflare account (for deployment)
- `wrangler` CLI (installed via npm)
## Setup
```bash
git clone https://github.com/oc-xiaoju/ograph.git
cd ograph
npm install
```
UI has its own dependencies:
```bash
cd packages/engine/ui
npm install
```
## Development Workflow
### Engine (API + Core Logic)
```bash
cd packages/engine
npm run dev # Local dev server (wrangler dev)
npm test # Run tests (vitest, 105+ tests)
```
### UI (React SPA)
```bash
cd packages/engine/ui
npm run dev # Vite dev server (hot reload)
npm run build # Build → dist/index.html (single-file)
```
After building UI, copy to engine:
```bash
cp packages/engine/ui/dist/index.html packages/engine/src/ui.html
```
### CLI
```bash
cd packages/cli
npm run build # TypeScript compile
npm test # Run tests (vitest, 31+ tests)
npm run dev # Watch mode
```
### Run All Tests
```bash
npm test # Runs tests across all workspaces
```
## CI/CD
**Pipeline:** `.github/workflows/ci.yml`
On every push to `main`:
1. **Test**`npm install``npm test` (all workspaces)
2. **Deploy** — Build UI → copy `ui.html``wrangler deploy` to Cloudflare Workers
On pull requests:
1. **Test** only (no deploy)
### Secrets (GitHub Actions)
| Secret | Description |
|--------|-------------|
| `CLOUDFLARE_API_TOKEN` | Wrangler deploy auth |
| `CLOUDFLARE_ACCOUNT_ID` | CF account |
### Production URL
- API: `https://ograph.shazhou.workers.dev`
- UI: `https://ograph.shazhou.workers.dev/ui`
## Commit Conventions
Format: `type(scope): description`
Types: `feat`, `fix`, `refactor`, `ci`, `docs`, `test`, `chore`
Scopes: `engine`, `cli`, `ui`, `dispatcher`, `board`
Examples:
```
feat(engine): add incremental event query with ?after=N
fix(ui): Projection ref params now filter objects by matching type
ci: add CD — auto deploy to Cloudflare Workers on push to main
```
Sign commits:
```
小橘 🍊(NEKO Team)
小墨 🖊️(KUMA Team)
```
Git config:
```bash
git config user.name "小橘"
git config user.email "xiaoju@shazhou.work"
```
## Architecture Notes
### Engine (Cloudflare Worker)
- **Runtime:** Cloudflare Workers (D1 database, Hono framework)
- **Auth:** API Key in `Authorization: Bearer ogk_xxx` header
- **UI:** Single HTML file served at `/ui`, built with Vite singlefile plugin
- **Logs:** Request logs auto-cleaned (7-day retention via `waitUntil`)
### Key Design Decisions
- **Snake_case everywhere** — API, DB, event names (`task_created`, not `taskCreated`)
- **Event names:** `{object}_{past_participle}` (e.g. `task_created`, `comment_added`)
- **Params use `_id` suffix**`task_id`, `agent_id`
- **Content-addressed hashing** — defs are immutable versions identified by hash
- **Projection health:** expression errors → `errored` status, returns stale value, no reaction triggered
- **Lazy computation:** projections compute on query, not on event emit
### UI Routing
Hash-based routing (`#/events`, `#/reaction-logs`). No react-router dependency — hand-rolled.
Pages:
| Route | Page |
|-------|------|
| `#/health` | Health dashboard |
| `#/object-defs` | Object type definitions |
| `#/objects` | Object instances |
| `#/event-defs` | Event type definitions |
| `#/events` | Event log |
| `#/projection-defs` | Projection definitions |
| `#/projections` | Query projections |
| `#/reactions` | Reaction definitions |
| `#/reaction-logs` | Reaction execution logs |
| `#/request-logs` | API request logs |
| `#/api-keys` | API key management |
### D1 Storage
- Free tier: 500 MB storage, 5M reads/writes per month
- TEXT fields: no length limit (SQLite underneath, ~1 MB per row)
- Logs: auto-pruned after 7 days
- Events: append-only, never deleted
### Testing
Engine tests use miniflare (local D1). Tests cover:
- CRUD for all entity types (object defs, event defs, projection defs, etc.)
- Projection computation + incremental reduce
- Reaction execution + handler sandboxing
- API key auth + permissions
- Error handling + edge cases
To add a test, edit `packages/engine/src/index.test.ts`.
## Manual Deploy (if needed)
```bash
cd packages/engine
# Build UI first
cd ui && npm run build && cp dist/index.html ../src/ui.html && cd ..
# Deploy
npx wrangler deploy
```
Requires `CLOUDFLARE_API_TOKEN` and `CLOUDFLARE_ACCOUNT_ID` env vars.
## D1 Database Access
```bash
# Query production D1
npx wrangler d1 execute ograph --remote --command "SELECT COUNT(*) FROM events"
# Time Travel (point-in-time recovery)
npx wrangler d1 time-travel ograph --before <timestamp>
```
---
*Built by 小橘 🍊 & 小墨 🖊️ — NEKO + KUMA Teams*