Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
c30572a
Add new tables to support the new notfication configuration UI.
iTerminate Feb 16, 2026
7a3837f
Add db entties and facades for the new tables.
iTerminate Feb 16, 2026
7e9b9f9
:recycle: refactor user id to user info
iTerminate Feb 17, 2026
d97626d
:recycle: more refactoring of the variables with id in name.
iTerminate Feb 17, 2026
0771380
Add variables needed for handling the UI for adding notificaiton conf…
iTerminate Feb 17, 2026
2c11f7e
:sparkles: Add improved handling of errors. If the exception happens …
iTerminate Feb 17, 2026
547cffa
Add empty setting object to fulfill the reqiurement of creating a not…
iTerminate Feb 17, 2026
c42c935
Add notification configuration controllers and utility.
iTerminate Feb 17, 2026
6041477
Add view to add notification configurations per user.
iTerminate Feb 17, 2026
c1dc97d
Resolve destroy redirect to list.
iTerminate Feb 19, 2026
9e370d1
Add notification configurations to user settings page.
iTerminate Feb 19, 2026
2cb05a5
Add send test notification to the notification dialog.
iTerminate Feb 19, 2026
aa6c6f2
Add handing of the send test notification button to send it to the ha…
iTerminate Feb 19, 2026
2d2dbd6
:recycle: standardize sending of mqtt event since it is referenced fr…
iTerminate Feb 19, 2026
ec56f32
Add support for handling notification test event.
iTerminate Feb 19, 2026
692c0ee
Add a handler for sending test notification to apprise handler.
iTerminate Feb 19, 2026
25d5dc2
Add a new API for fetching notification configurations.
iTerminate Feb 19, 2026
68cef20
Match the signlar format for route names.
iTerminate Feb 19, 2026
ad98e21
format and add notification configuration api to factory.
iTerminate Feb 19, 2026
0f60b0a
Simplify the return structure of a notification configuration.
iTerminate Feb 19, 2026
317c987
Add details needed to load up the notitication handler.
iTerminate Feb 19, 2026
8ee5260
Use BelyAPIFactory as the API client.
iTerminate Feb 19, 2026
c26f9c1
Update interface.
iTerminate Feb 19, 2026
0558f52
Load the notification configuration from the API.
iTerminate Feb 20, 2026
3aa7b22
Resolve existing handler tests with recent changes.
iTerminate Feb 20, 2026
56f865c
Add a new test to verify that API endpoint parses data correctly.
iTerminate Feb 20, 2026
d9ec528
Resolve linter issues.
iTerminate Feb 20, 2026
748ad37
Fix quality issues.
iTerminate Feb 20, 2026
8f725f4
Update the api publish script for publishing BELY api to pypi.
iTerminate Feb 20, 2026
af099ab
Add the dep for beliy API to the project.
iTerminate Feb 20, 2026
836e1b7
Resolve more quality issues.
iTerminate Feb 20, 2026
b45da5b
Ignore type markers.
iTerminate Feb 20, 2026
483d757
Add handling of automtic reloading of the notification configuration.
iTerminate Feb 23, 2026
1b6240f
Add a notification configuration id for later quick lookup and matchi…
iTerminate Feb 23, 2026
f6097e7
Ensure that the api_url can be specified in the configuration file in…
iTerminate Feb 23, 2026
baa2b48
Add view and handling for unsubcribe permalink that can be provided w…
iTerminate Feb 23, 2026
7234022
Include unsubscribe link with the notifications that can be unsubscri…
iTerminate Feb 23, 2026
fbf4c10
Only allow one instance of the mqtt broker at a time.
iTerminate Feb 24, 2026
e9ef537
Clean up the unsubscribe flow.
iTerminate Feb 24, 2026
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
237 changes: 237 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,237 @@
# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

## Project Overview

BELY (Best Electronic Logbook Yet) is a Java EE web application for electronic logbook management. It is deployed on Payara Server (GlassFish fork) and uses MySQL/MariaDB as its database. The project includes:

- **LogrPortal**: Main Java EE web application (JSF/PrimeFaces frontend + REST API)
- **Python web service**: Python-based web service components
- **MQTT integration**: Python framework for handling MQTT events and notifications
- **CLI utilities**: Command-line tools for searching and querying the system

## Build and Development Commands

### Environment Setup

Always source the environment setup script before running any commands:
```bash
source setup.sh
```

This sets up critical environment variables:
- `LOGR_ROOT_DIR`: Root directory of the repository
- `LOGR_SUPPORT_DIR`: Support software directory (Payara, Java, MySQL, etc.)
- `LOGR_INSTALL_DIR`: Installation directory
- `LOGR_DATA_DIR`: Data directory
- `PYTHONPATH`: Includes `src/python` and Python client paths

### Initial Setup

