Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
baa4c3d
create seeders
mariscalromeroalejandro Oct 7, 2025
75d1e3b
database configuration
mariscalromeroalejandro Oct 7, 2025
01205fe
mapper to patch a layout
mariscalromeroalejandro Oct 7, 2025
fc6dbe1
layout service helpers to keep the database synchronized
mariscalromeroalejandro Oct 7, 2025
f2de380
Merge branch 'dev' into feature/QCG/OGUI-1620/sequelize-seeders
mariscalromeroalejandro Oct 8, 2025
380002b
make database intialization optional
mariscalromeroalejandro Oct 8, 2025
8a05af1
update readme
mariscalromeroalejandro Oct 8, 2025
a4f8b28
add jsdoc to seeders
mariscalromeroalejandro Oct 8, 2025
1eef828
Merge branch 'dev' into feature/QCG/OGUI-1620/layout-management-services
mariscalromeroalejandro Oct 8, 2025
a5bf414
create services to interact with the repositories
mariscalromeroalejandro Oct 8, 2025
41371bd
Merge branch 'dev' into feature/QCG/OGUI-1620/layout-management-services
mariscalromeroalejandro Oct 10, 2025
a41f05f
Potential fix for code scanning alert no. 260: Superfluous trailing a…
mariscalromeroalejandro Oct 10, 2025
48beefb
Potential fix for code scanning alert no. 265: Unused variable, impor…
mariscalromeroalejandro Oct 10, 2025
2829840
Revert changes to QCObjectService since the services created in this …
mariscalromeroalejandro Oct 13, 2025
8a04046
fix layout service tests
mariscalromeroalejandro Oct 13, 2025
17b6a09
Merge remote-tracking branch 'origin/dev' into feature/QCG/OGUI-1620/…
mariscalromeroalejandro Oct 20, 2025
c5d2f50
Synchronizers initialization
mariscalromeroalejandro Oct 20, 2025
d61844d
adapt User controller
mariscalromeroalejandro Oct 20, 2025
fb85db3
updated layout controller
mariscalromeroalejandro Oct 20, 2025
b28ed81
update middlewares
mariscalromeroalejandro Oct 20, 2025
0947b23
update qcobjectservice
mariscalromeroalejandro Oct 20, 2025
63a1303
refactor api to use new services and updated middlewares
mariscalromeroalejandro Oct 20, 2025
ddcd09e
refactor layout middleware tests
mariscalromeroalejandro Oct 20, 2025
fb62519
map ids properly
mariscalromeroalejandro Oct 21, 2025
545d178
Merge branch 'feature/QCG/OGUI-1620/layout-management-services' into …
mariscalromeroalejandro Oct 21, 2025
3ebb6d0
add root password for healthcheck access
mariscalromeroalejandro Oct 21, 2025
db340d8
Merge branch 'feature/QCG/OGUI-1620/sequelize-seeders' into feature/Q…
mariscalromeroalejandro Oct 23, 2025
d828c86
Merge branch 'feature/QCG/OGUI-1620/layout-management-services' into …
mariscalromeroalejandro Oct 23, 2025
a82e894
align seeders to tests
mariscalromeroalejandro Oct 24, 2025
68b9319
refactor LayoutService methods and add getLayoutByName
mariscalromeroalejandro Oct 24, 2025
f5736c8
refactor tab/chart/grid synchronizers
mariscalromeroalejandro Oct 24, 2025
50db698
allow +-5ms margin
mariscalromeroalejandro Oct 24, 2025
a39d071
Merge branch 'feature/QCG/OGUI-1620/sequelize-seeders' into feature/Q…
mariscalromeroalejandro Oct 24, 2025
b918cba
Merge branch 'feature/QCG/OGUI-1620/layout-management-services' into …
mariscalromeroalejandro Oct 24, 2025
4844f80
refactor layout controller and id validation
mariscalromeroalejandro Oct 24, 2025
fb3f66a
fix findLayoutsByFilters to support more filters
mariscalromeroalejandro Oct 24, 2025
b053400
remove objectId generator as it will be set by the repository, layout…
mariscalromeroalejandro Oct 24, 2025
fc7cc69
update api tests
mariscalromeroalejandro Oct 24, 2025
ec0a7eb
add mocks and configuration
mariscalromeroalejandro Oct 24, 2025
2cfb1a9
frontend tests
mariscalromeroalejandro Oct 24, 2025
8179b70
add ownerUsername, fix layout navigation, and allow empty id in valid…
mariscalromeroalejandro Oct 24, 2025
b8fed02
fix lint error
mariscalromeroalejandro Oct 24, 2025
1eea374
load item after save to get the created ids
mariscalromeroalejandro Oct 24, 2025
084f6c6
fix tests to return id created
mariscalromeroalejandro Oct 24, 2025
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
2 changes: 2 additions & 0 deletions QualityControl/config-default.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ export const config = {
timezone: '+00:00',
logging: false,
retryThrottle: 5000,
//forceSeed: true, --- ONLY IN DEVELOPMENT ---
//drop: true, --- ONLY IN DEVELOPMENT ---
},
bookkeeping: {
url: 'http://localhost:4000', // local insance
Expand Down
2 changes: 1 addition & 1 deletion QualityControl/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ services:
target: /docker-entrypoint-initdb.d
# Max total time for the container to start 2 mins (20s + 5*20s)
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-p${MYSQL_ROOT_PASSWORD:-cern}"]
interval: 20s
timeout: 20s
retries: 5
Expand Down
30 changes: 17 additions & 13 deletions QualityControl/docs/Configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -86,16 +86,20 @@ qc: {
### Database Configuration

The application requires the following database configuration parameters:
| **Field** | **Description** |
|-----------------|---------------------------------------------------------------------------------------------|
| `host` | Hostname or IP address of the database server. |
| `port` | Port number used to connect to the database server. |
| `username` | Username for authenticating with the database. |
| `password` | Password for the specified database user. |
| `database` | Name of the database to connect to. |
| `charset` | Character encoding used for the connection. |
| `collate` | Collation setting used for string comparison and sorting. |
| `timezone` | Time zone used for all date/time values in the database connection. |
| `logging` | Enables or disables SQL query logging (useful for debugging). |
| `retryThrottle` | Time in milliseconds to wait before retrying a failed database connection. |
| `migrationSeed` | *(Optional)* Set to `true` to execute seeders that populate the database with mock data. |

| **Field** | **Type** | **Description** | **Default Value** |
|-----------------|-------------|---------------------------------------------------------------------------------------------|---------------------------|
| `host` | `string` | Hostname or IP address of the database server. | `'database'` |
| `port` | `number` | Port number used to connect to the database server. | `3306` |
| `username` | `string` | Username for authenticating with the database. | `'cern'` |
| `password` | `string` | Password for the specified database user. | `'cern'` |
| `database` | `string` | Name of the database to connect to. | `'qcg'` |
| `charset` | `string` | Character encoding used for the connection. | `'utf8mb4'` |
| `collate` | `string` | Collation setting used for string comparison and sorting. | `'utf8mb4_unicode_ci'` |
| `timezone` | `string` | Time zone used for all date/time values in the database connection. | `'+00:00'` |
| `logging` | `boolean` | Enables or disables SQL query logging (useful for debugging). | `false` |
| `retryThrottle` | `number` | Time in milliseconds to wait before retrying a failed database connection. | `5000` |
| `forceSeed` | `boolean` | (for dev mode) Force seeding the database with mock data. **Warning:** Not recommended for production use. | `false` |
| `drop` | `boolean` | (for dev mode) Force deleting the data from the database when server starts. **Warning:** This will erase all data—never use in production. | `false` |

To know more about the database configuration, please go to: [Database Setup](./Database.md)
79 changes: 79 additions & 0 deletions QualityControl/docs/Database.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
# Database Setup and Configuration

This document explains how to set up and configure the database for development and testing purposes.

## Development Database Setup

There are two ways to set up a database for development:

### Option 1: Docker (Recommended)

The easiest way to get started is using Docker with the default configuration:

```bash
npm run docker-dev
```

This command will:
- Start the database container using Docker Compose
- Use the default configuration settings
- Set up the database ready for development

### Option 2: Local MariaDB Installation

For a local MariaDB setup, you'll need to install MariaDB on your system first.

**Installation Guide:** [MariaDB Getting Started](https://mariadb.com/get-started-with-mariadb/)

After installing MariaDB locally, configure your application to connect to your local database instance by updating the appropriate configuration files.

## Testing Database Setup

For running tests, Docker must be installed and running on your system.

To set up the test database:

```bash
npm run docker-test
```

This command will:
- Start a test database container
- Automatically seed the database with mock data prepared specifically for testing
- Ensure a clean testing environment

## Database Seeding and Configuration

### Development Seeding

For development purposes, you can seed the database with mock data by setting `forceSeed` to `true` in your configuration.

**Important Notes:**
- When `forceSeed` is enabled, seeding will execute every time the server reloads
- The `drop` property will clean all data from the database if set to `true` every time the server reloads
- Use these options carefully to avoid unintended data loss

### Migrations

Database migrations will be executed automatically if they haven't been run before.

**Clean Setup Recommendation:**
For a completely clean database setup, it's recommended to run:

```bash
docker compose down database -v
```

And delete all existing data.

**WARNING:** Only perform this clean setup the first time or when you specifically need to reset everything, as it will permanently delete all database data.

## Current Status

**Important:** The database is currently not being used by the application or tests, as the services and controllers are not yet configured to utilize the database layer. This functionality is planned for future implementation.

## Database Management Commands

- `npm run docker-dev` - Start development database
- `npm run docker-test` - Start test database with mock data
- `docker compose down database -v` - Clean database setup (removes all data)
4 changes: 3 additions & 1 deletion QualityControl/jsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,7 @@
"public/**/*.js",
"lib/**/*.js",
"test/**/*.js",
"lib/database/migrations/*.mjs" ]
"lib/database/migrations/*.mjs",
"lib/database/seeders/*.mjs"
]
}
48 changes: 33 additions & 15 deletions QualityControl/lib/QCModel.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ import { Kafka, logLevel } from 'kafkajs';
import { CcdbService } from './services/ccdb/CcdbService.js';
import { IntervalsService } from './services/Intervals.service.js';
import { StatusService } from './services/Status.service.js';
import { JsonFileService } from './services/JsonFileService.js';
import { QcObjectService } from './services/QcObject.service.js';
import { FilterService } from './services/FilterService.js';
import { BookkeepingService } from './services/BookkeepingService.js';
Expand All @@ -36,9 +35,6 @@ import { FilterController } from './controllers/FilterController.js';
import { UserController } from './controllers/UserController.js';

