# Set up CloudHike.dev in this app

You are an AI coding agent. The user gave you a CloudHike.dev project id and an
access token. CloudHike.dev hosts the app's backend: a Postgres database, user
sign-up and login (Auth), S3-compatible file storage, and Redis. Follow these
steps in order.

## 1. Download the project's environment

```sh
curl -fsS -H "Authorization: Bearer <access token>" https://cloudhike.dev/api/projects/<project id>/env
```

The response is a .env file with a line for every service the project is
running, and the user's own variables:

| Variable | Service |
| --- | --- |
| DATABASE_URL | Postgres 16 connection string (pooled when DIRECT_URL is present) |
| DIRECT_URL | Direct Postgres connection, only when DATABASE_URL is pooled |
| AUTH_URL, AUTH_PUBLISHABLE_KEY, AUTH_SECRET_KEY | Auth API |
| S3_ENDPOINT, S3_REGION, S3_BUCKET, S3_ACCESS_KEY_ID, S3_SECRET_ACCESS_KEY | Storage bucket |
| REDIS_URL | Redis |
| EMAIL_API_URL, EMAIL_API_KEY, EMAIL_FROM | Email API, and the address to send from |
| JOBS_API_URL, JOBS_API_KEY | Background jobs API |

A 401 means the token is wrong or was revoked: ask the user to copy the
prompt again from the project's Overview page in the CloudHike.dev dashboard.

## 2. Save it

- Merge the lines into the app's env file: `.env.local` for Next.js, `.env`
  otherwise. Replace keys that already exist and keep every other line.
- Make sure that file is listed in `.gitignore`.
- Never print secret values in chat, commit them, or put them in browser
  code. Only AUTH_URL and AUTH_PUBLISHABLE_KEY may be used in the browser.
- Do not save the access token in the app. It is only for this download.

## 3. Use the services the app needs

Only wire up services whose variables were in the response. Use the app's
existing libraries and patterns where it has them.

**Postgres** (DATABASE_URL): connect from server code with the app's ORM, or
`pg`. Create tables with the ORM's migrations, or plain SQL. Create one small
pool (at most 5 connections) per process and, in frameworks with hot reload
such as Next.js, keep it on `globalThis` so a reload reuses it: each leaked
pool holds connections, and the database refuses new ones once its limit is
used up. When DIRECT_URL is present, DATABASE_URL goes through a connection
pooler (PgBouncer, transaction mode): use DATABASE_URL for the app's queries,
and DIRECT_URL for migrations (the ORM's direct or migration URL setting),
LISTEN/NOTIFY, session-level SET and advisory locks.

**Auth** (AUTH_*): an email and password API. Every request sends the header
`x-api-key: AUTH_PUBLISHABLE_KEY` and a JSON body.

- `POST {AUTH_URL}/sign-up/email` with `{ name, email, password }`
- `POST {AUTH_URL}/sign-in/email` with `{ email, password }`

Both return `{ token, user }`. Keep the token and send it as
`authorization: Bearer <token>` to:

- `GET {AUTH_URL}/get-session` for the signed-in user (null when signed out)
- `POST {AUTH_URL}/sign-out`

From server code only, with `x-api-key: AUTH_SECRET_KEY`:
`GET {AUTH_URL}/admin/users?search=&limit=50&offset=0` and
`DELETE {AUTH_URL}/admin/users/<id>`.

**Storage** (S3_*): use `@aws-sdk/client-s3` from server code:

```ts
new S3Client({
  endpoint: process.env.S3_ENDPOINT,
  region: process.env.S3_REGION,
  forcePathStyle: true,
  credentials: {
    accessKeyId: process.env.S3_ACCESS_KEY_ID!,
    secretAccessKey: process.env.S3_SECRET_ACCESS_KEY!,
  },
});
```

All objects go in S3_BUCKET. For uploads from the browser, create presigned
URLs on the server with `@aws-sdk/s3-request-presigner`.

**Redis** (REDIS_URL): connect from server code with `ioredis` or `redis`.

**Email** (EMAIL_*): transactional email (receipts, password resets, alerts), never
marketing or bulk mail. From server code only, because the key is secret:
`POST {EMAIL_API_URL}/send` with the header `x-api-key: EMAIL_API_KEY` and a JSON
body `{ to, subject, html, text, fromName?, replyTo?, scheduledAt? }` (`to` is one address or an
array; send `html`, `text` or both; `scheduledAt` is an ISO time up to 7 days ahead,
and `POST {EMAIL_API_URL}/emails/<id>/cancel` cancels a scheduled message). Mail goes out from the platform's own
address, so set `replyTo` to the app's support address. Always send `from: EMAIL_FROM`: it is the
platform address until the user verifies their own domain under Email → Domains, then an address on that domain,
so fetching the .env again picks the domain up. A 429 means a plan limit
was reached.

**Jobs** (JOBS_*): background runs for slow API calls and AI workflows. From server
code only: `POST {JOBS_API_URL}/runs` with `x-api-key: JOBS_API_KEY` and a JSON body
`{ url, method?, headers?, body?, timeoutSeconds?, retries?, callbackUrl? }` answers
202 with `{ id }`. The platform calls `url`; read the result with
`GET {JOBS_API_URL}/runs/<id>` until `status` is succeeded, failed or cancelled, or
receive it as a POST to `callbackUrl`. Verify the `x-cloudhike-signature` header
(`t=<ts>,v1=<hex>`, HMAC-SHA256 of `<ts>.<raw body>` with JOBS_API_KEY) on both.
Full guide: https://cloudhike.dev/docs/md/jobs

## 4. Missing services

If the app needs a service that was not in the response, tell the user to
deploy it on the project's Services tab in the CloudHike.dev dashboard
(https://cloudhike.dev/dashboard), then run step 1 again. Auth needs Postgres.

## 5. Finish

Tell the user which services you connected and which files you changed,
without showing any secret values.
