# Koha-Lite v3.20 — Full Implementation Plan

## Overview

Build a faithful Koha 3.20 prototype in Laravel using the two existing blade design templates as the visual foundation. The project splits into two interfaces that already exist as stubs:

| Interface | Current File | URL | Status |
|---|---|---|---|
| **OPAC** (Public Catalog) | `welcome.blade.php` | `/opac` | Stub — search results view only |
| **Staff Intranet** | `dashboard.blade.php` | `/dashboard` | Stub — SPA with 4 working modules |

The goal is to expand each into a **multi-page, route-driven Laravel application** with a SQLite database behind it — keeping the exact same visual style from both templates.

---

## User Review Required

> [!IMPORTANT]
> All modules will use **mock/seed data** (no real MARC Z39.50 integration). The prototype faithfully represents the Koha 3.20 UI and workflows but is not a real ILS backend.

> [!WARNING]
> The current `goToOPAC()` function in `dashboard.blade.php` opens `window.open('/', '_blank')` which now redirects back to `/dashboard`. This will be fixed by adding a dedicated `/opac` route.

> [!IMPORTANT]
> A **shared layout system** (`layouts/staff.blade.php` and `layouts/opac.blade.php`) needs to be extracted from the two existing monolithic blade files. Every module page will `@extend` these layouts — preserving the visual design with zero duplication.

---

## Architecture

```
koha-lite/
├── routes/web.php                  ← All routes (OPAC + Staff)
├── app/
│   ├── Http/Controllers/
│   │   ├── Staff/                  ← Staff intranet controllers
│   │   └── Opac/                   ← OPAC controllers
│   └── Models/                     ← Eloquent models
├── database/
│   └── migrations/                 ← SQLite schema
├── resources/views/
│   ├── layouts/
│   │   ├── staff.blade.php         ← Extracted from dashboard.blade.php
│   │   └── opac.blade.php          ← Extracted from welcome.blade.php
│   ├── staff/                      ← All staff module pages
│   └── opac/                       ← All OPAC pages
```

---

## Phase 1 — Foundation (Routes + Layouts)

### Goal: Extract shared layouts, fix routing, seed database

---

#### [MODIFY] [web.php](file:///d:/MTU-ONLINE/koha-lite/routes/web.php)

Add all routes. Grouped by interface:

