Compare commits

...

2 Commits

9 changed files with 376 additions and 3 deletions

View File

@ -1,4 +1,5 @@
{ {
"name": "@service/ams", "name": "@service/ams",
"version": "0.1.0" "version": "0.1.0",
"exports": "./main.ts"
} }

146
deno.lock generated Normal file
View File

@ -0,0 +1,146 @@
{
"version": "5",
"specifiers": {
"jsr:@oak/commons@1": "1.0.1",
"jsr:@oak/oak@^17.1.3": "17.2.0",
"jsr:@std/assert@1": "1.0.19",
"jsr:@std/bytes@1": "1.0.6",
"jsr:@std/crypto@1": "1.1.0",
"jsr:@std/encoding@1": "1.0.11",
"jsr:@std/encoding@^1.0.11": "1.0.11",
"jsr:@std/http@1": "1.1.2",
"jsr:@std/internal@^1.0.14": "1.0.14",
"jsr:@std/media-types@1": "1.1.0",
"jsr:@std/path@1": "1.1.6",
"npm:mysql2@3": "3.22.5_@types+node@26.1.0",
"npm:path-to-regexp@^6.3.0": "6.3.0"
},
"jsr": {
"@oak/commons@1.0.1": {
"integrity": "889ff210f0b4292591721be07244ecb1b5c118742f5273c70cf30d7cd4184d0c",
"dependencies": [
"jsr:@std/assert",
"jsr:@std/bytes",
"jsr:@std/crypto",
"jsr:@std/encoding@1",
"jsr:@std/http",
"jsr:@std/media-types"
]
},
"@oak/oak@17.2.0": {
"integrity": "938537a92fc7922a46a9984696c65fb189c9baad164416ac3e336768a9ff0cd1",
"dependencies": [
"jsr:@oak/commons",
"jsr:@std/assert",
"jsr:@std/bytes",
"jsr:@std/http",
"jsr:@std/media-types",
"jsr:@std/path",
"npm:path-to-regexp"
]
},
"@std/assert@1.0.19": {
"integrity": "eaada96ee120cb980bc47e040f82814d786fe8162ecc53c91d8df60b8755991e"
},
"@std/bytes@1.0.6": {
"integrity": "f6ac6adbd8ccd99314045f5703e23af0a68d7f7e58364b47d2c7f408aeb5820a"
},
"@std/crypto@1.1.0": {
"integrity": "b8d6d0a6377a32b213af2661ed7bf1062d94feac0c57def5526a8e74a95c3ec8"
},
"@std/encoding@1.0.11": {
"integrity": "e7cef2f0b3153bccc17431e7c864a1de03a4b6d9647389c43e08aaa775d37385"
},
"@std/http@1.1.2": {
"integrity": "1c0473590d5e5b75b30b2be4833c08047dd799aeea35624fd34ec58d67fc9240",
"dependencies": [
"jsr:@std/encoding@^1.0.11"
]
},
"@std/internal@1.0.14": {
"integrity": "291516b3d4c35024d6ffbc0a9df5bf4c64116e05b50012cf846710152d2ffdf7"
},
"@std/media-types@1.1.0": {
"integrity": "c9d093f0c05c3512932b330e3cc1fe1d627b301db33a4c2c2185c02471d6eaa4"
},
"@std/path@1.1.6": {
"integrity": "c68485c2a4dfbb5ae3cc74fae4e8c4e5d874cf8a8ed12927917235c758b46cbe",
"dependencies": [
"jsr:@std/internal"
]
}
},
"npm": {
"@types/node@26.1.0": {
"integrity": "sha512-O0A1G3xPGy4w7AgQdAQYUlQ+BKk2Oovw8eRpofyp5KdBZULnbe+WqaOVNrm705SHphCiG4XHsACrSmPu1f+Kgw==",
"dependencies": [
"undici-types"
]
},
"aws-ssl-profiles@1.1.2": {
"integrity": "sha512-NZKeq9AfyQvEeNlN0zSYAaWrmBffJh3IELMZfRpJVWgrpEbtEpnjvzqBPf+mxoI287JohRDoa+/nsfqqiZmF6g=="
},
"denque@2.1.0": {
"integrity": "sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw=="
},
"generate-function@2.3.1": {
"integrity": "sha512-eeB5GfMNeevm/GRYq20ShmsaGcmI81kIX2K9XQx5miC8KdHaC6Jm0qQ8ZNeGOi7wYB8OsdxKs+Y2oVuTFuVwKQ==",
"dependencies": [
"is-property"
]
},
"iconv-lite@0.7.2": {
"integrity": "sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==",
"dependencies": [
"safer-buffer"
]
},
"is-property@1.0.2": {
"integrity": "sha512-Ks/IoX00TtClbGQr4TWXemAnktAQvYB7HzcCxDGqEZU6oCmb2INHuOoKxbtR+HFkmYWBKv/dOZtGRiAjDhj92g=="
},
"long@5.3.2": {
"integrity": "sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA=="
},
"lru.min@1.1.4": {
"integrity": "sha512-DqC6n3QQ77zdFpCMASA1a3Jlb64Hv2N2DciFGkO/4L9+q/IpIAuRlKOvCXabtRW6cQf8usbmM6BE/TOPysCdIA=="
},
"mysql2@3.22.5_@types+node@26.1.0": {
"integrity": "sha512-95uZ2TrPWAZdwpB3vvvDbmEMcNG8yIeNCyu6GUcr/QnWEE/wXm7+mhOCsdQfWQDTV7qYT/PDUZ4U4UPP4AsXqQ==",
"dependencies": [
"@types/node",
"aws-ssl-profiles",
"denque",
"generate-function",
"iconv-lite",
"long",
"lru.min",
"named-placeholders",
"sql-escaper"
]
},
"named-placeholders@1.1.6": {
"integrity": "sha512-Tz09sEL2EEuv5fFowm419c1+a/jSMiBjI9gHxVLrVdbUkkNUUfjsVYs9pVZu5oCon/kmRh9TfLEObFtkVxmY0w==",
"dependencies": [
"lru.min"
]
},
"path-to-regexp@6.3.0": {
"integrity": "sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ=="
},
"safer-buffer@2.1.2": {
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
},
"sql-escaper@1.3.3": {
"integrity": "sha512-BsTCV265VpTp8tm1wyIm1xqQCS+Q9NHx2Sr+WcnUrgLrQ6yiDIvHYJV5gHxsj1lMBy2zm5twLaZao8Jd+S8JJw=="
},
"undici-types@8.3.0": {
"integrity": "sha512-j375ScV60dom+YkPFIfTLcOiPxkN/buHz5GobjLhixFuANaNs3C9l4GmrWqejgXWJ7BbJcFYpTEUkS1Ge8bpZQ=="
}
},
"workspace": {
"dependencies": [
"jsr:@oak/oak@^17.1.3",
"npm:mysql2@3"
]
}
}

