Project structure
A tour of the repository: what each folder and package contains and where to look when you want to change something. Architecture explains how the parts work together; this page is the map.
Repository root
Marginalia/
├── marginalia/ the application - a Maven project (see below)
│ └── plugins/ bundled extensions, one Maven project each
├── manual/ sources of this manual (Retype, Markdown)
│ └── images/ screenshots used by the manual and the READMEs
├── docs/ generated manual, served by GitHub Pages - don't edit by hand
├── screenshots/ scripted environment that takes the pictures of the manual (see its SCREENSHOTS.md)
├── tools/ check_dev_docs.py (stale developer pages), annotate_ui_maps.py (labels of the UI map figures), retype_build.sh (builds the manual into docs/ with the version in the label and footer)
├── .github/workflows/
│ ├── desktop.yml CI: tests, desktop builds for 5 platforms, release upload
│ └── server.yml CI: WAR, plugin JARs, Docker image (ghcr.io), release upload
├── pom.xml parent POM: the version of the application and the plugins, lists them as modules
├── Dockerfile two-stage build: Maven builder → Jetty 12 image
├── docker-compose.yml the server setup (port 8080, ./data volume, JVM options)
├── rebuild.sh, rebuild.bat update a Docker server: pull, build the plugins, copy them to data/extensions, restart
├── retype.yml manual configuration (input manual/, output docs/)
├── README.md, LICENSE
├── CHANGELOG.MD user- and plugin-visible changes, per release
├── TODO.md release plan
├── TODO.BUGS.md known bugs
└── TODO.IMAGES.md screenshots not taken by the scripts
The application (marginalia/)
marginalia/
├── pom.xml dependencies, build plugins, the desktop profile
├── src/main/java/ application code
├── src/main/resources/ Spring XML, Flyway migrations, logback, Vaadin build info
├── src/main/resources-release/ WAR-only resources: the release logback.xml
├── src/main/resources-raw/ copied into WEB-INF/classes without filtering (empty)
├── src/main/webapp/config/ configuration.properties, persistence.xml
├── src/main/frontend/ CSS and JavaScript for the Vaadin frontend
├── src/desktop/ desktop launcher and launch scripts (not part of the WAR)
├── src/test/ tests
└── plugins/ bundled extensions
The root pom.xml is the parent POM and lists the application and every plugin as modules, so mvn package there builds
all of them; each plugin is also a Maven project that is built on its own. See Building from source.
Java packages
Application code lives in com.github.enerccio.marginalia (paths below are relative to
src/main/java/com/github/enerccio/marginalia/), plus a few helpers in com.github.enerccio.tools.
Top level
bound - startup and sessions
ui - user interface
domain.model - entities
User and Permission are in domain.security.model, PermissionType in domain.security.permissions. Every entity must also be listed in src/main/webapp/config/persistence.xml.
See Domain model.
domain.repository - data access
One interface and one JPA implementation (impl/Jpa*Repository) per entity, built on BaseRepository →
OwnedRepository → ExtendableRepository (and JpaBaseRepository → ...). The beans are defined in
services-config.xml with the shared EntityManager. FolderRepository / JpaFolderRepository come with FolderScope (the folder clause of the list queries) and FolderModification (the Last modified of the folders). ManuscriptStatisticRepository, ActivityIntervalRepository and ManuscriptSizeRepository (the statistics) share the queries of impl/StatisticQueries (the filter of a StatisticFilter as a where).
domain.components - plain data and helpers
Small classes that are neither entities nor services, shared by services, generation steps and the UI. No Spring beans, no state besides their fields.
domain.service - business logic
Interfaces in domain.service, implementations in domain.service.impl:
Also here: CancellationToken, GenerationListener (UI
callbacks of a generation) and search/ (Sorter, ManuscriptFilterValues for the book lists; FulltextQuery, FulltextHit and LikePatterns for the full-text search and LIKE patterns).
See Services and Generation pipeline.
domain.templates - prompts
See Templating & macros.
export - story export
See Story export.
domain.security
model/User, repository/UserRepository (+ impl/JpaUserRepository), service/UserService (+
impl/UserServiceImpl: authentication, password hashes, saved logins, protection of the last administrator),
model/Permission with permissions/PermissionType (what an administrator allowed a user to do), repository/PermissionRepository (+ impl/JpaPermissionRepository) and service/PermissionService (+ impl/PermissionServiceImpl, see Permissions),
AdminGuard (requireAdmin(), used by the administrator-only services, see Services) and
PersistedLoginInfo (a saved login; the user's saved logins are stored as delimited text in User.savedLogins).
domain.traits, domain.collections, domain.listener
Extensions, localization, helpers
Resources and configuration
Frontend (src/main/frontend/)
There is no hand-written frontend application - Vaadin generates it. The only sources are:
Generated and ignored by Git: src/main/frontend/generated/, src/main/frontend/index.html, the development bundle
in src/main/bundles/, node_modules/, package.json and the Vite configuration.
Desktop app (src/desktop/)
Built only by the desktop profile. See Packaging & releases.
Tests (src/test/)
Test classes mirror the areas they cover (paths relative to src/test/java/com/github/enerccio/marginalia/):
src/test/resources/META-INF/spring/test-application-config.xml is the test variant of the Spring configuration and
macro-test.json a lorebook fixture. See Testing.
Plugins (marginalia/plugins/)
Each plugin is a Maven project with bundle packaging and the same layout:
plugins/<name>/
├── pom.xml depends on io.github.enerccio:marginalia:1.5.0:classes (provided)
├── README.md user documentation
└── src/main/java/com/github/enerccio/marginalia/extensions/<name>/
├── <Name>Activator.java OSGi BundleActivator - registers the extension service
├── <Name>Extension.java MarginaliaExtension - registers decorators on load, removes them on unload
├── model/ data kept in entity attributes
├── service/ plugin logic
└── ui/ components added to the UI
plugins/Dockerfile and plugins/docker-compose.yml build all of them in a container (JARs end up in plugins/build/,
ignored by Git), see Packaging.
See Plugin development.