```php
// OPAC routes
Route::prefix('opac')->name('opac.')->group(function () {
    Route::get('/', [OpacController::class, 'home'])->name('home');
    Route::get('/search', [OpacController::class, 'search'])->name('search');
    Route::get('/record/{id}', [OpacController::class, 'detail'])->name('detail');
    Route::get('/account', [OpacController::class, 'account'])->name('account');
    Route::get('/account/holds', [OpacController::class, 'holds'])->name('holds');
    Route::get('/account/history', [OpacController::class, 'history'])->name('history');
    Route::get('/account/fines', [OpacController::class, 'fines'])->name('fines');
    Route::get('/lists', [OpacController::class, 'lists'])->name('lists');
    Route::get('/authorities', [OpacController::class, 'authorities'])->name('authorities');
    Route::get('/tags', [OpacController::class, 'tagcloud'])->name('tagcloud');
});

// Staff Intranet routes
Route::prefix('dashboard')->name('staff.')->group(function () {
    Route::get('/', [StaffController::class, 'home'])->name('home');

    // Circulation
    Route::get('/circulation', [CirculationController::class, 'index'])->name('circulation');
    Route::get('/circulation/checkin', [CirculationController::class, 'checkin'])->name('checkin');
    Route::get('/circulation/renew', [CirculationController::class, 'renew'])->name('renew');
    Route::get('/circulation/holds', [CirculationController::class, 'holds'])->name('holds');
    Route::get('/circulation/overdues', [CirculationController::class, 'overdues'])->name('overdues');

    // Patrons
    Route::get('/patrons', [PatronController::class, 'index'])->name('patrons');
    Route::get('/patrons/create', [PatronController::class, 'create'])->name('patrons.create');
    Route::get('/patrons/{id}', [PatronController::class, 'show'])->name('patrons.show');
    Route::get('/patrons/{id}/edit', [PatronController::class, 'edit'])->name('patrons.edit');
    Route::get('/patrons/{id}/account', [PatronController::class, 'account'])->name('patrons.account');

    // Cataloging
    Route::get('/cataloging', [CatalogingController::class, 'index'])->name('cataloging');
    Route::get('/cataloging/create', [CatalogingController::class, 'create'])->name('cataloging.create');
    Route::get('/cataloging/{id}', [CatalogingController::class, 'show'])->name('cataloging.show');
    Route::get('/cataloging/{id}/edit', [CatalogingController::class, 'edit'])->name('cataloging.edit');
    Route::get('/cataloging/z3950', [CatalogingController::class, 'z3950'])->name('cataloging.z3950');
    Route::get('/cataloging/import', [CatalogingController::class, 'import'])->name('cataloging.import');

    // Acquisitions
    Route::get('/acquisitions', [AcquisitionsController::class, 'index'])->name('acquisitions');
    Route::get('/acquisitions/vendors', [AcquisitionsController::class, 'vendors'])->name('acquisitions.vendors');
    Route::get('/acquisitions/orders', [AcquisitionsController::class, 'orders'])->name('acquisitions.orders');
    Route::get('/acquisitions/budgets', [AcquisitionsController::class, 'budgets'])->name('acquisitions.budgets');

    // Serials
    Route::get('/serials', [SerialsController::class, 'index'])->name('serials');
    Route::get('/serials/{id}', [SerialsController::class, 'show'])->name('serials.show');

    // Reports
    Route::get('/reports', [ReportsController::class, 'index'])->name('reports');
    Route::get('/reports/{type}', [ReportsController::class, 'run'])->name('reports.run');

    // Tools
    Route::get('/tools', [ToolsController::class, 'index'])->name('tools');
    Route::get('/tools/batch-edit', [ToolsController::class, 'batchEdit'])->name('tools.batch');
    Route::get('/tools/labels', [ToolsController::class, 'labels'])->name('tools.labels');
    Route::get('/tools/inventory', [ToolsController::class, 'inventory'])->name('tools.inventory');
    Route::get('/tools/notices', [ToolsController::class, 'notices'])->name('tools.notices');
    Route::get('/tools/patron-import', [ToolsController::class, 'patronImport'])->name('tools.patron-import');

    // Authorities
    Route::get('/authorities', [AuthoritiesController::class, 'index'])->name('authorities');
    Route::get('/authorities/{id}', [AuthoritiesController::class, 'show'])->name('authorities.show');

    // Administration
    Route::get('/administration', [AdministrationController::class, 'index'])->name('administration');
    Route::get('/administration/preferences', [AdministrationController::class, 'preferences'])->name('admin.preferences');
    Route::get('/administration/libraries', [AdministrationController::class, 'libraries'])->name('admin.libraries');
    Route::get('/administration/item-types', [AdministrationController::class, 'itemTypes'])->name('admin.item-types');
    Route::get('/administration/patron-categories', [AdministrationController::class, 'patronCategories'])->name('admin.patron-categories');
    Route::get('/administration/circ-rules', [AdministrationController::class, 'circRules'])->name('admin.circ-rules');
    Route::get('/administration/marc-frameworks', [AdministrationController::class, 'marcFrameworks'])->name('admin.marc-frameworks');
});
```

#### [NEW] `layouts/staff.blade.php`
Extracted from `dashboard.blade.php` — contains topnav, header (patron lookup), breadcrumb, footer, and all CSS/JS. Pages `@yield('content')` and `@yield('breadcrumb-trail')`.

#### [NEW] `layouts/opac.blade.php`
Extracted from `welcome.blade.php` — contains top utility bar, logo header, search bar, sub-nav, breadcrumb, footer, CSS. Pages yield content and sidebar.

---

## Phase 2 — Database Schema (Migrations)

### All tables backed by SQLite, seeded with MTU Library mock data