View File

@ -0,0 +1,20 @@
version: '3.8'
services:
ems_mysql:
image: docker.io/library/mysql:8.4
container_name: hrms_ems_db
environment:
MYSQL_ROOT_PASSWORD: root
MYSQL_DATABASE: hrms_ems
MYSQL_USER: admin
MYSQL_PASSWORD: admin123
ports:
- "3306:3306"
volumes:
- ./init-db:/docker-entrypoint-initdb.d:Z # <-- Added :Z here
- mysql_ems_data:/var/lib/mysql
restart: unless-stopped
volumes:
mysql_ems_data:

View File

@ -1,4 +1,5 @@
{ {
"name": "@service/ems", "name": "@service/ems",
"version": "0.1.0" "version": "0.1.0",
"exports": "./main.ts"
} }

View File

@ -0,0 +1,43 @@
import { Application, Router } from "@oak/oak";
import pool from "../shared/db.ts";
const app = new Application();
const router = new Router();
// Define the endpoint Sufail will call from the Vite frontend
router.get("/api/employees", async (ctx) => {
try {
const [rows] = await pool.query(
`SELECT
e.employee_code,
p.first_name,
p.last_name,
d.name AS department,
j.title AS designation,
c.work_email
FROM employees e
JOIN partners p ON e.partner_id = p.partner_id
JOIN contracts c ON e.employee_id = c.employee_id
JOIN departments d ON c.department_id = d.department_id
JOIN job_positions j ON c.job_id = j.job_id`
);
ctx.response.body = {
success: true,
count: (rows as any[]).length,
data: rows
};
} catch (error) {
ctx.response.status = 500;
ctx.response.body = {
success: false,
error: (error as Error).message
};
}
});
app.use(router.routes());
app.use(router.allowedMethods());
console.log("EMS Service running on http://localhost:8001");
await app.listen({ port: 8001 });

