Ctrl K
ComunidadGuías…

CONTRIBUTING.md

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
# Contributing to Linky

Thanks for taking the time to contribute.

## Getting set up

Follow the [local development guide](./docs/local-development.md). In short:

```bash
pnpm install
cp .env.example .env.local          # then fill it in
docker-compose up -d                # postgres
pnpm dev:push
pnpm dev
```

The repo pins its package manager in `package.json` (`packageManager`), so use
`pnpm`, not `npm` or `yarn`, or the lockfile will drift.

## Before you open a pull request

CI runs these four on every PR. Run them locally first:

```bash
pnpm typecheck
pnpm lint
pnpm test
pnpm prettier --check "apps/**/*.{ts,tsx}" "packages/**/*.{ts,tsx}"
```

`pnpm test` includes DB-backed integration tests for the API, so it needs a
running database and `DATABASE_URL` in `.env.local`. CI brings up its own
postgres service container.

If prettier complains, `pnpm prettier --write` on the files you touched. Please
don't reformat files your change doesn't otherwise touch — it makes review
harder.

## Conventions worth knowing

- **Lint is enforced.** `@typescript-eslint/no-unused-vars` is an error. If a
  binding is deliberately unused — a key destructured only to keep it out of a
  rest object, say — prefix it with `_`.
- **Don't weaken the types.** The session a route handler sees comes from
  `apps/api/src/middleware/authenticate.ts` via Hono's typed `Variables`. A
  previous version of this typing referenced types it never imported, which
  `skipLibCheck` quietly turned into `any` and disabled type checking on
  `session` in every route handler. If you change it, check with
  `tsc --noEmit --skipLibCheck false` and confirm nothing in `src/` or `types/`
  errors.
- **The API is a Cloudflare Worker.** `apps/api` runs on workerd via Hono, so
  Node-only APIs and modules are not available; `nodejs_compat` covers
  `Buffer`, `process.env`, `AsyncLocalStorage` and friends, not `sharp`,
  `http` or the AWS SDK. Configuration is read from `process.env` at request
  time (Wrangler populates it from `vars` and secrets), with one exception:
  Wrangler defines `NODE_ENV` at build time, so avoid branching on it. Clients
  that hold a socket (the database pool, better-auth) are constructed per
  request, see `apps/api/src/lib/db.ts`; anything else must be constructed
  lazily, never at module scope, because Cloudflare executes the top level
  when it validates an upload, before any secret exists
  (`apps/api/src/lib/stripe.ts` shows the pattern).
- **CORS is deliberate.** Only first-party origins get credentialed requests.
  Published pages run on user custom domains and may only call session-free
  endpoints. See `apps/api/src/lib/origins.ts` before changing it.
- **Authorization belongs on the server.** A check in a server action that a
  client can skip by calling the underlying endpoint directly is not a check.

## Tests

Vitest, throughout:

- `apps/api` — unit tests plus DB-backed integration tests against the dev
  database. Files run serially (`fileParallelism: false`) because they share it.
- `packages/*` — plain unit tests.

Inject external boundaries (Stripe, S3, DynamoDB, the LLM) rather than reaching
for the network in a test. `apps/api/src/modules/reactions/service.test.ts`
shows the pattern for stubbing an AWS client.

## Commit messages

Explain _why_, not just what. If you fixed a bug, say what the broken behaviour
was — that is the part that is hard to reconstruct later.

## Reporting security issues

Please don't open a public issue. See [SECURITY.md](./SECURITY.md).