Files
metabuilder/AGENTS.md
johndoe6345789 9e892dcd74 refactor(deployment): remove 10 redundant shell scripts replaced by Python CLI
All deployment commands now go through deployment.py. Deleted:
build-base-images.sh, build-apps.sh, build-testcontainers.sh, deploy.sh,
start-stack.sh, release.sh, nexus-ci-init.sh, push-to-nexus.sh,
populate-nexus.sh, publish-npm-patches.sh.

Kept nexus-init.sh and artifactory-init.sh (Docker container entrypoints).
Updated all references in CLAUDE.md, README.md, AGENTS.md, ROADMAP.md,
deployment docs, Dockerfiles, and docker-compose comments.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-16 01:19:32 +00:00

191 lines
6.1 KiB
Markdown

# MetaBuilder — Agent Guide
**Last Updated**: 2026-03-04
Quick-start for AI agents (Claude Code, Copilot, etc.) working on this codebase.
Read CLAUDE.md for the full guide. This file covers agent-specific patterns and shortcuts.
---
## What's Running
```
http://localhost/pastebin # Next.js UI
http://localhost/pastebin-api # Flask auth (register, login, JWT)
http://localhost:8080 # DBAL C++ REST API (entities)
```
**Test accounts**: `demo/demo1234`, `alice/alice1234`, `bob/bob12345`
---
## Architecture in 30 Seconds
```
Browser (Next.js + Redux + IndexedDB)
└── Flask (JWT auth, Python runner) frontends/pastebin/backend/
└── DBAL C++ daemon (REST API) dbal/production/
└── PostgreSQL (prod)
```
**DBAL event flow on user registration**:
```
POST /pastebin/pastebin/User
└── handleCreate() → dispatchAsync("pastebin.User.created")
└── detached thread → on_user_created.json (15 nodes)
└── 2 namespaces + 5 seed snippets created
```
---
## Key Files to Know
| Path | What it is |
|------|-----------|
| `dbal/shared/api/schema/entities/` | JSON entity schemas — SOURCE OF TRUTH (39 entities) |
| `dbal/shared/api/schema/events/event_config.json` | Event → workflow mappings |
| `dbal/shared/api/schema/workflows/` | JSON workflow definitions |
| `dbal/shared/api/schema/auth/auth.json` | JWT + ACL rules |
| `dbal/shared/seeds/database/` | Declarative seed data (JSON, loaded at startup) |
| `dbal/production/src/workflow/` | C++ workflow engine (WfEngine, WfExecutor, steps/) |
| `dbal/production/src/daemon/server_routes.cpp` | Route registration + auto-seed startup |
| `frontends/pastebin/backend/app.py` | Flask JWT auth + Python runner |
| `frontends/pastebin/src/` | Next.js React app |
| `deployment/docker-compose.stack.yml` | Full stack compose |
| `deployment/deployment.py` | Python CLI for all build/deploy/stack commands |
---
## Before You Touch Anything
```bash
# Search docs first (SQLite FTS5)
cd docs && python3 docs.py search "topic"
cd txt && python3 reports.py search "topic"
# Check what's already there
ls dbal/shared/api/schema/entities/
ls dbal/shared/seeds/database/
# Logs
docker logs -f metabuilder-dbal
docker logs -f metabuilder-pastebin-backend
```
---
## Deploy Commands
```bash
cd deployment
# Full rebuild + restart
python3 deployment.py build apps --force dbal pastebin
docker compose -f docker-compose.stack.yml up -d
# Flask backend (separate from Next.js)
docker compose -f docker-compose.stack.yml build pastebin-backend
docker compose -f docker-compose.stack.yml up -d pastebin-backend
# dbal-init volume (schema volume container — rebuild when entity JSON changes)
docker compose -f docker-compose.stack.yml build dbal-init
docker compose -f docker-compose.stack.yml up dbal-init
```
---
## Entity Schema Format (JSON)
All schemas live in `dbal/shared/api/schema/entities/*.json`.
```json
{
"name": "MyEntity",
"tenantId": "pastebin",
"package": "pastebin",
"fields": [
{ "name": "id", "type": "uuid", "primary": true },
{ "name": "name", "type": "string", "required": true },
{ "name": "userId", "type": "uuid", "required": true },
{ "name": "tenantId", "type": "string", "required": true },
{ "name": "createdAt", "type": "timestamp", "required": true }
]
}
```
After schema changes: `python3 dbal/shared/tools/codegen/gen_types.py`
---
## Seed Data Format (JSON)
All seed files in `dbal/shared/seeds/database/*.json`. Idempotent — skipped if records exist.
```json
{
"entity": "MyEntity",
"records": [
{ "id": "uuid-here", "name": "Example", "tenantId": "pastebin", "createdAt": 0 }
],
"metadata": { "bootstrap": true }
}
```
For multi-document seeds (array of seed objects): wrap in `[...]` at top level.
**User passwords**: Generate werkzeug hashes inside the container:
```bash
docker exec metabuilder-pastebin-backend python3 -c \
"from werkzeug.security import generate_password_hash; print(generate_password_hash('mypassword'))"
```
---
## Workflow Step Types
| Type | What it does |
|------|-------------|
| `dbal.uuid` | Generates UUID v4, stores via `outputs` |
| `dbal.timestamp` | Current timestamp (ms), stores via `outputs` |
| `dbal.entity.create` | `client.createEntity(entity, data)` |
| `dbal.entity.get` | `client.getEntity(entity, id)` |
| `dbal.entity.list` | `client.listEntities(entity, options)` |
| `dbal.var.set` | `ctx.set(key, value)` |
| `dbal.log` | `spdlog::info(message)` |
Context variable resolution: `"${var_name}"`, `"${event.userId}"`, `"prefix-${name}-suffix"`
---
## Rules (Non-Negotiable)
1. **Multi-tenant always**: Every DBAL query filters by `tenantId`. No exceptions.
2. **JSON not YAML**: All schemas, events, workflows, seeds — pure JSON. yaml-cpp removed.
3. **Seed data in `dbal/shared/seeds/`** — never hardcode in Flask Python or C++.
4. **No hardcoded entity names** — loaded from schema JSON.
5. **Call `ensureClient()` before any DB op in `registerRoutes()`**`dbal_client_` starts null.
6. **`deployment.py build apps pastebin` ≠ Flask** — that only rebuilds Next.js. Flask needs `docker compose build pastebin-backend`.
---
## Common Traps
| Trap | Fix |
|------|-----|
| nlohmann/json iterator `it->second` | Use `it.value()` |
| dbal-init volume stale after schema rename | `docker compose build dbal-init && docker compose up dbal-init` |
| `.dockerignore` blocks `dbal/shared/seeds/` | Add `!dbal/shared/seeds/database` |
| Seed segfaults on startup | Missing `ensureClient()` guard |
| Seed runs every restart | `skipIfExists` check broken — verify entity name matches schema |
| Werkzeug scrypt not on host Python | Generate inside running container with `docker exec` |
---
## Pastebin Stack URLs (dev)
| Service | URL | Auth |
|---------|-----|------|
| UI | `http://localhost/pastebin` | JWT cookie |
| Flask auth API | `http://localhost/pastebin-api/api/auth/*` | — |
| DBAL entities | `http://localhost:8080/{tenant}/{package}/{entity}` | Bearer JWT |
| DBAL health | `http://localhost:8080/health` | — |