| Migration | Table | Key columns |
|---|---|---|
| `create_libraries_table` | `libraries` | id, branchcode, name, address, phone |
| `create_item_types_table` | `item_types` | id, code, description, loan_period, fine_rate |
| `create_patron_categories_table` | `patron_categories` | id, code, description, enrolment_period, max_checkouts |
| `create_patrons_table` | `patrons` | id, cardnumber, firstname, surname, email, category_id, library_id, expiry_date |
| `create_biblios_table` | `biblios` | id, title, author, isbn, publisher, pub_year, subject, call_number, cover_url |
| `create_items_table` | `items` | id, biblio_id, barcode, library_id, item_type_id, location, status (available/checkedout/lost) |
| `create_issues_table` | `issues` | id, patron_id, item_id, issuedate, date_due, returndate |
| `create_holds_table` | `holds` | id, patron_id, biblio_id, item_id, reservedate, status, priority |
| `create_fines_table` | `fines` | id, patron_id, issue_id, amount, fine_type, due_date |
| `create_orders_table` | `orders` | id, vendor_id, biblio_id, quantity, price, status |
| `create_vendors_table` | `vendors` | id, name, address, contact, active |
| `create_budgets_table` | `budgets` | id, name, amount, spent, period |
| `create_subscriptions_table` | `subscriptions` | id, biblio_id, frequency, start_date, end_date, vendor_id |
| `create_authorities_table` | `authorities` | id, type (personal/corporate/geographic/subject), heading, see_also |
| `create_news_table` | `news` | id, title, content, published_date, library_id, active |
| `create_system_preferences_table` | `system_preferences` | id, module, variable, value, type, options |

---

## Phase 3 — OPAC (Public Catalog) Pages

Using **`layouts/opac.blade.php`** design. All pages match the existing `welcome.blade.php` visual style.

### 3a. Home Page — `opac/home.blade.php`
- Welcome message + library news (from `news` table)
- Popular searches as clickable tags
- New arrivals section (latest 5 `biblios`)
- Left sidebar: Quick Links, Online Resources (AGORA, JSTOR, HINARI, EBSCOhost)

### 3b. Search Results — `opac/search.blade.php`
- Query from `?q=` param, searches `biblios` + `items`
- Result count header: _"You searched: **X** returned N results"_
- Per-result: title link, author, publisher/year, availability badge (Available/Checked Out)
- Toolbar: Select All, Clear All, Add to Cart/List, Sort (newest/oldest/relevance/title/author)
- Left sidebar: Refine facets — Availability, Libraries, Authors, Subject, Item Type, Year
- Pagination: Previous / 1 2 3 … / Next
- Fade-in animation on results (already in existing CSS)

### 3c. Record Detail — `opac/detail.blade.php`
- Full bibliographic display: Title, Author, Publisher, ISBN, Subject headings (linked), Call number
- Cover image (or placeholder `no-cover` div from existing CSS)
- **Holdings table**: Barcode, Library, Location, Item Type, Status per item
- Action buttons: Place Hold (if all copies checked out), Add to Cart, Add to List
- Enhanced content tabs: Description | Reviews | Tags
- "Report a problem" link

### 3d. Patron Account — `opac/account.blade.php`
Tabbed interface matching existing tab CSS:

| Tab | Content |
|---|---|
| **Summary** | Checkouts count, Overdues, Holds, Fines balance |
| **Checkouts** | Table of current items out — Title, Due Date, Renew button, Overdue tag |
| **Holds** | Active holds — Title, Placed Date, Status (Waiting/In Transit/Pending), Cancel button |
| **Fines** | Outstanding charges table — Date, Reason, Amount, Status |
| **Reading History** | Past borrowing — Title, Author, Checkout Date, Return Date |
| **Personal Details** | Name, Address, Card number, Expiry, Category — with "Request change" link |

### 3e. Lists — `opac/lists.blade.php`
- Public and private virtual shelves
- Table: List name, Owner, Num items, Privacy, Actions

### 3f. Authority Search — `opac/authorities.blade.php`
- Search by heading, type (personal name / corporate / subject / geographic)
- Results table with heading and "See also" links

### 3g. Tag Cloud — `opac/tagcloud.blade.php`
- Visual word cloud of subject tags; click filters search

---

## Phase 4 — Staff Intranet Pages

Using **`layouts/staff.blade.php`** design. All pages match existing `dashboard.blade.php` visual style.

### 4a. Dashboard Home — `staff/home.blade.php`
- Module grid (already designed — keep as-is)
- Left sidebar news widget (pull from `news` DB table, not hardcoded)

### 4b. Circulation Module

#### `staff/circulation/index.blade.php` — Check Out
- Patron quick-lookup (card/name → show patron info bar)
- Item barcode scan → checkout
- Currently checked-out items table with Renew/Return actions
- Overdue indicator (red tag)

#### `staff/circulation/checkin.blade.php` — Check In
- Barcode input → mark item returned
- Shows: Item title, Patron who had it, Due date, Days overdue, Fine calculated

#### `staff/circulation/holds.blade.php` — Holds Queue
- Filterable table: Title, Patron, Priority, Date Placed, Status
- Bump/Lower priority buttons

