Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 50 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ Requires Node.js 24+ and [pnpm](https://pnpm.io) 10+.

```bash
pnpm install
pnpm dev # Vite dev server on :5173
```

To also run the API locally you need PostgreSQL and a `DATABASE_URL` in
Expand All @@ -35,6 +34,18 @@ pnpm --filter @t19/server db:seed # optional: replace the catalog with the
pnpm --filter @t19/server dev # GraphQL Yoga on :3001/graphql
```

Keep the API running in one terminal, then start the frontend in another:

```bash
pnpm dev # Vite dev server on :5173, client only
```

Open <http://localhost:5173/project2/> to use the application.

The frontend communicates with the GraphQL backend through Apollo Client. During local development, Vite forwards API requests to the backend running on port 3001. On the VM, Apache handles this routing instead.

To use a different GraphQL endpoint, set `VITE_GRAPHQL_URL` in `client/.env.local`.

`db:seed` is a reset command, not a loader. It replaces the catalog and,
through foreign-key cascades, deletes the reviews and crate items hanging
off it. Do not run it against a database holding user content you want.
Expand Down Expand Up @@ -75,23 +86,54 @@ All four must pass. CI runs the same thing.

| Path | What it is |
| ---------------- | --------------------------------------------------------------------------------------------------------------- |
| `client/` | React + Vite. Still the M1 skeleton; #9 wires the search view to the API |
| `client/` | React + Vite + Apollo Client. Album and artist search connected to the GraphQL API |
| `server/` | GraphQL Yoga + Drizzle over PostgreSQL. `searchAlbums` with filtering, facets and keyset paging. Live on the VM |
| `schema.graphql` | The contract both sides work against |
| `docs/` | Architecture and data model ADRs, UI specification, workflow, AI log, VM runbook |

Implemented: the PostgreSQL schema, with tracks, simulated users, reviews
and crate items, and trigger-maintained full-text search over titles
(weight A) and artist names (weight B). On top of it, album search by word,
genre and decade facets, keyset paging, four sort modes, and the `X-User-Id`
contract for the simulated user.
**Implemented:** PostgreSQL database with tables for albums, artists, genres,
tracks, users, reviews and crate items. The GraphQL backend supports album
searches, genre and decade filtering, pagination and sorting by `RELEVANCE`,
`TITLE_ASC` and `RELEASE_YEAR_DESC`. The schema also defines
`AVERAGE_RATING_DESC`, but this currently returns an error until reviews are
implemented.

The database tables for reviews and crate items exist, but the corresponding
GraphQL functionality is not yet implemented.

Planned: filters and sorting in the UI, the reviews and wantlist
The frontend supports searching by album title or artist name, with a 300 ms
debounce to avoid unnecessary requests. Users can also submit a search
immediately using Enter or the Search button. The interface provides loading
feedback, error handling and a message when no albums are found.

Currently, the frontend displays the first 20 matching albums, sorted by
relevance. Filtering, sorting, pagination controls and album details are not
yet available in the UI.

**Planned:** filters and sorting in the UI, the reviews and wantlist
mutations, accessibility and bærekraft (M3), then the Playwright `e2e/`
suite (M4). The GraphQL operations behind those are in `schema.graphql`,
but `searchAlbums` is the only query with a resolver so far, along with the
`Album` fields it returns.

Simulated user identity is defined in the GraphQL schema and architecture
documentation, but runtime handling of `X-User-Id` is not yet implemented.

## Try the application

Open <http://it2810-19.idi.ntnu.no/project2/> or your local frontend and try
these searches. Expected counts depend on the sample catalog from
`pnpm --filter @t19/server db:seed`; a different database may return different
results.

| Search | Expected matches | Albums |
| ----------- | ---------------- | ------------------------------------------ |
| `blue` | 4 | Kind of Blue, Blue Train, Blue, Blue Lines |
| `coltrane` | 2 | A Love Supreme, Blue Train |
| `radiohead` | 2 | OK Computer, Kid A |

Search is case-insensitive: `BLUE` should return the same matches as `blue`.

## Infrastructure

The database and the GraphQL API run directly on the group VM, not in
Expand Down
6 changes: 6 additions & 0 deletions docs/AI-USAGE.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,17 +36,23 @@ the part that matters most.
| 2026-10-01 | erikhfj | opencode | Simplified this log to a table at the group's request |
| 2026-10-01 | robertky | Codex (ChatGPT) | Assisted with formulating good reviews of the architecture and UI-specification PRs. The group decided to include decade filtering; Rachel implemented the corresponding schema and documentation update in #38. |
| 2026-10-07 | erikhfj | opencode | Simulated user identity for #10: a `User` type and the `X-User-Id` header contract, read into a per-request GraphQL context so that no field in `schema.graphql` takes a `userId` argument |
| 2026-10-07 | rachelks | ChatGPT | Assisted with frontend styling, UI decisions and troubleshooting for #9 (PR #47). |
| 2026-10-09 | robertky | Codex (ChatGPT) | AI was a good sparring partner when I drafted the initial #5 PostgreSQL migration. It gave me ideas on how to structure and improve the tables, relation tables, constraints, indexes, full-text search triggers and TypeScript migration runner. |
| 2026-10-09 | erikhfj | opencode | VM runbook for #8, and converted `~/T19-Project-2` from a hand-copied prototype into a real git clone of `main` with a deploy SSH key. The gitignored `.env` was checksummed across `git checkout --force` to prove a deploy does not wipe `DATABASE_URL` |
| 2026-10-10 | evenkkl | Claude | Assisted with implementing the GraphQL Yoga server with `searchAlbums` for #6, and formulated an easy to understand PR description. Guided the reset of the prototype tables in the VM database (backup taken first). |
| 2026-10-10 | erikhfj | opencode | Wrote out the facet-count trade-off on #13: OR within a category pairs with per-dimension exclusion, AND with global counts. Posted as an analysis for the group to settle, not as a decision |
| 2026-10-10 | erikhfj | opencode | Forced `source-map-js` to 1.2.2 through `pnpm.overrides` for #43, after the Dependabot alert |
| 2026-10-10 | rachelks | ChatGPT | Assisted with reviewing PR #42, identifying an issue with the backend deployment workflow that led to #44. |
| 2026-10-10 | erikhfj | opencode | Traced the deploy gap rachelks raised on #42 and opened #44: CI built `server/` in the runner workspace while `crate-api.service` runs `dist/index.js` out of `~/T19-Project-2/server`, so a restart kept bringing back a 23 September prototype |
| 2026-10-12 | erikhfj | opencode | **Tool output corrected by a person.** The draft identity contract said `displayName`, derived server-side from the UUID, stops one user writing as another. It does not: the client can still send any UUID. robertky caught it on review and the wording was fixed in #40 |
| 2026-10-13 | evenkkl | Claude | Fixed the review feedback on #6: cursor values validated against the sort, `reviewCount` returns 0 until reviews exist. The group decided genre filters combine with AND; Claude made the filter and the genre counts match that. |
| 2026-10-15 | rachelks | Codex (ChatGPT) | Assisted with reviewing PRs #45 and #46, identifying issues with deployment checks, database migrations and FTS triggers. Erik and Robert addressed the issues before merging. |
| 2026-10-15 | erikhfj | opencode | Rachel's four review points on #45: the smoke query omitted the required `sort` field so it could never have passed, the deploy step skipped instead of failing, and the body check grepped for the word "errors" instead of parsing JSON. Two bugs in my own first attempt: a multi-line `python3 -c` cannot live inside a YAML block scalar, and `\"` in bash single quotes is a literal backslash |
| 2026-10-15 | rachelks | Codex (ChatGPT) | Assisted with reviewing M2 documentation for #48, identifying outdated setup instructions and missing frontend information. |
| 2026-10-15 | erikhfj | opencode | Documentation pass for #48: this log and the README brought up to date with what has actually landed |
| 2026-10-15 | erikhfj | opencode | Folded #46 into the README, and added `db:migrate` to the deploy on #45 after #46 pointed out it never ran: a deploy that lands migration files without applying them leaves the schema behind the code. Also reconciled `DATABASE_URL`, which the systemd unit reads from the checkout root and the server package scripts read from `server/.env` |
| 2026-10-16 | rachelks | Codex (ChatGPT) | Assisted with updating README and VM setup documentation for #48, clarifying implemented functionality and local development instructions. |
| 2026-10-16 | evenkkl | Claude | Assisted with reviewing PRs #50 and #51, checking the changes against the code and identifying areas for improvement. |

## Notes

Expand Down
27 changes: 23 additions & 4 deletions docs/VM-setup.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,33 @@ DATABASE_URL=postgres://t19:<password>@127.0.0.1:5432/crate
```bash
pnpm install
pnpm --filter @t19/server db:migrate # create the catalog tables
pnpm --filter @t19/server db:seed # replace the catalog with the sample albums
pnpm --filter @t19/server build
pnpm --filter @t19/server start # http://localhost:3001/graphql
```

`db:seed` is a development/reset command. It replaces the catalog and, through
foreign-key cascades, deletes its associated reviews and crate items. Do not run
it against a database with user content you intend to keep.
### Optional sample data

To reset the database with the small sample catalog:

```bash
pnpm --filter @t19/server db:seed
```

**Warning:** This replaces the existing catalog and deletes associated
reviews and crate items. Do not run it against a database containing data
you want to keep.

## Frontend GraphQL endpoint

The frontend uses Apollo Client with `/graphql` as its default endpoint.
On the VM, Apache proxies `/graphql` to the API on port 3001; the frontend's
`/project2/` asset base does not change that endpoint.

For local development, run `pnpm --filter @t19/server dev` and `pnpm dev` in
separate terminals, after configuring the database and applying migrations.
Open <http://localhost:5173/project2/>. Vite proxies `/graphql` to
`http://127.0.0.1:3001`, so both processes must be running. To override the
frontend endpoint, set `VITE_GRAPHQL_URL` in `client/.env.local`.

## Smoke suite

Expand Down