۱. مقدمه و صورت مسئله (Executive Summary)
در سازمانهای در حال رشد و تکنولوژیمحور، فرایند ورود نیروهای جدید (Onboarding) و آموزش اولیه (Training) شامل تعاملات پیچیده بین چندین واحد سازمانی از جمله تیم جذب (TA)، reources انسانی (HR)، زیرساخت و فناوری اطلاعات (IT)، اداری و پشتیبانی (Admin) و امور مالی (Finance) است.عدم وجود یک سامانه یکپارچه برای مدیریت این چرخه، منجر به چالشهای زیر میشد:
تاخیر در اعطای دسترسیها و تحویل تجهیزات تا روزهای پس از شروع به کار فرد.
ناهمگامی واحدهای IT و پشتیبانی در ساخت اکانتهای Active Directory، ایمیل سازمانی و پیامرسانهای داخلی.
خطاهای انسانی در ثبت اطلاعات مالی (شماره شبا، کد ملی، مراکز هزینه) و تخصیص سیمکارت یا مزایای پرسنلی.
عدم وجود شفافیت و قابلیت پیگیری (Traceability) برای مدیران ارشد و تیم HRBP.
برای حل این چالشها، پروژه ارکستراسیون و اتوماسیون فرآیند آنبوردینگ بر روی بستر Jira Service Management (JSM) با استفاده از قابلیتهای ScriptRunner for Jira، اتوماسیونهای native، یکپارچهسازی با Active Directory / LDAP و سامانههای ارسال پیامک طراحی و پیادهسازی گردید.
۲. معماری کلان راهکار (Architectural Blueprint)
طراحی بر پایه یک مدل ترکیبی ارکستراسیون مرکزی (Hybrid Orchestration Model) انجام شده است. در این مدل، یک Main Issue در پروژه جذب (TA) ایجاد شده و چرخه حیات درخواست را کنترل میکند. متناسب با وضعیت فرآیند و پاسخ به سوالات شرطی فرمها، Issueهای وابسته (Linked Issues) در پروژههای متناظر به صورت خودکار ساخته شده و با لینکهای JQL blocking به یکدیگر متصل میشوند.
┌─────────────────────────────────────────┐
│ [TA] Onboarding Request │
│ (Main Orchestrator) │
└────────────────────┬────────────────────┘
│
┌──────────────────────────┴──────────────────────────┐
▼ ▼
┌─────────────────┐ ┌─────────────────┐
│ Tier A │ │ Tier B │
│ (Pre-Day 1 Gate)│ │ (Day 1 Actions)│
└────────┬────────┘ └────────┬────────┘
│ │
┌──────────┼──────────┬──────────┐ ┌──────────────────┼──────────────────┐
▼ ▼ ▼ ▼ ▼ ▼ ▼
[ADM] [IT] [IT] [HR] [ADM] [IT] [IT]
Contract Accounts Equip. Pack/Lunch Perks Metabase CRM/BackOffice
Setup (AD/Mail) Config Prep Activation Access Accessساختار پروژهها و تفکیک وظایف (Project Mapping)
کلید پروژه | نام پروژه Jira | مسئولیت اصلی | Issue Typeهای مرتبط |
|---|---|---|---|
TA | Talent Acquisition | ارکستراسیون کل فرآیند، فرم آموزش، چکلیست نهایی |
|
HR | Human Resources | ارزیابی قرارداد، تجهیزات، سیمکارت، بودجه آموزش |
|
IT | Information Technology | ساخت اکانت Active Directory، سرویسهای CRM، Metabase، مرکز تلفن |
|
ADM | Admin & Facilities | خدمات رفاهی، ناهار، بیمه تکمیلی، هماهنگی امضا |
|
FIN | Finance | محاسبات مالی، مرکز هزینه، تسویهحساب |
|
۳. جزئیات پیادهسازی تکنیکال (Deep-Dive Technical Implementation)
۳.۱ اتوماسیون ساخت کاربر در Active Directory با Groovy ScriptRunner
یکی از کلیدیترین بخشهای تکنیکال این فرآیند، ساخت خودکار اکانت کاربر در Active Directory / LDAP بلافاصله پس از تایید مراحل اولیه است. این اقدام از طریق یک Groovy Post-Function در ScriptRunner روی Transition مربوطه اجرا میشود.
کدهای ساخت کاربر در Active Directory (نمونه کد اصلاحشده و امن):
import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.issue.CustomFieldManager
import com.atlassian.jira.issue.MutableIssue
import com.atlassian.jira.issue.fields.CustomField
import com.atlassian.jira.issue.comments.CommentManager
import javax.naming.directory.*
import javax.naming.Context
import java.util.Hashtable
// ۱. تنظیمات اتصال امن به LDAP / Active Directory
Hashtable<String, String> env = new Hashtable<>()
env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory")
env.put(Context.PROVIDER_URL, "ldaps://ad.company.local:636")
env.put(Context.SECURITY_AUTHENTICATION, "simple")
env.put(Context.SECURITY_PRINCIPAL, "CN=Jira ServiceAccount,OU=ServiceAccounts,DC=company,DC=local")
env.put(Context.SECURITY_CREDENTIALS, "SecureServiceAccountPassword123!")
CustomFieldManager customFieldManager = ComponentAccessor.getCustomFieldManager()
MutableIssue mutableIssue = (MutableIssue) issue
CommentManager commentManager = ComponentAccessor.getCommentManager()
// ۲. دریافت مقادیر Custom Fieldها از تیکت جیرا
CustomField firstNameField = customFieldManager.getCustomFieldObjectByName("نام انگلیسی")
CustomField lastNameField = customFieldManager.getCustomFieldObjectByName("نام خانوادگی انگلیسی")
CustomField emailField = customFieldManager.getCustomFieldObjectByName("ایمیل شرکتی")
CustomField passwordField = customFieldManager.getCustomFieldObjectByName("account-password")
CustomField ouField = customFieldManager.getCustomFieldObjectByName("واحد مربوطه")
def firstName = ((firstNameField?.getValue(issue) as String) ?: "").toLowerCase().trim()
def lastName = ((lastNameField?.getValue(issue) as String) ?: "").toLowerCase().trim()
def userPrincipalName = (emailField?.getValue(issue) as String) ?: ""
def rawPassword = (passwordField?.getValue(issue) as String) ?: ""
def targetOU = (ouField?.getValue(issue) as String) ?: "Employees"
DirContext ctx = null
try {
ctx = new InitialDirContext(env)
String userCn = "${firstName} ${lastName}"
String userLogin = "${firstName}.${lastName}"
String userDn = "CN=${userCn},OU=${targetOU},OU=EnterpriseUsers,DC=company,DC=local"
Attributes userAttributes = new BasicAttributes(true)
Attribute objectClass = new BasicAttribute("objectClass")
objectClass.add("top")
objectClass.add("person")
objectClass.add("organizationalPerson")
objectClass.add("user")
userAttributes.put(objectClass)
// کدگذاری کلمه عبور به فرمت UTF-16LE برای Active Directory
String quotedPassword = "\"" + rawPassword + "\""
byte[] utf16Password = quotedPassword.getBytes("UTF-16LE")
userAttributes.put(new BasicAttribute("givenName", firstName))
userAttributes.put(new BasicAttribute("sn", lastName))
userAttributes.put(new BasicAttribute("cn", userCn))
userAttributes.put(new BasicAttribute("displayName", userCn))
userAttributes.put(new BasicAttribute("sAMAccountName", userLogin))
userAttributes.put(new BasicAttribute("userPrincipalName", userPrincipalName))
userAttributes.put(new BasicAttribute("mail", userPrincipalName))
userAttributes.put(new BasicAttribute("unicodePwd", utf16Password))
// تنظیم بیتهای UAC: ترکیب ۵۱۲ (Normal Account) و ۶۵۵۳۶ (Password Never Expires) = ۶۶۰۴۸
userAttributes.put(new BasicAttribute("userAccountControl", Integer.toString(66048)))
userAttributes.put(new BasicAttribute("pwdLastSet", "-1"))
// ایجاد کاربر در LDAP
ctx.createSubcontext(userDn, userAttributes)
String successMsg = "✅ اکانت Active Directory با موفقیت ایجاد شد: ${userDn}"
log.info(successMsg)
commentManager.create(mutableIssue, ComponentAccessor.getJiraAuthenticationContext().getLoggedInUser(), successMsg, false)
} catch (Exception e) {
String errorMsg = "❌ خطا در ساخت کاربر در Active Directory: " + e.getMessage()
commentManager.create(mutableIssue, ComponentAccessor.getJiraAuthenticationContext().getLoggedInUser(), errorMsg, false)
log.error(errorMsg, e)
} finally {
if (ctx != null) {
try { ctx.close() } catch (Exception e) { log.error("خطا در بستن LDAP Context", e) }
}
}۳.۲ استعلام خودکار اطلاعات پرسنلی و مالی از پایگاهداده (Database Integration)
جهت جلوگیری از دوبارهکاری و ورود دستی دادهها، اسکریپت زیر با اتصال به پایگاهداده بانک اطلاعاتی پرسنلی (Personnel_Info) بر اساس ایمیل ثبتکننده، فیلدهای شماره شبا، کد ملی، کد مرکز هزینه (CostCenter) و شناسه Threads را استخراج کرده و Custom Fieldهای تیکت جیرا را بهروزرسانی میکند.
import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.issue.fields.CustomField
import com.atlassian.jira.issue.ModifiedValue
import com.atlassian.jira.issue.util.DefaultIssueChangeHolder
import com.onresolve.scriptrunner.db.DatabaseUtil
import org.apache.log4j.Logger
def log = Logger.getLogger("com.enterprise.PersonnelFieldUpdater")
def customFieldManager = ComponentAccessor.getCustomFieldManager()
def issueManager = ComponentAccessor.getIssueManager()
def changeHolder = new DefaultIssueChangeHolder()
def issue = issueManager.getIssueObject(transientVars["issue"].id ?: transientVars["issue"].getKey())
if (!issue) return
def reporterEmail = issue.getReporter()?.getEmailAddress()
if (!reporterEmail) return
// شناسه Custom Fieldهای هدف در جیرا
final String shebaFieldId = 'customfield_10508'
final String costCenterFieldId = 'customfield_21501'
final String nationalIdFieldId = 'customfield_12310'
DatabaseUtil.withSql('Personnel_DB_Connection') { sql ->
def query = "SELECT NationalID, SHEBA, CostCenter FROM Personnel WHERE Email = ?"
def row = sql.firstRow(query, reporterEmail)
if (row) {
def shebaVal = row['SHEBA'] ?: "-"
def costVal = row['CostCenter']?.toString()?.isNumber() ? Double.parseDouble(row['CostCenter'].toString()) : null
def nationalVal = row['NationalID']?.toString()?.isNumber() ? Double.parseDouble(row['NationalID'].toString()) : null
CustomField shebaField = customFieldManager.getCustomFieldObject(shebaFieldId)
CustomField costField = customFieldManager.getCustomFieldObject(costCenterFieldId)
CustomField nationalField = customFieldManager.getCustomFieldObject(nationalIdFieldId)
if (shebaVal && shebaField) {
shebaField.updateValue(null, issue, new ModifiedValue(issue.getCustomFieldValue(shebaField), shebaVal), changeHolder)
}
if (costVal && costField) {
costField.updateValue(null, issue, new ModifiedValue(issue.getCustomFieldValue(costField), costVal), changeHolder)
}
if (nationalVal && nationalField) {
nationalField.updateValue(null, issue, new ModifiedValue(issue.getCustomFieldValue(nationalField), nationalVal), changeHolder)
}
}
}۳.۳ یکپارچهسازی با سامانه پیامک (Kavenegar REST API Webhook)
پس از ایجاد اکانت یا تعیین کد داخلی (Extension Code) در مرکز تلفن (MicroSIP)، اطلاعات دسترسی از طریق Web Request در Jira Automation به API وبسرویس پیامک ارسال میگردد:
Endpoint:
https://api.kavenegar.com/v1/{API_KEY}/verify/lookup.jsonMethod:
POSTPayload Params:
receptor:{{issue.customfield_mobile}}template:OnboardingCredentialstoken:{{issue.customfield_extension_code}}
۴. چرخه حیات و معماری فازهای اجرایی (Workflow Phases)
فرآیند ورود نیرو شامل دو فاز اصلی قبل از شروع به کار (Tier A) و اقدامات روز اول (Tier B) است:
[تکمیل فرم توسط TA]
│
▼
[امضای قرارداد و NDA] (Gate 1)
│
├─────────────────────────┬─────────────────────────┐
▼ ▼ ▼
[ایجاد اکانت IT] [تحویل و کانفیگ سیستم] [پک آنبوردینگ & ناهار]
(Mail & Mattermost) (Stock vs Purchase) (بر اساس ساختمان)
│ │ │
└─────────────────────────┼─────────────────────────┘
│
▼
[روز اول حضور (Start Date)] (Gate 2)
│
├─────────────────────────┼─────────────────────────┐
▼ ▼ ▼
[فعالسازی مزایا] [دسترسی Metabase] [دسترسی CRM & VoIP]
(Baino, Cubi, Snapp) (بر اساس Collection) (Extension Code)
│
▼
[چکلیست نهایی & بستن تیکت]۱. فاز پیشنیازهای روز اول (Tier A - Pre-Day 1)
تایید امضای قرارداد و NDA: گیت اولیه فرآیند. تا زمانی که این مرحله انجام نشود، سایر تیکتها صادر نمیشوند.
ساخت اکانتهای سازمانی: تولید ایمیل سازمانی و اکانت Mattermost ظرف ۲۴ ساعت کاری.
تامین و کانفیگ تجهیزات: بررسی موجودی انبار توسط تیم اموال. در صورت عدم موجودی، صادر شدن خودکار تیکت خرید به مسئول مربوطه و تحویل جهت کانفیگ فنی به IT.
هماهنگی لوجستیک و ناهار: ارسال اطلاعرسانی به مدیر فضای کار هر ساختمان (نکست، آفتاب، کانون، اردیبهشت) بر اساس فیلد ساختمان محل کار.
۲. فاز اقدامات روز اول (Tier B - Day 1 Actions)
فعالسازی حسابهای رفاهی: اعطای اعتبار سامانههای سازمانی.
اعطای دسترسیهای تخصصی: بر اساس شرطهای فرم اولیه، تیکتهای دسترسی به Metabase، CRM شرکا، Back-Office و سیستم تلفنی ParsLogic صادر شده و کد داخلی ثبت میشود.
چکلیست نهایی TA: پس از تکمیل تمام تیکتهای موازی، یک چکلیست جمعبندی برای کارشناس جذب صادر شده و پس از تایید نهایی، تیکت اصلی به وضعیت
Closedتغییر مییابد.
۵. دستاوردها و نتایج کلیدی (Business Impact & KPIs)
پیادهسازی این سناریو روی Jira Service Management دستاوردهای زیر را به همراه داشت:
کاهش ۸۰ درصدی زمان آمادهسازی دسترسیها: زمان اعطای دسترسیها و ساخت اکانت از ۳ روز کاری به کمتر از ۴ ساعت کاهش یافت.
حذف کامل خطاهای انسانی در اعطای دسترسی: به لطف اسکریپتهای اتوماتیک ساخت کاربر در Active Directory و استعلام پایگاهداده.
شفافیت کامل در گزارشگیری (SLA Tracking): امکان سنجش عملکرد واحدهای پشتیبانی (IT، اداری، مالی) با Dashboardهای اختصاصی JSM.
تجربه کاربری عالی برای نیوجوینرها (NPS بالا): دریافت اطلاعات ورود، کد داخلی و خوشآمدگویی از طریق پیامک دقیقاً در روز اول حضور.