#### `staff/circulation/overdues.blade.php` — Overdues
- Table of all overdue items: Patron, Title, Due Date, Days Overdue, Fine, Notify button

### 4c. Patrons Module

#### `staff/patrons/index.blade.php` — Search & List
- Search form (name, card, email, category, library)
- Results table: Name, Card, Category, Library, Items Out, Expiry, Actions

#### `staff/patrons/show.blade.php` — Patron Detail
Tabbed layout:

| Tab | Content |
|---|---|
| **Checkouts** | Current items, due dates, renew buttons |
| **Holds** | Active holds, cancel/suspend |
| **Fines** | Outstanding + paid fines |
| **Details** | Personal info, addresses, guarantors |
| **Account** | Login history, messaging preferences |
| **Statistics** | Lifetime checkouts, most borrowed subjects |

#### `staff/patrons/create.blade.php` — New Patron Form
- Category, Library, Personal info, Card number (auto-generate or manual)
- Address, Email, Phone, Expiry date
- Messaging preferences checkboxes

#### `staff/patrons/edit.blade.php` — Edit Patron

### 4d. Cataloging Module

#### `staff/cataloging/index.blade.php` — Search Catalog (staff view)
- Advanced search: Title, Author, ISBN, Call Number, Subject, Publisher
- Results with Edit / View / Delete actions

#### `staff/cataloging/show.blade.php` — Record Detail (staff)
- Full MARC-style field display (tag, subfield, value in table)
- Holdings: all items, with barcode, location, status, edit item link
- Actions: Edit record, Add item, MARC preview, Delete

#### `staff/cataloging/create.blade.php` — New Record (MARC form)
- MARC framework selector (dropdown)
- Field-by-field form: 020 ISBN, 100 Author, 245 Title, 260 Publisher, 300 Physical desc, 500 Notes, 650 Subject
- Save / Cancel buttons

#### `staff/cataloging/z3950.blade.php` — Z39.50 Import
- Search remote databases (mocked: Library of Congress, British Library)
- Results list with "Import this record" button
- Simulated import → redirects to edit form

### 4e. Acquisitions Module

#### `staff/acquisitions/index.blade.php` — Dashboard
- Summary cards: Open Orders, Pending Invoices, Budgets by fund
- Recent orders table

#### `staff/acquisitions/vendors.blade.php` — Vendors
- List: Vendor name, Contact, Active orders, Actions
- "Add vendor" form

#### `staff/acquisitions/orders.blade.php` — Orders
- Filter by vendor, status (pending/received/cancelled), date range
- Table: Order #, Title, Vendor, Qty, Unit price, Fund, Status, Received date

#### `staff/acquisitions/budgets.blade.php` — Budgets & Funds
- Budget period selector
- Table: Fund name, Allocated, Spent, Remaining, % used (progress bar)

### 4f. Serials Module

#### `staff/serials/index.blade.php` — Subscriptions List
- Table: Title, Vendor, Frequency, Start/End Date, Last Received, Status

#### `staff/serials/show.blade.php` — Subscription Detail
- Subscription metadata panel
- Issues table: Issue #, Expected Date, Received Date, Status (Expected/Received/Late/Missing), Notes
- "Receive issues" form + "Claim missing" button

### 4g. Reports Module

#### `staff/reports/index.blade.php` — Reports List
- Pre-built reports table: Name, Category, Last Run, Run button
- Categories: Circulation, Catalog, Patrons, Acquisitions, Serials

#### `staff/reports/run.blade.php` — Report Results
- Report name header + parameter filters (date range, library)
- Results in sortable table
- Export as CSV button (client-side download via JS blob)

Reports to implement (all with mock data):
| Report | Output |
|---|---|
| Circulation statistics | Checkouts by month bar chart |
| Overdues | Patron + item + days overdue table |
| Most borrowed items | Title + checkout count |
| Patrons with no checkouts | Patron table filtered |
| Catalog statistics | Item count by type/library |
| Acquisitions by fund | Budget spend breakdown |

### 4h. Tools Module

#### `staff/tools/index.blade.php` — Tools Menu
- Grid of tool cards (matches module-btn style)

#### `staff/tools/batch-edit.blade.php` — Batch Item Modification
- Upload barcode list or search to build item set
- Bulk-change: Location, Item type, Status, Library
- Preview changes → Apply

#### `staff/tools/labels.blade.php` — Label Printing
- Select items by barcode or search
- Label template: call number, barcode, library name
- Print-ready layout (CSS print media query)

