Skip to content

Repository files navigation

Onja Library App

An internal library management tool for Onja team members to browse, borrow, and return books — replacing the previous spreadsheet and Google Form workflow.

What it does

  • General users can view and filter books, borrow/return books, favourite books, and leave reviews.
  • Admins can do all of the above, plus add/edit/delete books and manage users (roles and removal).

The app is a single page. General users see the books view only. Admins see two tabs: Books and Admin.

Tech Stack

Layer Technology
Framework Next.js 16 (App Router), TypeScript
Database & Auth Supabase (Postgres, RLS, Google OAuth)
Styling Tailwind CSS v4 — brand tokens in globals.css via @theme
Deployment Vercel

Key files

  • src/types/index.ts — TypeScript interfaces for every entity. Import from here, never redefine types elsewhere.
  • src/lib/supabase.ts — Typed Supabase client. Use for all DB queries.
  • src/hooks/useAuth.ts — Returns the current user, their role, and signOut.
  • src/middleware.ts — Redirects unauthenticated users to /login.
  • SCHEMA.md — Full database schema. Read this before every session.

Branding

Brand tokens are defined in src/app/globals.css via Tailwind v4's @theme block:

--color-onja-navy:    #1B3A6B  /* headers, nav, primary buttons */
--color-onja-red:     #E8401C  /* CTA buttons, active states */
--color-onja-blue:    #2D5FA6  /* hover states, links, focus rings */
--color-onja-offwhite:#F5F5F0  /* page background */
--color-onja-black:   #1A1A1A  /* body text */

Use bg-onja-navy, text-onja-red, border-onja-blue, etc. No generic Tailwind blues or grays.

Font: Inter (loaded via next/font). Headings weight 600–700 in Onja Navy. Body weight 400 in Near Black.

Getting Started

npm install
npm run dev

Open http://localhost:3000.

Copy .env.example to .env.local and fill in your Supabase URL and anon/service keys.

Data Model (summary)

Entity Purpose
books Core book records with genre, library, English level lookups
profiles User profiles linked to Supabase Auth; stores name, avatar, email, role
libraries Lookup table of physical library locations
genres Lookup table to keep genre values consistent
english_levels Lookup table (A1–C2)
borrows Append-only borrow/return history
reviews One review per user per book (rating and/or comment)
favourites Join table between users and books

See SCHEMA.md for full column definitions, indexes, and trigger logic.

Sprint task map

Wave Tasks Notes
1 Task 1 Types + Supabase client — push first, everything depends on it
2 Tasks 2, 4, 6 Auth, books API, BookCard — no cross-dependencies
3 Tasks 3, 5, 7–11, 13–15 Feature components and API routes
4 Task 12 BookModal (composes BorrowButton, FavouriteButton, Reviews)
5 Task 16 Main page — final integration, must be last

Each developer works on feature/task-XX. Import types from src/types/index.ts.

How to Contribute

Branch and PR workflow

  1. Branch from main using the naming convention feature/task-XX (e.g. feature/task-07).
  2. Open a pull request against main when your task is ready for review.
  3. Keep PRs scoped to a single task — don't bundle unrelated changes.

Before you write any code

  • Read SCHEMA.md — every query and type must be grounded in the real database schema.
  • Check src/types/index.ts — import types from here, never redefine them inline.
  • Read the relevant guide in node_modules/next/dist/docs/ — this project uses Next.js 16, which has breaking changes from earlier versions.

Code conventions

  • Supabase client: use src/lib/supabase/client.ts in client components and src/lib/supabase/server.ts in Server Components and Route Handlers.
  • Auth: use src/hooks/useAuth.ts to get the current user and role — don't query profiles directly in components.
  • Styling: Onja brand tokens only (bg-onja-navy, text-onja-red, etc.). No generic Tailwind blues or grays. See the Branding section above.
  • Write operations (add/edit/delete books, user role changes) must be admin-only and use the service role key.
  • Borrow records are append-only — set returned_at on return, never delete rows.
  • favourites_count is maintained by a database trigger — do not update it from the app layer.

Lookup tables

Genres, English levels, and libraries come from lookup tables. Always use the IDs from these tables — never store free text for these fields.

Testing your changes

Run npm run dev and verify your feature end-to-end in the browser before opening a PR. TypeScript errors (npm run build) should be zero.

About

An internal library management tool for Onja team members to browse, borrow, and return books — replacing the previous spreadsheet and Google Form workflow.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages