CONTRIBUTING.md
Rama main · réplica de lectura del repositorio original.
# Contributing to DataBounty Community
Thanks for looking. Before anything else, one thing about this repository will trip you up if nobody
warns you:
> ### ⚠️ There is no root install
>
> This repository holds **four independent applications** under `apps/`. There is no root
> `package.json`, no npm workspace, and no monorepo build tool. Each app has its own
> `package.json` and its own `package-lock.json`.
>
> **`npm install` at the repository root does nothing.** Install, build, lint, and test from
> *inside* each app directory.
That is deliberate — the four apps share no code and talk to each other only over HTTP — but it is
the opposite of what most `apps/`-shaped repositories do, so it is stated first.
---
## Table of contents
- [What you need](#what-you-need)
- [Getting it running](#getting-it-running)
- [The four apps](#the-four-apps)
- [Before you open a pull request](#before-you-open-a-pull-request)
- [Running the tests](#running-the-tests)
- [What we will and won't merge](#what-we-will-and-wont-merge)
- [House rules that are not negotiable](#house-rules-that-are-not-negotiable)
- [Commit messages](#commit-messages)
- [Certifying your contribution (DCO)](#certifying-your-contribution-dco)
- [Credit and attribution](#credit-and-attribution)
- [Reporting bugs](#reporting-bugs)
- [Security](#security)
- [License](#license)
---
## What you need
- **Node.js 20.19.0 or newer.** `apps/api` declares `"engines": { "node": ">=20.19.0" }`. The three
Next.js apps do not declare an `engines` field, but run on the same toolchain — use the same Node
across all four.
- **PostgreSQL**, one reachable instance.
- **npm.** Per-app, as described above.
- **Docker** (optional) — for the one-command stack instead of running four processes by hand.
## Getting it running
The fastest path to a working stack is Docker Compose, which starts Postgres, applies migrations,
seeds the dataset-type catalog, and runs all four apps plus the background worker:
```bash
docker compose up
```
To run apps directly, start with the API — the other three need it to be useful:
```bash
cd apps/api
npm install
cp .env.example .env # fill in DATABASE_URL at minimum
npx prisma migrate deploy # applies prisma/migrations/
npx tsx prisma/seed-catalog.ts # idempotent; loads the dataset-type catalog
npm run dev # API on http://localhost:4000
```
Then any frontend:
```bash
cd apps/web # or apps/admin, apps/landing
npm install
cp .env.example .env # fill in NEXT_PUBLIC_API_URL and the other apps' URLs
npm run dev
```
Background jobs run inside `npm run dev` — there is no separate worker process to start (that split was removed 2026-09-02). Deduplication,
sandboxed execution, and publication all run as background jobs — without the worker they queue and
nothing happens, which looks exactly like a bug in the code you just wrote.
## The four apps
| App | What it is | `npm run dev` port |
|---|---|---|
| `apps/api` | Fastify + Prisma + Postgres. REST API, MCP server, background worker, validation pipeline. | `4000` |
| `apps/web` | Next.js. The logged-in dashboard: sponsor requests, contributor submission, validator audits, karma/profile. | `53000` |
| `apps/admin` | Next.js. Operator console: review requests, moderate, configure settings. | `3002` |
| `apps/landing` | Next.js. Public site: dataset catalog, public profiles, marketing pages. | `3001` |
If you change a port, `NEXT_PUBLIC_API_URL` and the API's `CORS_ORIGINS` / `APP_URL` have to agree with
it. **`CORS_ORIGINS` must list every frontend origin you actually run**, or the browser silently blocks
API calls from the ones you left out — with no server-side error to tell you why.
## Before you open a pull request
Run these in **each app you touched**. All four apps have `typecheck`; the three frontends have `lint`;
`apps/api` has `test`.
```bash
npm run typecheck # all four apps
npm run lint # apps/web, apps/admin, apps/landing (apps/api has no eslint config)
npm run build # confirms it actually compiles for production
npm test # apps/api only — see below, it needs a database
```
Then, in the pull request description, say **what you verified and how**. "Should work" is not a
verification. If you changed something a user can see, say which page you loaded and what you observed.
### What CI runs on your pull request
CI is path-aware. It compares your branch against its merge base with `main` and checks only the apps
your commits actually touch: a pull request confined to `apps/web` runs the web typecheck, lint, build
and image build, and nothing for `apps/api`. A change to anything shared — `docker-compose.yml`, the
workflow itself, the root `.dockerignore`, any file outside `apps/**` that is not documentation — runs
all four apps, because a shared file can break any of them.
The job names never change and no job is ever skipped: a job with nothing to do runs, prints why, and
exits. That is deliberate. A required status check that sometimes does not exist is a required check
that has silently stopped being required, and the "Decide what to run" job's step summary lists exactly
which apps were checked, so a green run always says what it actually proved.
Pushes to `main` and manual runs always check all four apps regardless of paths. The deploy hand-off
fires from a `main` run, so a deployment is never built on a partial one.
> **Do not edit `.github/workflows/ci.yml` as part of an application, documentation, or bug-fix pull request.**
> CI changes affect every contributor and deployment hand-off, so they require a separately scoped,
> explicitly approved change with its own verification evidence.
## Running the tests
`apps/api` has unit and integration tests on Vitest. The integration tests are the substance of the
suite, and they need a real Postgres database. `npm test` deliberately runs files serially because
they share the disposable database and their cleanup would otherwise race across workers. Do not
remove that serialization unless every worker first receives an isolated database.
**They will refuse to run against the wrong one.** Every integration test file checks that
`DATABASE_URL` contains `databounty_community_parity_verify` and throws immediately if it does not:
```
Refusing to run integration tests: DATABASE_URL does not point at the disposable
databounty_community_parity_verify database. Check .env before running tests.
```
That guard exists because these tests write and delete rows. Do not weaken it, do not special-case it,
and do not point it at a database you care about. Create the disposable one:
```bash
createdb databounty_community_parity_verify
DATABASE_URL="postgresql://…/databounty_community_parity_verify" npx prisma migrate deploy
DATABASE_URL="postgresql://…/databounty_community_parity_verify" npm test
```
If you add a test that touches the database, carry the same guard.
The three frontends have no test suite. Adding one is welcome; adding a mostly-empty one so the badge
turns green is not.
## What we will and won't merge
**Welcome:**
- Bug fixes, with a note on how you reproduced the bug and confirmed the fix.
- Tests for existing behavior, particularly on the frontends where there are none.
- Documentation that corrects something wrong. If a doc and the code disagree, **the code wins** — fix
the doc to match reality, not the other way around.
- Accessibility, responsive, and error-state fixes.
- New dataset types and validation harnesses.
**Please open an issue first:**
- New API endpoints, or changes to existing request/response shapes.
- Prisma schema changes. Every schema change ships with a matching migration in the same pull request —
a schema edit without a migration silently drifts every deployment.
- Anything that changes what a trust claim means, or when a pipeline stage is considered passed.
- Large refactors. A 3,000-line diff that moves code around is very hard to review against a product
whose correctness rests on specific guarantees.
**We will not merge:**
- **Wallet, payment, escrow, payout, validator-bond, or on-chain functionality.** This is not a missing
feature, a disabled flag, or a paid tier held back — karma is the only reward this product has,
and there is nothing to upgrade to. A pull request adding any of it will be declined on scope alone.
- A pipeline stage that reports a result it did not compute. See below.
- Generated or vendored dependency directories, build output (`dist/`, `.next/`, `out/`), or `.env`
files. All are gitignored; if one shows up in your diff, remove it.
## House rules that are not negotiable
These come from the product's own guarantees, not from style preference. A pull request that breaks one
will be asked to change regardless of how good the rest of it is.
1. **Never fake a check result.** If a validation stage was skipped, is unsupported, is unconfigured, or
went stale, the stored evidence and the UI must both say exactly that. A placeholder that always
reports "not attempted" — or worse, "passed" — is worse than not having the stage. Fail closed and be
honest about why. This is the single rule the product cannot survive breaking.
2. **Do not hardcode to today's formats.** Dataset types are a versioned registry with per-type
allowlists and pluggable parsers. Submission, preview, validation, similarity, and export logic must
not assume JSON/CSV or today's catalog. Unknown types fail closed to quarantine or human review.
3. **Heavy work is asynchronous.** Parsing, media processing, similarity, sandboxed execution, and LLM
review run as background jobs — idempotent, with bounded retries and recoverable failures. Do not do
them inline in a request handler, and do not hold a database transaction open across a network call
to a sandbox or a model provider.
4. **Filter and paginate server-side.** List endpoints take query parameters. Do not fetch everything
and filter in the browser.
5. **A contributor cannot validate their own submission.** Conflict-of-interest checks are enforced
server-side. Do not add a client-side-only version and call it done.
6. **Reuse what exists.** All three frontends have a shared component layer — `components/ui.tsx` in
`apps/web` and `apps/landing`, `components/admin-shell.tsx` (`AdminButton`, `AdminTable`,
`AdminErrorBanner`, `AdminPill`, …) in `apps/admin`. Use the existing button, banner, dialog, and table
before hand-rolling markup, and route API calls through the existing client modules — `lib/api-*` in
`apps/web`, `lib/use-admin-resource.ts` in `apps/admin`, `lib/public-data.ts` in `apps/landing` — rather
than calling `fetch` directly from a page.
7. **Every user-visible async action needs a loading and an error state.** A button that silently does
nothing on a 403 is a bug, not an edge case.
## Commit messages
Write plain, human commit messages in the imperative — "fix duplicate karma award on re-settlement",
not "fixed some stuff" and not a wall of bullet points. Explain *why* in the body when the reason is not
obvious from the diff.
**Do not add AI attribution to commit messages** — no `Co-Authored-By` trailer naming an AI assistant,
no "generated with" line, no robot emoji. Use the tools you like; the commit log stays a human record.
## Certifying your contribution (DCO)
This project uses the **Developer Certificate of Origin** — the same mechanism the Linux kernel and
Git itself use. There is no contributor licence agreement to sign, no form, and no account to create.
You certify a contribution by adding one line to the end of each commit message:
```
Signed-off-by: Your Name <your.email@example.com>
```
`git commit -s` adds it for you from your `git config` name and email. Set them once:
```bash
git config user.name "Your Name"
git config user.email "your.email@example.com"
git commit -s -m "fix duplicate karma award on re-settlement"
```
Use a real name and a working email — the sign-off is a statement of record, so it should identify
you the way you would identify yourself. Anonymous and pseudonymous sign-offs cannot be accepted.
**What you are certifying** is the full text of the [DCO version 1.1](https://developercertificate.org/):
in plain terms, that you wrote the contribution or otherwise have the right to submit it under this
repository's licence, and that you understand the contribution and your sign-off are public and
permanent.
**What you are not doing** is transferring anything. You keep the copyright in your own work; the
sign-off licenses it in under the [Apache License 2.0](LICENSE), the same terms the rest of the repository
carries. That is the whole of it — a DCO is a certification, not an assignment.
Forgot the sign-off? Nothing is lost:
```bash
git commit --amend -s --no-edit # last commit
git rebase --signoff HEAD~3 # last three
git push --force-with-lease
```
CI checks every commit in a pull request for the trailer, so an unsigned commit will fail the run
rather than sit unnoticed until review.
## Credit and attribution
You get credit automatically. You never have to ask for it, and asking is not held against you
either — if you were missed, that is our process failing, not a verdict on your work.
Four layers, all of them automatic:
- **Git history.** Your commit carries your name and email permanently, and feeds `git blame` and the
Contributors graph. We do not rewrite history and we do not squash away authorship.
- **[`CONTRIBUTORS.md`](CONTRIBUTORS.md).** Credits every kind of contribution, not just code — bug
reports, docs, design, review, accessibility, dataset types, translation, infrastructure. Maintained
by the [all-contributors](https://allcontributors.org) bot, so a maintainer adds you with a comment
on your merged pull request and you do nothing.
- **Release notes.** Each release names the people whose work is in it and links the pull request.
- **The pull request.** Public, attached to your account, linked from the commit — in practice the
most detailed record of what you did.
Two things worth knowing:
- **You can decline.** Say so in your pull request and we will leave you out of `CONTRIBUTORS.md` and
the release notes. Your commit stays in git history regardless — that is authorship, not
promotion, and removing it would mean rewriting the repository.
- **Security reports are credited in the advisory unless you ask us not to** — see
[`SECURITY.md`](SECURITY.md).
If your commits show up under more than one name or email, add yourself to [`.mailmap`](.mailmap) —
that is what the file is for.
## Reporting bugs
Open an issue with:
- Which app, and which page or endpoint.
- What you expected, and what actually happened.
- Steps to reproduce, and the commit SHA you are on.
- For the frontends: browser console output and the failing network request.
- For the API: the request, the response status and body, and the relevant server log lines.
Before filing, check the **Works today · Being wired up · Not built** table in
[README.md](README.md#works-today--being-wired-up--not-built). Several things are known-incomplete on
purpose; a report against one of those is still useful, but say that you saw it listed.
## Security
**Do not open a public issue for a security vulnerability.** See [SECURITY.md](SECURITY.md) for the
private reporting channel and what is in scope.
## License
Your contributions are licensed under the [Apache License 2.0](LICENSE), the same terms that cover this
repository. You certify that with a DCO sign-off on each commit — see
[Certifying your contribution](#certifying-your-contribution-dco). You keep the copyright in your own
work; nothing here asks you to assign it.