#### `staff/tools/inventory.blade.php` — Inventory
- Scan barcodes to mark items as "seen"
- Missing items list (in catalog but not scanned)

#### `staff/tools/notices.blade.php` — Notices & Slips
- List of notice templates: Overdue 1st, Overdue 2nd, Hold Ready, Checkout slip
- Edit notice HTML/text template

#### `staff/tools/patron-import.blade.php` — Patron Import
- CSV upload form with column mapping
- Preview first 10 rows
- Import with error log

### 4i. Authorities Module

#### `staff/authorities/index.blade.php` — Authority Search
- Search by type (Personal name / Corporate body / Geographic / Subject) + heading text
- Results table with "View / Edit" links

#### `staff/authorities/show.blade.php` — Authority Record
- Heading, Authority type, Used for / See from references, Associated biblio records count

### 4j. Administration Module

#### `staff/administration/index.blade.php` — Admin Home
- Category cards: Libraries, Item Types, Patron Categories, Circulation Rules, MARC Frameworks, System Preferences, Z39.50

#### `staff/administration/preferences.blade.php` — System Preferences
- Tabbed by module: OPAC / Circulation / Cataloging / Acquisitions / Serials / Patrons / Logs
- Per-preference: label, description, control (toggle / text / dropdown), Save

#### `staff/administration/libraries.blade.php`
- Table: branchcode, name, address, phone, email
- Add/Edit/Delete inline

#### `staff/administration/item-types.blade.php`
- Table: code, description, loan period, overdue fine rate, renewal limit
- Add/Edit form

#### `staff/administration/patron-categories.blade.php`
- Table: code (ST/STAFF/AC), description, max checkouts, enrolment period
- Add/Edit form

#### `staff/administration/circ-rules.blade.php` — Circulation Matrix
- Matrix table: rows = patron categories, cols = item types
- Per-cell: loan period, renewals allowed, holds allowed, fines
- `AllowOnShelfHolds` + `OpacItemHolds` toggles (3.20 specific feature)

#### `staff/administration/marc-frameworks.blade.php`
- Table of MARC frameworks: Default, Fast add, Serials, etc.
- "Edit tags" link → tag list with subfields

---

## Phase 5 — `/opac` Route Fix

#### [MODIFY] [web.php](file:///d:/MTU-ONLINE/koha-lite/routes/web.php)

```php
// Fix / and add /opac
Route::get('/', fn() => redirect('/dashboard'));
Route::get('/opac', fn() => redirect('/opac/'));
```

Fix `dashboard.blade.php` line 923:
```js
// Before
function goToOPAC() { window.open('/', '_blank'); }
// After
function goToOPAC() { window.open('/opac', '_blank'); }
```

---

## Verification Plan

### Manual Page-by-Page Verification
- Visit every route; confirm layout loads without errors
- Confirm breadcrumb trail updates per page
- Confirm sidebar context switches (OPAC search vs home sidebar)
- Confirm `goToOPAC()` opens OPAC in new tab

### Data Integrity Checks
- Patron with checkouts shows correct item count
- Overdue items flagged in red
- Budget "spent" sum matches orders total

### Print Test
- Tools > Labels page — trigger browser print, confirm barcode label layout

---

## Implementation Order (Recommended Phases)

```mermaid
gantt
    title Koha-Lite Build Order
    dateFormat  YYYY-MM-DD
    section Phase 1 — Foundation
    Extract layouts           :p1a, 2026-07-05, 1d
    Fix routes + /opac        :p1b, after p1a, 1d
    section Phase 2 — Database
    Write all migrations      :p2a, after p1b, 2d
    Write seeders             :p2b, after p2a, 1d
    section Phase 3 — OPAC
    Home + Search + Detail    :p3a, after p2b, 2d
    Patron Account pages      :p3b, after p3a, 1d
    Lists + Authorities + Tags:p3c, after p3b, 1d
    section Phase 4 — Staff
    Circulation (full)        :p4a, after p3c, 2d
    Patrons (full)            :p4b, after p4a, 2d
    Cataloging (full)         :p4c, after p4b, 2d
    Acquisitions + Serials    :p4d, after p4c, 2d
    Reports + Tools           :p4e, after p4d, 2d
    Authorities + Admin       :p4f, after p4e, 2d
```

**Total estimated scope:** ~35 blade views, ~12 controllers, ~16 DB migrations, ~6 seeders.