```bash
# Install support software (Java, Payara, etc.)
make support

# Install MySQL (if needed)
make support-mysql

# Install NetBeans IDE
make support-netbeans

# Create development configuration
make dev-config
```

### Database Management

```bash
# Create clean database with schema
make clean-db

# Create test database with test data
make test-db

# Backup database
make backup

# Development database variants
make clean-db-dev
make backup-dev
```

Database SQL files are located in `db/sql/`:
- `clean/`: Clean database schema initialization scripts
- `test/`: Test data initialization scripts
- `static/`: Static lookup data (e.g., notification providers)
- `updates/`: Database migration scripts (e.g., `updateTo2025.3.sql`)
- `create_logr_tables.sql`: Main table creation script
- `create_stored_procedures.sql`: Stored procedures
- `create_views.sql`: Database views

### Building and Deployment

```bash
# Build the web portal
cd src/java/LogrPortal
ant clean
ant dist

# Deploy to Payara (from project root)
make deploy-web-portal

# Deploy web service
make deploy-web-service

# Undeploy
make undeploy-web-portal
make undeploy-web-service

# Development deployment variants
make deploy-web-portal-dev
make deploy-web-service-dev
```

### Running Tests

```bash
# Run full test suite (backs up DB, deploys test DB, runs tests, restores DB)
make test

# Manual API tests
cd tools/developer_tools/python-client/
pytest test/api_test.py

# Test requirements
pip install -r tools/developer_tools/python-client/test/requirements.txt
```

### Python Web Service Development

```bash
# Start the Python web service
./sbin/cdbWebService.sh
```

Python code is in `src/python/cdb/`.

## Architecture

### Java Package Structure

All Java code is under `src/java/LogrPortal/src/java/gov/anl/aps/logr/`:

**portal** - Main web portal application
- `controllers/` - JSF managed beans for UI logic
- `model/db/entities/` - JPA entity classes (e.g., `Log`, `UserInfo`, `NotificationConfiguration`)
- `model/db/beans/` - EJB facades for database operations (stateless session beans)
- `view/` - View objects and JSF utilities
- `import_export/` - Import/export functionality
- `plugins/` - Plugin support system
- `utilities/` - General utility classes

**rest** - REST API
- `routes/` - JAX-RS resource classes (e.g., `LogbookRoute`, `SearchRoute`)
- `authentication/` - Authentication filters and utilities
- `entities/` - DTO classes for API responses
- `provider/` - JAX-RS providers

**common** - Shared utilities
- `mqtt/` - MQTT integration models and utilities
- `objects/` - Common data objects
- `utilities/` - Shared utility classes
- `search/` - Search functionality

**api** - API client interfaces

### Web Application Structure

Location: `src/java/LogrPortal/web/`

- `views/` - XHTML pages organized by entity type (e.g., `log/`, `userInfo/`, `notificationConfiguration/`)
- `templates/` - XHTML template files
- `resources/` - Static resources (CSS, JavaScript, images)
- `WEB-INF/` - Web application configuration

### Technology Stack

- **Framework**: Java EE 8 (JSF 2.3, EJB 3.2, JPA 2.2, JAX-RS 2.1)
- **UI**: PrimeFaces 11 + PrimeFaces Extensions, OmniFaces 3
- **App Server**: Payara 5.2022.5 (GlassFish fork)
- **Database**: MySQL/MariaDB (driver: mariadb-java-client-3.1.0.jar)
- **ORM**: EclipseLink (JPA implementation)
- **Build**: Apache Ant + NetBeans project
- **API Docs**: Swagger/OpenAPI 2.1.5
- **PDF Generation**: iText 5.5.13.1
- **Markdown**: Flexmark 0.64.8
- **Logging**: Log4j 2.17.0

### MQTT Integration

The MQTT notification framework is a pluggable Python system for handling MQTT events:
- Location: `tools/developer_tools/bely-mqtt-message-broker/`
- Features: Type-safe Pydantic models, topic matching with wildcards, notification handlers (email, Slack, Discord)
- See `tools/developer_tools/bely-mqtt-message-broker/README.md` for details

### Plugins System

BELY supports custom plugins for extending functionality:
- Templates: `tools/developer_tools/logr_plugins/pluginTemplates/`
- Deployment: `make deploy-cdb-plugin` or `make deploy-cdb-plugin-dev`

## Development Workflow

### NetBeans Setup

1. Open NetBeans: `netbeans &`
2. File > Open Project > Select `src/java/LogrPortal`
3. Resolve missing server: Right-click project > "Resolve Missing Server Problem"
4. Add Payara Server pointing to `$LOGR_SUPPORT_DIR/netbeans/payara`
5. Copy MariaDB driver to Payara:
```bash
cp src/java/LogrPortal/lib/mariadb-java-client-3.1.0.jar \
$LOGR_SUPPORT_DIR/netbeans/payara/glassfish/domains/domain1/lib/
```
6. Run project from NetBeans