import { config } from './config/configProvider.js';
import { LayoutRepository } from './repositories/LayoutRepository.js';
import { UserRepository } from './repositories/UserRepository.js';
import { ChartRepository } from './repositories/ChartRepository.js';
import { initDatabase } from './database/index.js';
import { SequelizeDatabase } from './database/SequelizeDatabase.js';
import { objectGetByIdValidationMiddlewareFactory }
Expand All @@ -49,6 +45,9 @@ import { objectGetContentsValidationMiddlewareFactory }
import { RunModeService } from './services/RunModeService.js';
import { KafkaConfigDto } from './dtos/KafkaConfigurationDto.js';
import { QcdbDownloadService } from './services/QcdbDownload.service.js';
import { LayoutService } from './services/layout/LayoutService.js';
import { setupRepositories } from './database/repositories/index.js';
import { UserService } from './services/layout/UserService.js';
const LOG_FACILITY = `${process.env.npm_config_log_label ?? 'qcg'}/model-setup`;

/**
Expand All @@ -63,10 +62,13 @@ export const setupQcModel = async (eventEmitter) => {
const __dirname = dirname(__filename);
const packageJSON = JSON.parse(readFileSync(`${__dirname}/../package.json`));

const jsonFileService = new JsonFileService(config.dbFile || `${__dirname}/../db.json`);
if (config.database) {
initDatabase(new SequelizeDatabase(config?.database || {}));
const databaseConfig = config.database || {};
if (!databaseConfig || Object.keys(databaseConfig).length === 0) {
logger.errorMessage('Database configuration is not provided. The application cannot be initialized');
return;
}
const sequelizeDatabase = new SequelizeDatabase(databaseConfig);
initDatabase(sequelizeDatabase, { forceSeed: config?.database?.forceSeed, drop: config?.database?.drop });

if (config?.kafka?.enabled) {
try {
Expand All @@ -85,12 +87,29 @@ export const setupQcModel = async (eventEmitter) => {
}
}

const layoutRepository = new LayoutRepository(jsonFileService);
const userRepository = new UserRepository(jsonFileService);
const chartRepository = new ChartRepository(jsonFileService);
const {
layoutRepository,
gridTabCellRepository,
userRepository,
tabRepository,
chartRepository,
chartOptionRepository,
optionRepository,
} = setupRepositories(sequelizeDatabase);

const userService = new UserService(userRepository);
const layoutService = new LayoutService(
layoutRepository,
userService,
tabRepository,
gridTabCellRepository,
chartRepository,
chartOptionRepository,
optionRepository,
);

const userController = new UserController(userRepository);
const layoutController = new LayoutController(layoutRepository);
const userController = new UserController(userService);
const layoutController = new LayoutController(layoutService);

const statusService = new StatusService({ version: packageJSON?.version ?? '-' }, { qc: config.qc ?? {} });
const statusController = new StatusController(statusService);
Expand All @@ -100,7 +119,7 @@ export const setupQcModel = async (eventEmitter) => {
const ccdbService = CcdbService.setup(config.ccdb);
statusService.dataService = ccdbService;

const qcObjectService = new QcObjectService(ccdbService, chartRepository, { openFile, toJSON });
const qcObjectService = new QcObjectService(ccdbService, layoutService, { openFile, toJSON });
qcObjectService.refreshCache();

const intervalsService = new IntervalsService();
Expand All @@ -125,9 +144,8 @@ export const setupQcModel = async (eventEmitter) => {
statusController,
objectController,
intervalsService,
layoutService,
filterController,
layoutRepository,
jsonFileService,
objectGetByIdValidation,
objectsGetValidation,
objectGetContentsValidation,
Expand Down
16 changes: 3 additions & 13 deletions QualityControl/lib/api.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,6 @@ import { setupQcModel } from './QCModel.js';
import { minimumRoleMiddleware } from './middleware/minimumRole.middleware.js';
import { UserRole } from './../common/library/userRole.enum.js';
import { layoutOwnerMiddleware } from './middleware/layouts/layoutOwner.middleware.js';
import { layoutIdMiddleware } from './middleware/layouts/layoutId.middleware.js';
import { layoutServiceMiddleware } from './middleware/layouts/layoutService.middleware.js';
import { statusComponentMiddleware } from './middleware/status/statusComponent.middleware.js';
import { runStatusFilterMiddleware } from './middleware/filters/runStatusFilter.middleware.js';
import { runModeMiddleware } from './middleware/filters/runMode.middleware.js';
Expand All @@ -39,7 +37,6 @@ export const setup = async (http, ws, eventEmitter) => {
* statusController: import('./controllers/StatusController.js').StatusController,
* statusService: import('./services/statusService').StatusService,
* userController: import('./controllers/UserController.js').UserController,
* jsonFileService: import('./services/JsonFileService.js').JsonFileService
* }}
*/
const {
Expand All @@ -48,8 +45,7 @@ export const setup = async (http, ws, eventEmitter) => {
statusController,
statusService,
userController,
layoutRepository,
jsonFileService,
layoutService,
filterController,
objectGetByIdValidation,
objectsGetValidation,
Expand All @@ -75,23 +71,17 @@ export const setup = async (http, ws, eventEmitter) => {
http.post('/layout', layoutController.postLayoutHandler.bind(layoutController));
http.put(
'/layout/:id',
layoutServiceMiddleware(jsonFileService),
layoutIdMiddleware(layoutRepository),
layoutOwnerMiddleware(layoutRepository),
layoutOwnerMiddleware(layoutService),
layoutController.putLayoutHandler.bind(layoutController),
);
http.patch(
'/layout/:id',
layoutServiceMiddleware(jsonFileService),
layoutIdMiddleware(layoutRepository),
minimumRoleMiddleware(UserRole.GLOBAL),
layoutController.patchLayoutHandler.bind(layoutController),
);
http.delete(
'/layout/:id',
layoutServiceMiddleware(jsonFileService),
layoutIdMiddleware(layoutRepository),
layoutOwnerMiddleware(layoutRepository),
layoutOwnerMiddleware(layoutService),
layoutController.deleteLayoutHandler.bind(layoutController),
);

Expand Down
2 changes: 2 additions & 0 deletions QualityControl/lib/config/database.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,5 +29,7 @@ export function getDbConfig(config) {
timezone: config.timezone ?? '+00:00',
logging: config.logging ?? false,
retryThrottle: config.retryThrottle ?? 5000,
forceSeed: config.forceSeed ?? false,
drop: config.drop ?? false,
};
};
Loading