# Deploy a Go URL shortener with PostgreSQL on Yeeted

A Yeeted sample: URL shortener in plain Go. What it demonstrates:

- **Platform conventions**: binds `0.0.0.0`, honors `$PORT`, `/healthz`.
- **Managed postgres with self-migration**: `DATABASE_URL` is injected by the
  platform; the app applies `migrations/*.sql` in order at startup, tracked in
  `schema_migrations` (tracked across sequential restarts).
- **Redis read-through cache**: set `REDIS_URL` and resolves hit redis first
  with a 5-minute TTL; without it the app is merely slower, never wrong.
- **Graceful degradation**: no `DATABASE_URL` runs an in-memory store, which
  is also what the unit tests use.

Tests: `go test ./...` (unit, zero services) ·
`SHORTEN_URL=https://... go test -run Deployed` (integration) ·
`./smoke.sh https://...` (smoke).

## Run locally

Use Go 1.23 or newer. From `go/shorten-go`:

```sh
go test ./...
go run .
```

Open `http://localhost:3000`. Without `DATABASE_URL`, links live in memory.
With `DATABASE_URL`, startup applies the SQL migrations to PostgreSQL.
`REDIS_URL` enables the optional cache; leave it unset for the first run.

## Deploy and verify

Follow the [deployment walkthrough](getting-started.md). Deploy this
folder with `go.mod`, `go.sum`, migrations, and `yeeted.yaml`. Its manifest
requests PostgreSQL and health checks on `/healthz`.

```sh
sh smoke.sh "$PREVIEW_URL"
SHORTEN_URL="$PREVIEW_URL" go test -run Deployed
```

Create a link by sending `POST /api/links` with
`{"url":"https://yeeted.ai/"}`. Read the `slug` from the response, then
request `/{slug}` without following redirects. Expect 302 and a `Location`
header containing the original URL. `GET /api/links/{slug}/hits` reports
resolutions. The smoke script checks basic creation and redirect behavior;
it does not prove Redis usage or persistence across restarts.

## What to change before real use

This demo has no account system or abuse controls for public link creation.
Hit counting on cache hits is asynchronous and best-effort, not billing-grade
analytics. The SQL migration runner is sequentially repeatable but does not
coordinate concurrent replicas. Test PostgreSQL persistence and Redis failure
behavior before relying on those paths in your own application.

[All examples](index.md) · [Deploy an example](getting-started.md)