### Adding New Entities

When adding new database entities (e.g., notification system):

1. Update `db/sql/create_logr_tables.sql` with new table definitions
2. Add static data SQL files to `db/sql/static/` if needed
3. Create JPA `@Entity` class in `portal/model/db/entities/`
4. Create `@Stateless` facade in `portal/model/db/beans/` (extends `AbstractFacade`)
5. Create JSF controller in `portal/controllers/` (extends appropriate base controller)
6. Create XHTML views in `web/views/<entity_name>/`
7. Update database with `make clean-db` or create migration in `db/sql/updates/`

### Database Migrations

Version updates go in `db/sql/updates/updateToYYYY.X.sql` (e.g., `updateTo2025.3.sql`)

## Key Patterns

- **Entity/Facade/Controller**: Standard Java EE pattern - JPA entities, EJB facades for CRUD, JSF controllers for UI
- **Named Queries**: Use JPA `@NamedQuery` annotations on entities for common queries
- **Lazy Loading**: JSF data tables use lazy loading models
- **Session Management**: Session-scoped JSF beans maintain user state
- **REST Authentication**: Token-based auth via `rest/authentication/`
- **MQTT Events**: Notification configurations trigger MQTT messages handled by Python framework

## Important Files

- `Makefile`: Top-level make targets for building, deploying, testing
- `setup.sh`: Environment variable setup (must be sourced)
- `sbin/`: Deployment and utility scripts
- `src/java/LogrPortal/build.xml`: Ant build file
- `src/java/LogrPortal/nbproject/project.properties`: NetBeans project configuration
- `db/sql/create_logr_tables.sql`: Main database schema

## Notes

