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
1 change: 1 addition & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
* text=auto eol=lf
44 changes: 44 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
name: CI/CD

on:
pull_request:
branches: [main]
push:
branches: [main]

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

jobs:
quality:
name: Format, lint, test, build
runs-on: [self-hosted, linux, x64]
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: 24
cache: npm

- name: Install dependencies
run: npm ci

- name: Check formatting
run: npm run format:check

- name: Lint
run: npm run lint

- name: Test
run: npm test

- name: Build
run: npm run build

- name: Deploy to Apache (main only)
if: github.ref == 'refs/heads/main' && github.event_name == 'push'
run: sudo rsync -a --delete dist/ /var/www/html/project1/
25 changes: 25 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*

node_modules
dist
dist-ssr
coverage
*.local

# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
3 changes: 3 additions & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
dist
coverage
package-lock.json
3 changes: 3 additions & 0 deletions .prettierrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"printWidth": 100
}
79 changes: 79 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
# AGENTS.md

Guidance for AI coding agents and human contributors working on this repository.

## Project

Digital library for IT2810 (NTNU) Project 1. Books are fetched live from the
[OpenLibrary REST API](https://openlibrary.org/developers/api) and presented one at a
time with navigation, filtering, sorting, and favorites.

- TypeScript + React (Vite), plain CSS only, no third-party UI component libraries.
- Data fetching via TanStack Query. The app must fetch on the fly — never persist API
data to disk or bundle it into the repo.
- Node.js 24.x, npm 11.x.

## Commands

| Command | Purpose |
| ---------------------- | ---------------------------------- |
| `npm install` | Install dependencies |
| `npm run dev` | Start dev server |
| `npm run build` | Type-check + production build |
| `npm run lint` | ESLint (must pass with 0 warnings) |
| `npm test` | Vitest, single run |
| `npm run test:watch` | Vitest in watch mode |
| `npm run format` | Prettier, write |
| `npm run format:check` | Prettier, CI check |

Run `npm run lint && npm test && npm run build` before opening a PR. All three must
pass with no errors or warnings.

## Architecture conventions

```
src/
api/ fetch functions for OpenLibrary (no React code here)
hooks/ custom hooks (useBooks, useFavorites, usePreferences)
components/ one component per file, plain function components
test/ Vitest setup (jsdom + jest-dom)
```

- Components are props-driven; keep derived logic in hooks, not JSX.
- All API access goes through `src/api/` and is consumed via TanStack Query hooks.
Configure a sensible `staleTime` so we never send unnecessary API calls.
- Filtering/sorting choices persist in `sessionStorage`; favorites persist in
`localStorage`. Use the storage keys `t19.preferences` and `t19.favorites`, always
JSON-serialized, and tolerate missing/corrupt data.
- Plain CSS files (one per component when needed), imported by the component.
No CSS frameworks, no inline style objects for static styling.

## Code style

- Functional React components with explicit prop types; no `any`.
- Named exports for components; default export only for `App`.
- No comments in code unless genuinely necessary — let names carry the meaning.
- Accessibility is a graded requirement: semantic HTML landmarks, labeled controls,
alt text, visible keyboard focus. `eslint-plugin-jsx-a11y` guards this.

## Testing

- Vitest + React Testing Library. Tests must never hit the network: mock all
OpenLibrary requests with msw handlers.
- Required test types: snapshot tests, component tests over props/state, and
user-interaction tests (clicks, selections).
- When a component's rendered output changes intentionally, update snapshots
deliberately (`vitest -u`) and say so in the PR.

## Git workflow

- `main` is protected. Never push to it — use feature branches and pull requests.
- Branch names: `feat/<issue>-short-name`, `fix/<issue>-short-name`,
`chore/<issue>-short-name`, `docs/<issue>-short-name`.
- Conventional commits: `feat:`, `fix:`, `docs:`, `chore:`, `test:`. Reference the
issue (`Closes #N`) so it links automatically.
- Every PR needs an approving review from another group member and all review
conversations resolved before merge.
- Label issues at creation time using the repo's `type:*`, `area:*`, `priority:*`
labels. Add `ai-assisted` when substantial code was generated with AI assistance,
and document the AI usage in the README.
73 changes: 71 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,44 @@

Repository for team IT2810-H26-T19 in IT2810-H26.

## Project

A digital library where users browse reading material fetched live from the
[OpenLibrary REST API](https://openlibrary.org/developers/api) — one book at a time,
with navigation, subject filtering, sorting, and persistent favorites. Built as the
course project for IT2810 Web Development (NTNU).

## Tech stack

- [Vite](https://vite.dev/) + [React](https://react.dev/) + TypeScript
- [TanStack Query](https://tanstack.com/query) for REST data fetching
- [Vitest](https://vitest.dev/) + React Testing Library + [msw](https://mswjs.io/)
for testing (API requests are always mocked)
- ESLint + Prettier, plain CSS
- npm as package manager — the course environment guide recommends pnpm, but the
project spec explicitly names "Node og npm (og kompatible pakkeverktøy)", so npm
is kept for simplicity

## Getting started

Requires Node.js 24.6+ and npm 11+.

```bash
npm install
npm run dev
```

| Command | Description |
| ---------------------- | ----------------------------- |
| `npm run dev` | Start the dev server |
| `npm run build` | Type-check and build for prod |
| `npm run preview` | Preview the production build |
| `npm run lint` | Run ESLint |
| `npm test` | Run tests once |
| `npm run test:watch` | Run tests in watch mode |
| `npm run format` | Format code with Prettier |
| `npm run format:check` | Check formatting (used in CI) |

## Working in this repository

`main` is protected — you cannot push to it directly. Work on a branch and
Expand All @@ -18,7 +56,38 @@ Before a pull request can be merged:
request, and approvals from staff do not count — you review each other's
code.
2. **Every review comment must be marked resolved.** Reply to each one, fix it
or explain why not, then click *Resolve conversation*.
or explain why not, then click _Resolve conversation_.
3. **Pushing new commits dismisses the approval**, so if you change something
after being approved, ask for another review. This is deliberate: what was
approved is what gets merged.
approved is what gets merged.

### Commits

Use [conventional commit](https://www.conventionalcommits.org/) messages and link
issues so they close automatically:

```
feat: add favorites toggle with localStorage (#42)
```

### Issues and labels

Issues are organized under milestones (M1 Setup → M5 Delivery) and labeled by type
(`type: feature|bug|docs|chore|test`), area (`area: ui|api|storage|styling|a11y`),
and priority. The schedule and current status live in [ROADMAP.md](ROADMAP.md).
Issues where substantial code was AI-generated carry the `ai-assisted` label; AI
usage is documented in the README as required by the course.

## CI

Every pull request runs a GitHub Actions workflow that checks formatting (Prettier),
linting (ESLint), tests (Vitest), and the production build. Everything must pass
with zero errors and warnings before merge.

## Testing

- Snapshot tests of rendered components
- Component tests covering props, state, and user interaction
- Tests never touch the network: msw is installed and will intercept all
OpenLibrary requests once the mock handlers land with the data-layer tests
(#12, milestone M2) and the full suite in M4
44 changes: 44 additions & 0 deletions ROADMAP.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# Roadmap — Project 1: Digital Library

Delivery: **Friday 18 September 2026** (medstudentvurdering by 25/9).
Issues are grouped under milestones. Day-to-day workflow status lives on the
[Kanban board](https://git.ntnu.no/orgs/IT2810-H26/projects/7) (Backlog → Ready →
In progress → In review → Done); issues also carry `status:*` labels.

## Milestones

| Milestone | Due | Scope |
| -------------------------- | -------- | ------------------------------------------------------------------------- |
| M1 — Setup | Thu 3/9 | Template, tooling, CI, types + API client (#1#4) |
| M2 — Core app | Tue 8/9 | BookCard, useBooks, navigation, jump list |
| M3 — Persistence & choices | Fri 11/9 | Subject filter, sorting (sessionStorage), favorites (localStorage) |
| M4 — Quality | Tue 15/9 | Responsive CSS, accessibility, Vitest suite, manual browser/device checks |
| M5 — Delivery | Thu 17/9 | Apache deployment, README, delivery artifacts (#5) |

## Status (updated 4/9)

- PR #3 — template, CI/CD pipeline, docs — **awaiting review** (any team member
can review it)
- #4 — types + API client — implemented and verified (8 tests) on
`feat/4-types-api-client` (pushed); PR opens right after #3 merges
- #11#14 — M2 issues created and assigned: robertky #11 BookCard, erikhfj #12
useBooks + App wiring, evenkkl #13 NavigationControls, rachelks #14 BookJumpList
- #7#10 — closed as not planned: duplicates of work already in #3/#4
- #6 — VM prepped (Apache, rsync, sudoers, runner v2.337.0); registration waits
on repository admin from staff; guide: [docs/ci-runner.md](docs/ci-runner.md)
- #5 — delivery artifacts (timeliste, VM, FeedbackFruits) — open

## Workflow

1. Pick an issue from the current milestone (unassigned, `status: blocked` means wait)
2. Branch: `feat/<issue>-short-name` from `main`
3. Conventional commits referencing the issue
4. PR → teammate review → all conversations resolved → merge
5. Issue auto-closes; PR gets `status: in-review` while waiting

## Delivery checklist (18/9)

Tracked in #5: code + docs on git.ntnu.no, prototype on the group VM (Apache,
[deployment guide](docs/deployment.md) — live at
http://it2810-19.idi.ntnu.no/project1), individual time log for Blackboard,
FeedbackFruits participation.
62 changes: 62 additions & 0 deletions docs/ci-runner.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
# Self-hosted CI runner on the group VM

The NTNU GitHub Enterprise installation (git.ntnu.no) has no shared Actions
runners, so CI runs on a runner registered on the group VM. Tracked in #6.

The VM (`it2810-19.idi.ntnu.no`) is reachable only from the NTNU network or via
VPN, and you have sudo on it. Note that **VM sudo is not the same as repository
admin** — registering the runner needs repo admin.

## Status

- [x] Apache2 installed and enabled on the VM
- [x] rsync installed; `/etc/sudoers.d/github-runner-deploy` grants NOPASSWD
`rsync` to `erikhfj` (used by the CI deploy step)
- [x] Connectivity verified from the VM: git.ntnu.no, github.com, nodejs.org
- [x] Actions runner v2.337.0 downloaded and extracted in `~/actions-runner`
- [ ] Runner registered — **blocked on repository admin**
(requested from `it2810@idi.ntnu.no`)
- [ ] CI green on PR #3, deploy verified after merge to main

## 1. Repository access

Registering a runner requires **repository admin**. If _Settings → Actions_ is
not visible on the repo, email `it2810@idi.ntnu.no` and ask for admin access on
`IT2810-H26/T19-Project-1` (one person per group is enough to register; the
runner serves the whole repo afterwards).

## 2. Install the runner (done)

Downloaded from the official releases —
`https://github.com/actions/runner/releases/download/v2.337.0/actions-runner-linux-x64-2.337.0.tar.gz`
— extracted into `~/actions-runner`. A one-time registration token (valid 1
hour) is fetched from _Settings → Actions → Runners → New self-hosted runner_,
or via `gh api -X POST repos/IT2810-H26/T19-Project-1/actions/runners/registration-token`.

## 3. Register and run as a service (pending admin)

```bash
cd ~/actions-runner
./config.sh --unattended --url https://git.ntnu.no/IT2810-H26/T19-Project-1 --token <TOKEN>
sudo ./svc.sh install
sudo ./svc.sh start
```

`--unattended` accepts the defaults: runner name = hostname, work folder
`_work`, labels `self-hosted`, `linux`, `x64` — which is what `ci.yml` targets.

## 4. Requirements (met)

- Internet access from the VM — verified: git.ntnu.no, github.com (runner +
actions download), nodejs.org (setup-node fetches Node 24 into the tool cache)
- `git`, `curl`, `rsync` installed
- Apache2 installed — pushes to `main` deploy with
`sudo rsync -a --delete dist/ /var/www/html/project1/` (NOPASSWD via the
sudoers entry above)

## 5. Verify

1. The runner shows **Idle** under _Settings → Actions → Runners_
2. Re-run the CI job on PR #3 — it should pick up and complete
3. After PR #3 merges, push to `main` → job deploys `dist/` to Apache → live at
http://it2810-19.idi.ntnu.no/project1
Loading
Loading