CONTRIBUTING.md
Rama main · réplica de lectura del repositorio original.
# 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).