- The project is also known as "ComponentDB" or "CDB" in some contexts
- Default database name: `logr` (development: `logr_dev`)
- Application URL after deployment: `https://<hostname>:8181/bely` or `https://<hostname>:8181/cdb`
- The main branch is `master` (not `main`)
- Always run database operations and deployments from the repository root after sourcing `setup.sh`
112 changes: 112 additions & 0 deletions db/sql/create_logr_tables.sql
Original file line number Diff line number Diff line change
Expand Up @@ -1200,6 +1200,118 @@ CREATE TABLE `connector_property` (
CONSTRAINT `connector_property_fk2` FOREIGN KEY (`property_value_id`) REFERENCES `property_value` (`id`) ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

--
-- Table `notification_provider`
--

DROP TABLE IF EXISTS `notification_provider`;
CREATE TABLE `notification_provider` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(64) NOT NULL,
`description` varchar(256) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `notification_provider_u1` (`name`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

--
-- Table `notification_configuration`
--

DROP TABLE IF EXISTS `notification_configuration`;
CREATE TABLE `notification_configuration` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(64) NOT NULL,
`description` varchar(256) DEFAULT NULL,
`notification_provider_id` int(11) unsigned NOT NULL,
`notification_endpoint` varchar(256) NOT NULL,
`user_id` int(11) unsigned DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `notification_configuration_u1` (`name`),
KEY `notification_configuration_k1` (`notification_provider_id`),
KEY `notification_configuration_k2` (`user_id`),
CONSTRAINT `notification_configuration_fk1` FOREIGN KEY (`notification_provider_id`) REFERENCES `notification_provider` (`id`) ON UPDATE CASCADE,
CONSTRAINT `notification_configuration_fk2` FOREIGN KEY (`user_id`) REFERENCES `user_info` (`id`) ON UPDATE CASCADE ON DELETE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

--
-- Table `notification_provider_config_key`
--

DROP TABLE IF EXISTS `notification_provider_config_key`;
CREATE TABLE `notification_provider_config_key` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`notification_provider_id` int(11) unsigned NOT NULL,
`config_key` varchar(64) NOT NULL,
`description` varchar(256) DEFAULT NULL,
`is_required` bool NOT NULL DEFAULT 0,
`display_order` int(11) DEFAULT 0,
PRIMARY KEY (`id`),
UNIQUE KEY `notification_provider_config_key_u1` (`notification_provider_id`, `config_key`),
KEY `notification_provider_config_key_k1` (`notification_provider_id`),
CONSTRAINT `notification_provider_config_key_fk1` FOREIGN KEY (`notification_provider_id`) REFERENCES `notification_provider` (`id`) ON UPDATE CASCADE ON DELETE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

--
-- Table `notification_configuration_setting`
--

DROP TABLE IF EXISTS `notification_configuration_setting`;
CREATE TABLE `notification_configuration_setting` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`notification_configuration_id` int(11) unsigned NOT NULL,
`notification_provider_config_key_id` int(11) unsigned NOT NULL,
`config_value` varchar(256) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `notification_configuration_setting_u1` (`notification_configuration_id`, `notification_provider_config_key_id`),
KEY `notification_configuration_setting_k1` (`notification_configuration_id`),
KEY `notification_configuration_setting_k2` (`notification_provider_config_key_id`),
CONSTRAINT `notification_configuration_setting_fk1` FOREIGN KEY (`notification_configuration_id`) REFERENCES `notification_configuration` (`id`) ON UPDATE CASCADE ON DELETE CASCADE,
CONSTRAINT `notification_configuration_setting_fk2` FOREIGN KEY (`notification_provider_config_key_id`) REFERENCES `notification_provider_config_key` (`id`) ON UPDATE CASCADE ON DELETE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

-- ============================================================================
-- Notification Handler Configuration Tables
-- ============================================================================

-- Handler configuration key definitions
-- These define global handler settings like entry_updates, own_entry_edits
DROP TABLE IF EXISTS `notification_handler_config_key`;
CREATE TABLE `notification_handler_config_key` (
`id` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT,
`config_key` VARCHAR(64) NOT NULL COMMENT 'Key name like entry_updates',
`display_name` VARCHAR(64) DEFAULT NULL COMMENT 'Short display name for UI',
`description` VARCHAR(256) DEFAULT NULL,
`value_type` ENUM('boolean', 'string', 'integer') NOT NULL DEFAULT 'boolean',
`default_value` VARCHAR(256) DEFAULT NULL,
`display_order` INT(11) DEFAULT 0,
PRIMARY KEY (`id`),
UNIQUE KEY `notification_handler_config_key_u1` (`config_key`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

-- Per-configuration handler settings
-- Links notification_configuration to handler settings
DROP TABLE IF EXISTS `notification_configuration_handler_setting`;
CREATE TABLE `notification_configuration_handler_setting` (
`id` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT,
`notification_configuration_id` INT(11) UNSIGNED NOT NULL,
`notification_handler_config_key_id` INT(11) UNSIGNED NOT NULL,
`config_value` VARCHAR(256) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `notification_configuration_handler_setting_u1`
(`notification_configuration_id`, `notification_handler_config_key_id`),
KEY `notification_configuration_handler_setting_k1` (`notification_configuration_id`),
KEY `notification_configuration_handler_setting_k2` (`notification_handler_config_key_id`),
CONSTRAINT `notification_configuration_handler_setting_fk1`
FOREIGN KEY (`notification_configuration_id`)
REFERENCES `notification_configuration` (`id`)
ON UPDATE CASCADE ON DELETE CASCADE,
CONSTRAINT `notification_configuration_handler_setting_fk2`
FOREIGN KEY (`notification_handler_config_key_id`)
REFERENCES `notification_handler_config_key` (`id`)
ON UPDATE CASCADE ON DELETE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;


-- Note: CHECK constraint is not supported in MySQL.
-- Hence, we need triggers to verify that at least one of
-- is_used_required/optional is NULL
Expand Down
11 changes: 11 additions & 0 deletions db/sql/static/populate_notification_handler_config_key.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
LOCK TABLES `notification_handler_config_key` WRITE;
/*!40000 ALTER TABLE `notification_handler_config_key` DISABLE KEYS */;
INSERT INTO `notification_handler_config_key` VALUES
(1,'entry_updates', 'Entry Updates', 'Notify document owner when log entries in their document are updated or deleted by others', 'boolean', 'true', 1),
(2,'entry_replies', 'Replies to My Entries', 'Notify original entry creator when someone replies to their log entry, or when replies are updated/deleted on their entry', 'boolean', 'true', 2),
(3,'new_entries', 'New Entries', 'Notify document owner when new log entries are created in their document (excluding entries they create themselves)', 'boolean', 'true', 3),
(4,'document_replies', 'All Document Replies', 'Notify document owner when replies are added, updated, or deleted anywhere in their document', 'boolean', 'true', 4),
(5,'reactions', 'Entry Reactions', 'Notify entry creator when someone adds or removes a reaction (like emoji) to their entry', 'boolean', 'true', 5),
(6,'own_entry_edits', 'Edits to My Entries', 'Notify users when their own entries (or replies they created) are edited or deleted by someone else', 'boolean', 'true', 6);
/*!40000 ALTER TABLE `notification_handler_config_key` ENABLE KEYS */;
UNLOCK TABLES;
6 changes: 6 additions & 0 deletions db/sql/static/populate_notification_provider.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
LOCK TABLES `notification_provider` WRITE;
/*!40000 ALTER TABLE `notification_provider` DISABLE KEYS */;
INSERT INTO `notification_provider` VALUES
(1,'apprise', 'Apprise unified notification library supporting email, Discord, Slack, Teams, etc.');
/*!40000 ALTER TABLE `notification_provider` ENABLE KEYS */;
UNLOCK TABLES;
Loading