Kelompok should be API-first and CLI-first.
The web app, automation jobs, service integrations, and future AI workflows should use the same core API and command interfaces.
- Version all public endpoints under
/api/v1 - Return consistent response shapes
- Use cursor pagination for large public lists
- Keep public endpoints readable without authentication
- Require authentication for claims, edits, campaigns, and admin actions
- Make claim, import, and enrichment operations auditable
- Publish OpenAPI docs
- Expose plugin-safe ingestion endpoints and commands
- Return public DTOs instead of raw database models
- Keep claim-only contact data, source evidence, raw imports, and private plugin metadata out of public responses
Recommended success shape:
{
"data": {},
"meta": {},
"message": "ok"
}Recommended error shape:
{
"error": {
"code": "organization_not_found",
"message": "Organization not found",
"details": {}
}
}Public endpoints must be treated as an explicit allowlist.
They may include public organization profile fields, public post fields, and public impact metrics. They must not expose internal UUIDs, claim verification emails, raw source records, private evidence, credentials, tokens, or plugin-private metadata.
Dynamic JSON fields are filtered before they leave the API. If a plugin or import pipeline needs to keep raw evidence, it should store that data in internal tables or private JSON fields and expose only reviewed public fields through the stable response DTO.
Organizations:
GET /api/v1/organizations
GET /api/v1/organizations/{slug}
GET /api/v1/organizations/{slug}/events
GET /api/v1/organizations/{slug}/donations
GET /api/v1/organizations/{slug}/impact-reports
GET /api/v1/organizations/{slug}/posts
GET /api/v1/organizations/{slug}/posts/{post_slug}
GET /api/v1/organizations/{slug}/sdgs
Implemented in the first public read API slice:
GET /api/v1/organizations
GET /api/v1/organizations/{slug}
GET /api/v1/organizations/{slug}/posts
GET /api/v1/organizations/{slug}/posts/{post_slug}
GET /api/v1/organizations/{slug}/impact-reports
Posts:
GET /api/v1/posts
GET /api/v1/posts/{slug}
GET /api/v1/post-categories
GET /api/v1/post-tags
Implemented in the first public read API slice:
GET /api/v1/posts
GET /api/v1/posts/{slug}
Events:
GET /api/v1/events
GET /api/v1/events/{slug}
POST /api/v1/events/{event_id}/registrations
Donation campaigns:
GET /api/v1/donation-campaigns
GET /api/v1/donation-campaigns/{slug}
GET /api/v1/donation-campaigns/{slug}/reports
Auth:
POST /api/v1/auth/register
POST /api/v1/auth/login
POST /api/v1/auth/logout
GET /api/v1/auth/me
Claims:
POST /api/v1/organizations/{id}/claims
GET /api/v1/claims
GET /api/v1/claims/{id}
POST /api/v1/claims/{id}/verify-email
POST /api/v1/claims/{id}/verify-instagram
POST /api/v1/admin/claims/{id}/approve
POST /api/v1/admin/claims/{id}/reject
Organization management:
PATCH /api/v1/org-admin/organizations/{id}
POST /api/v1/org-admin/organizations/{id}/members
PATCH /api/v1/org-admin/organizations/{id}/members/{member_id}
DELETE /api/v1/org-admin/organizations/{id}/members/{member_id}
POST /api/v1/org-admin/organizations/{id}/impact-reports
PATCH /api/v1/org-admin/impact-reports/{id}
Post management:
POST /api/v1/org-admin/posts
PATCH /api/v1/org-admin/posts/{id}
POST /api/v1/org-admin/posts/{id}/publish
POST /api/v1/org-admin/posts/{id}/archive
Event management:
POST /api/v1/org-admin/events
PATCH /api/v1/org-admin/events/{id}
POST /api/v1/org-admin/events/{id}/ticket-types
GET /api/v1/org-admin/events/{id}/registrations
Donor management:
POST /api/v1/org-admin/donation-campaigns
PATCH /api/v1/org-admin/donation-campaigns/{id}
POST /api/v1/org-admin/donation-campaigns/{id}/reports
PATCH /api/v1/org-admin/donation-reports/{id}
The CLI should be useful for:
- Local development
- Self-hosted maintenance
- Data imports
- Import and enrichment jobs
- Claim operations
- Exporting data
- Future AI agent workflows
CLI commands should support:
--jsonoutput--dry-run--limit--source--since- clear exit codes
Server and database:
kelompok serve
kelompok migrate up
kelompok migrate down
kelompok seed
kelompok health
Implemented early:
kelompok seed demo
Organization data:
kelompok org import --file organizations.csv
kelompok org search "climate foundation"
kelompok org show {slug} --json
kelompok org claim {slug} --email admin@example.org
kelompok org export --format json
Members:
kelompok member import --file members.csv --organization {slug}
kelompok member export --organization {slug} --format json
Posts:
kelompok post import --file posts.csv --organization {slug}
kelompok post publish {id}
kelompok post archive {id}
kelompok post export --organization {slug} --format json
Imports and source operations:
kelompok source add --type website --url https://example.org
kelompok source normalize --source-record {id}
kelompok source match --dry-run
Plugins:
kelompok plugin list
kelompok plugin info {plugin}
kelompok plugin run {plugin} --job import-organizations --file organizations.csv
kelompok plugin run {plugin} --job import-members --organization {slug}
kelompok plugin run {plugin} --job import-posts --organization {slug}
kelompok plugin run {plugin} --job import-events --organization {slug}
Events:
kelompok event import --file events.csv
kelompok event publish {id}
Donor reports:
kelompok donor campaign create
kelompok donor report publish {id}
kelompok donor export --organization {slug}
Admin:
kelompok admin user create
kelompok admin claim approve {claim_id}
kelompok admin claim reject {claim_id}
kelompok admin audit show --entity organization:{id}
For future AI usage, CLI output should be deterministic and machine-readable.
Example:
kelompok org show green-foundation --json
Should return:
{
"id": "org_123",
"slug": "green-foundation",
"name": "Green Foundation",
"claim_status": "unclaimed",
"public_url": "https://example.org/o/green-foundation",
"sdgs": ["13", "15"],
"sources": [
{
"type": "website",
"url": "https://green.example.org"
}
]
}