Current section

Files

Jump to
voile CHANGELOG.md
Raw

CHANGELOG.md

# Changelog
All notable changes to Voile will be documented in this file.
The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
---
## [0.1.10] - 2026-04-10
### Fixed
- **Critical: Missing fine_per_day causes infinite fine calculation** — If a member type's `fine_per_day` is not set (nil) or set to zero, the system was previously treating it as a zero daily fine, which caused the total fine amount to also be zero regardless of how many days overdue. This could lead to confusion and incorrect fine waivers. The fix is to treat nil or zero `fine_per_day` as a default of 1000 (currency units) per day, ensuring that overdue items accrue fines properly even if the member type configuration is incomplete. This change affects both the fine calculation logic in `Voile.Library.Circulation` and the member type defaults when fetching member type details.
---
## [0.1.9] - 2026-04-10
### Added
- **Requisition workflow** — Added library requisition pages in the frontend and dashboard, including new circulation schema support and requisition helpers.
### Fixed
- **Plugin access control** — Fixed plugin access and dashboard routing so plugin pages now respect the correct authorization rules.
- **Node-scoped circulation actions** — Librarians can no longer Return, Extend, Waive, or Pay items and fines that belong to a different node. In the **Current Loans** tab, the Return and Extend buttons are now replaced with a read-only "Loaned from {Node}" badge when the item's node does not match the librarian's node. In the **Fines** tab, the Waive and Pay buttons are similarly replaced with a "Managed by {Node}" badge for fines originating from another node. Super admins bypass this restriction and always see all action buttons.
---
## [0.1.8] - 2026-04-06
### Added
- **Member identifier display** — The member management table now shows an
`Identifier` column beside `Member Type` for faster lookup.
- **Identifier-aware search** — The members search input now matches identifier
values in addition to name, email, and username.
### Fixed
- **Barcode label rendering** — Label printing now encodes the full stored
barcode value instead of truncating it.
- **Barcode readability** — Increased the barcode value font size and weight on
labels to make long barcode strings easier for librarians to read.
---
## [0.1.7] - 2026-04-05
### Added
- **Contact & Social settings** — Added `app_email`, `app_instagram_url`, and
`app_contact_number` settings (IDs 22–24) to the System Settings dashboard
(`SettingLive`). These are used in email templates and public-facing contact
information. Settings are editable via a new "Contact & Social Settings" form
card on the settings overview page.
- **Dynamic contact info on item detail page** — The "Need Help?" sidebar on
`/items/:id` now reads `app_contact_number` and `app_email` from the settings
store instead of the previously hardcoded values. Each entry is a clickable
link (WhatsApp/tel for contact number, `mailto:` for email) and only renders
if the setting is configured.
### Fixed
- **`mix hex.build` hard-fail on heroicons** — Newer Hex versions reject packages
with non-Hex dependencies. Restored `only: :dev` on the heroicons GitHub dep so
it is excluded from the published package. Added a `files:` whitelist to
`package/0` to also exclude `priv/static/uploads/` and compiled asset bundles,
keeping the tarball well under the 128 MB limit.
- **Production container builds with `heroicons: only: :dev`** — Since heroicons
is now dev-only, `mix deps.get --only prod` no longer fetches it. The
`Containerfile` now has a dedicated `git clone --depth=1` step that fetches
only the `optimized/` SVG tree before `mix assets.deploy`, replicating what
`mix deps.get` previously did. The same fix is applied to `pustaka/Containerfile`.
---
## [0.1.6] - 2026-04-05
### Revert
- Revert publishing Voile to Hex.pm. Planning to only use tags for releases and publishing only in Github.
---
## [0.1.5] - 2026-04-05
### Fixed
- Revert the deps and Containerfile changes from v0.1.4 that were meant for `pustaka` but accidentally got merged into `voile`. The `heroicons` dependency is only needed in `pustaka` for asset compilation, not in `voile`, and the extra `mix deps.get` command is also only needed in `pustaka`. These changes have been re-applied to the correct repo (`pustaka`) in a separate commit.
---
## [0.1.4] - 2026-04-05
### Fixed
- Small fix in mix dependency for heroicons
---
## [0.1.3] - 2026-04-05
### Fixed
- Default Seeds, Visitor Display and other stuffs that should be in the `pustaka` repo, not `voile`, have been moved to the correct repo. This was causing confusion and merge conflicts since `voile` is the core engine and `pustaka` is the GLAM-specific implementation.
---
## [0.1.2] - 2026-04-05
### Added
- Auto-release active locker sessions on visitor checkout when the
`locker_luggage` plugin is installed and the visitor has an active locker
session.
### Fixed
- Guarded plugin settings access to super admins and made the plugin settings
sidebar render correctly when the current plugin is loaded.
- Prevent duplicate hook registrations in `Voile.Hooks` when the same handler
and owner are registered multiple times.
### Changed
- Added `Plugins` to the main dashboard and mobile sidebar navigation.
- Plugin routing now forwards auth state into nested plugin LiveViews so plugin
pages render correctly for current user roles.
- `visitor_identifier` is now included in `:visitor_check_in_panels` hook payloads
for better plugin integration.
---
## [0.1.1] - 2026-04-04
### Fixed
- **Critical: RAM exhaustion on pages using LiveStream tables**`table/1` in
`core_components.ex` had an infinite recursion bug introduced in v0.1.0. The
`LiveStream`-detecting clause called `table(assigns)` after enriching assigns,
but `assigns.rows` was still a `%LiveStream{}`, so the same clause re-matched
forever. Each recursive call allocated a new assigns map, exhausting heap memory
and crashing the process. Fixed by extracting rendering into a private
`do_table/1` that both public clauses delegate to. Affected pages:
`/manage/master/locations` and `/manage/master/member_types`.
- **Performance: settings DB queries on every render**`get_setting_value/2`
was issuing a `Repo.get_by` on every call with no caching. Since settings are
read on every page render (app name, logo, colours) but almost never change,
results are now cached in `:persistent_term`. Cache is invalidated on
`create_setting/1` and `update_setting/2`.
- **Performance: nav bar double DB call** — The `nav_bar` component was calling
`get_setting_value("app_logo_url")` twice per render (once in the `if` guard,
once in the `src` attribute). Reduced to a single call via a temporary assign.
---
## [0.1.0] - 2026-04-04
Initial public release of Voile — a GLAM (Gallery, Library, Archive, Museum)
management system built with Elixir and Phoenix LiveView.
### Catalog
- Collection management with hierarchical structure support
- Item cataloging with customizable metadata resource classes
- MARC-compatible metadata properties system
- Full-text and trigram search across collections and items
- Attachment system for digital assets (polymorphic, multi-type)
- External book search integration (ISBN lookup & enrichment)
- OAI-PMH metadata harvesting endpoint
### Circulation
- Visitor check-in and check-out flow with per-node support
- Member management with borrowing history
- Fine calculation and payment tracking
- Stock opname (inventory count) module with CSV import/export
### Authentication & Access Control
- Role-based access control (RBAC) with GLAM-specific roles:
`super_admin`, `librarian`, `archivist`, `gallery_curator`, `museum_curator`
- `glam_type` scoping — roles constrained to institution type
- `phx.gen.auth`-based authentication with email/password
- OAuth 2.0 / SSO via Assent
- Audit logging with IP, user agent, and session tracking
- Fine-grained collection-level permissions
### GLAM Configuration
- Multi-GLAM instance support (one database, multiple institution profiles)
- Per-GLAM settings and branding
- Node (branch / service desk) management
- Master data management (subjects, classifications, languages, etc.)
### Plugin System
- OTP-application based plugin architecture
- `Voile.Plugin` behaviour contract
- `Voile.Hooks` action/filter system (`:persistent_term`-backed, zero-cost reads)
- `Voile.PluginManager` — install, activate, deactivate, uninstall, update lifecycle
- Per-plugin database migrations via `Voile.Plugin.Migrator`
- Per-plugin settings with a dynamic schema-driven form
- Dynamic plugin routing at `/manage/plugins/:plugin_id/*path`
- Plugin navigation sidebar with `nav/0` callback
- Plugin discovery from loaded OTP applications
### Dashboard & UI
- Phoenix LiveView dashboard with real-time updates
- Analytics overview
- Search dashboard
- Notification system (LiveView push)
- Cloudflare Turnstile CAPTCHA integration
- Dark mode support
### Developer
- Swagger / OpenAPI documentation (`/api/swagger`)
- Phoenix LiveDashboard at `/dev/dashboard` (dev only)
[0.1.7]: https://github.com/curatorian/voile/compare/v0.1.6...v0.1.7
[0.1.2]: https://github.com/curatorian/voile/compare/v0.1.1...v0.1.2
[0.1.1]: https://github.com/curatorian/voile/compare/v0.1.0...v0.1.1
[0.1.0]: https://github.com/curatorian/voile/releases/tag/v0.1.0