View File

@ -0,0 +1,99 @@
CREATE DATABASE IF NOT EXISTS hrms_ems;
USE hrms_ems;
-- 1. Legal Entities
CREATE TABLE companies (
company_id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(100) NOT NULL,
parent_id INT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (parent_id) REFERENCES companies(company_id) ON DELETE SET NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- 2. Physical Locations
CREATE TABLE branches (
branch_id INT AUTO_INCREMENT PRIMARY KEY,
company_id INT NOT NULL,
branch_name VARCHAR(100) NOT NULL,
code VARCHAR(20) NOT NULL UNIQUE, -- e.g., 'BLR-HQ'
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (company_id) REFERENCES companies(company_id) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- 3. Human Profiles (Isolated PII Data)
CREATE TABLE partners (
partner_id INT AUTO_INCREMENT PRIMARY KEY,
first_name VARCHAR(50) NOT NULL,
last_name VARCHAR(50) NOT NULL,
dob DATE NOT NULL,
gender VARCHAR(15) NOT NULL,
personal_email VARCHAR(100) NOT NULL UNIQUE,
personal_phone VARCHAR(20) NOT NULL UNIQUE,
profile_picture_url VARCHAR(255) NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- 4. Demographics & Addresses
CREATE TABLE addresses (
address_id INT AUTO_INCREMENT PRIMARY KEY,
partner_id INT NOT NULL,
address_type ENUM('PERMANENT', 'CURRENT', 'EMERGENCY') NOT NULL,
door_number VARCHAR(20) NOT NULL,
landmark VARCHAR(100) NULL,
address_line TEXT NOT NULL,
pincode VARCHAR(10) NOT NULL,
district VARCHAR(50) NOT NULL,
state VARCHAR(50) NOT NULL,
FOREIGN KEY (partner_id) REFERENCES partners(partner_id) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- 5. Business Organizational Units
CREATE TABLE departments (
department_id INT AUTO_INCREMENT PRIMARY KEY,
company_id INT NOT NULL,
name VARCHAR(50) NOT NULL,
parent_id INT NULL,
manager_id INT NULL, -- Logical Reference to employee_id
FOREIGN KEY (company_id) REFERENCES companies(company_id) ON DELETE CASCADE,
FOREIGN KEY (parent_id) REFERENCES departments(department_id) ON DELETE SET NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- 6. Functional Designations
CREATE TABLE job_positions (
job_id INT AUTO_INCREMENT PRIMARY KEY,
company_id INT NOT NULL,
title VARCHAR(50) NOT NULL,
description TEXT NULL,
FOREIGN KEY (company_id) REFERENCES companies(company_id) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- 7. Master Employee Mapping Engine
CREATE TABLE employees (
employee_id INT AUTO_INCREMENT PRIMARY KEY,
employee_code VARCHAR(20) NOT NULL UNIQUE, -- Matches your Excel Base Column
partner_id INT NOT NULL,
company_id INT NOT NULL,
branch_id INT NOT NULL,
is_active BOOLEAN DEFAULT TRUE,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (partner_id) REFERENCES partners(partner_id) ON DELETE RESTRICT,
FOREIGN KEY (company_id) REFERENCES companies(company_id) ON DELETE RESTRICT,
FOREIGN KEY (branch_id) REFERENCES branches(branch_id) ON DELETE RESTRICT
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- 8. Legal & Operational Contracts
CREATE TABLE contracts (
contract_id INT AUTO_INCREMENT PRIMARY KEY,
employee_id INT NOT NULL,
department_id INT NOT NULL,
job_id INT NOT NULL,
reporting_to_id INT NULL, -- Logical Reference to employee_id
work_email VARCHAR(100) NOT NULL UNIQUE,
date_joining DATE NOT NULL,
probation_days INT DEFAULT 90,
status ENUM('DRAFT', 'ACTIVE', 'EXPIRED', 'TERMINATED') DEFAULT 'DRAFT',
salary_structure_id INT NOT NULL, -- Logical Reference to PMS Microservice database
FOREIGN KEY (employee_id) REFERENCES employees(employee_id) ON DELETE CASCADE,
FOREIGN KEY (department_id) REFERENCES departments(department_id) ON DELETE RESTRICT,
FOREIGN KEY (job_id) REFERENCES job_positions(job_id) ON DELETE RESTRICT
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

View File

@ -0,0 +1,46 @@
-- Select the right database context
USE hrms_ems;
-- 1. Create the Company
INSERT INTO companies (company_id, name, parent_id)
VALUES (1, 'CliniLaunch Research', NULL);
-- 2. Create a Branch
INSERT INTO branches (branch_id, company_id, branch_name, code)
VALUES (1, 1, 'Bengaluru Main', 'BLR01');
-- 3. Define Departments
INSERT INTO departments (department_id, company_id, name, parent_id, manager_id)
VALUES
(1, 1, 'Training (PT)', NULL, NULL),
(2, 1, 'IT', NULL, NULL);
-- 4. Authorize Job Positions
INSERT INTO job_positions (job_id, company_id, title, description)
VALUES
(1, 1, 'Executive-II (PT)', 'Part-time executive role for training.'),
(2, 1, 'Trainee', 'Entry level IT trainee.');
-- 5. Create Partners (The personal identity)
INSERT INTO partners (partner_id, first_name, last_name, dob, gender, personal_email, personal_phone, profile_picture_url)
VALUES
(1, 'Blessy', 'Paul', '1995-06-15', 'Female', 'blessy.personal@example.com', '9876543210', NULL),
(2, 'Adhvaidh', 'Prasad', '1998-11-22', 'Male', 'adhvaidh.personal@example.com', '8765432109', NULL);
-- 6. Add Addresses for the Partners
INSERT INTO addresses (address_id, partner_id, address_type, door_number, landmark, address_line, pincode, district, state)
VALUES
(1, 1, 'CURRENT', '42/A', 'Near Metro', 'MG Road', '560001', 'Bengaluru', 'Karnataka'),
(2, 2, 'PERMANENT', '15-B', 'Tech Park', 'Whitefield', '560066', 'Bengaluru', 'Karnataka');
-- 7. Employ the Partners
INSERT INTO employees (employee_id, employee_code, partner_id, company_id, branch_id, is_active)
VALUES
(1, 'CLRI18', 1, 1, 1, TRUE),
(2, 'CLRI298', 2, 1, 1, TRUE);
-- 8. Assign Contracts
INSERT INTO contracts (contract_id, employee_id, department_id, job_id, reporting_to_id, work_email, date_joining, probation_days, status, salary_structure_id)
VALUES
(1, 1, 1, 1, NULL, 'Blessy.Paul@clinilaunchresearch.in', '2023-01-10', 90, 'ACTIVE', 101),
(2, 2, 2, 2, 1, 'adhvaidh.P@clinilaunchresearch.in', '2023-05-20', 180, 'ACTIVE', 102);

View File

@ -1,4 +1,5 @@
{ {
"name": "@service/lms", "name": "@service/lms",
"version": "0.1.0" "version": "0.1.0",
"exports": "./main.ts"
} }

View File

@ -0,0 +1,16 @@
import mysql from "mysql2/promise";
// Create a connection pool using the credentials from docker-compose.yml
const pool = mysql.createPool({
host: "127.0.0.1",
port: 3306,
user: "admin",
password: "admin123",
database: "hrms_ems",
waitForConnections: true,
connectionLimit: 10,
queueLimit: 0,
});
// Export the pool to be used across your EMS, AMS, and LMS services
export default pool;