در این مقاله
دو یکپارچگیِ جدا: هویت و داده
وقتی گفته میشود «سامانه به پرسنلی وصل شود»، دو کارِ متفاوت در یک جمله جمع شدهاند. هویت: کارمند با همان نامِ کاربری و رمزی که به ایمیل و اتوماسیون وارد میشود، به سامانهٔ رفاهی هم وارد شود؛ این کارِ دایرکتوریِ سازمان است (LDAP یا Active Directory). داده: سامانه بداند این کارمند در کدام واحد است، چند سال سابقه دارد، چند نفر عائله دارد و وضعیتِ استخدامیاش چیست؛ این کارِ سیستمِ پرسنلی است که معمولاً دایرکتوری نیست. دایرکتوری میگوید «چه کسی»، پرسنلی میگوید «با چه ویژگیهایی». سامانهای که فقط اولی را دارد، حسابِ سازمانی دارد ولی امتیاز را دستی وارد میکند؛ سامانهای که فقط دومی را دارد، دادهٔ درست دارد ولی هزار رمزِ عبورِ جدا.
چرا حسابِ جدا شکست میخورد، فراتر از رمزِ فراموششده: خروجِ کارکنان در دایرکتوری غیرِ فعال میشود ولی در سامانهٔ جدا نه، پس بازنشسته یا منتقلشده هنوز میتواند درخواست بدهد؛ دادهٔ رانشکرده، یعنی عائله در پرسنلی بهروز شده و در سامانهٔ رفاهی نه، و کارمند در مهلتِ اعتراض میفهمد؛ و دو منبعِ حقیقت که در جلسهٔ بازرسی باید توضیح داده شود کدام درست است. این مشکلِ هر نرمافزارِ رفاهیای است که جدا از پرسنلی زندگی کند، نه مشکلِ یک نرم افزار خاص.
LDAP و Active Directory: چه دادهای رد و بدل میشود
Active Directory دایرکتوریِ مایکروسافت است و LDAP پروتکلی که با آن (و با دایرکتوریهای دیگر مثلِ OpenLDAP) حرف زده میشود. برای سامانهٔ رفاهی تفاوتِ عملی کم است؛ چیزی که فرق میکند نامِ صفتهاست. در لحظهٔ ورود این اتفاق میافتد: کارمند نامِ کاربری و رمزِ سازمانیاش را در سامانهٔ رفاهی وارد میکند، سامانه با یک حسابِ سرویسِ فقطخواندنی کاربر را در دایرکتوری پیدا میکند، سپس با نامِ کاربری و رمزِ خودِ کارمند به دایرکتوری «بایند» میکند؛ اگر دایرکتوری پذیرفت، ورود انجام شده. رمز هیچوقت در سامانهٔ رفاهی ذخیره نمیشود؛ فقط یک نشستِ ورود ساخته میشود. ارتباط باید LDAPS (درگاهِ ۶۳۶) یا StartTLS باشد، وگرنه رمز بهصورتِ متن از شبکه رد میشود.
# ورود با حسابِ سازمانی، مرحله به مرحله
1. conn = ldaps://dc.example.local:636 # TLS اجباری
2. bind(serviceAccount, servicePassword) # فقطخواندنی، محدود به base DN
3. entry = search(base="OU=Staff,DC=example,DC=local",
filter="(sAMAccountName=<username>)",
attrs=[dn, displayName, mail, department, employeeID, memberOf])
4. bind(entry.dn, <userPassword>) # اعتبارسنجیِ رمزِ خودِ کارمند
5. if ok: createSession(employeeID) # رمز ذخیره نمیشود
6. role = memberOf contains "CN=Refah-Admins" ? admin : employee| صفتِ دایرکتوری | کاربرد در سامانهٔ رفاهی | لازم است؟ |
|---|---|---|
| sAMAccountName یا uid | نامِ کاربری برای ورود | بله |
| employeeID یا employeeNumber | کلیدِ اتصال به رکوردِ پرسنلی؛ کدِ پرسنلی | بله؛ بدونِ آن هویت و داده به هم وصل نمیشوند |
| displayName | نمایشِ نام در پیشخوان | بله |
| اطلاعرسانیِ فراخوان و نتیجه | مفید | |
| department | واحد یا شعبه، اگر پرسنلی آن را نمیدهد | وابسته |
| memberOf | نقش: کارمند، کارشناسِ رفاه، ناظر | مفید؛ جایگزینِ تعریفِ دستیِ نقشها |
| userAccountControl یا معادلِ آن | غیرِ فعالبودنِ حساب | بله؛ حسابِ غیرِ فعال نباید وارد شود |
اگر سازمان یک سرویسدهندهٔ هویتِ مرکزی با SAML یا OpenID Connect دارد، ورودِ یکپارچهٔ واقعی (SSO، بدونِ تایپِ دوبارهٔ رمز) هم ممکن است؛ ولی این را از هر فروشنده جدا بپرسید، چون «پشتیبانی از LDAP» به معنای پشتیبانی از SAML نیست و برعکس.
همگامسازیِ پرسنلی: API اگر هست، فایلِ زمانبندیشده اگر نیست
دادهٔ امتیازدهی (سابقه، عائله، وضعیتِ استخدامی، واحد، ایثارگری اگر آییننامه به آن وزن میدهد) در سیستمِ پرسنلی است. دو راه برای رساندنش به سامانهٔ رفاهی هست و انتخاب به یک سؤال بستگی دارد: سیستمِ پرسنلیِ شما درگاهِ برنامهنویسی (API) دارد و فروشندهاش اجازهٔ استفاده میدهد؟ اگر بله، سامانهٔ رفاهی در زمانبندیِ مشخص (مثلاً شبانه) فقط رکوردهایی را میخواند که از آخرین بار تغییر کردهاند. اگر نه، که در بسیاری از سازمانها همین است، سیستمِ پرسنلی در زمانبندیِ مشخص یک فایلِ استاندارد (CSV یا اکسل با ستونهای توافقشده) در یک مسیرِ امن (SFTP یا پوشهٔ اشتراکیِ محدود) میگذارد و سامانهٔ رفاهی آن را میخواند.
| API | فایلِ زمانبندیشده | |
|---|---|---|
| تازگیِ داده | ساعتی یا شبانه | شبانه یا هفتگی؛ برای امورِ رفاهی کافی است |
| وابستگی | به فروشندهٔ پرسنلی و پایداریِ API | به یک خروجیِ زمانبندیشده که تقریباً هر سیستمی دارد |
| خطای رایج | تغییرِ قالبِ API بدونِ اطلاع | ستونِ جابهجاشده، کدگذاریِ اشتباهِ فارسی، فایلِ نیمهنوشته |
| کنترلِ آیتی | کمتر؛ سامانه مستقیم میخواند | بیشتر؛ آیتی میبیند دقیقاً چه فیلدهایی خارج میشود |
| هزینهٔ راهاندازی | بیشتر | کمتر |
قاعدههای واردکردن، مستقل از راه: کلید کدِ پرسنلی است نه نام؛ رکوردِ موجود بهروز میشود و رکوردِ تازه ساخته میشود (upsert)؛ رکوردی که در منبع نیست غیرِ فعال میشود، هرگز حذف نمیشود، چون سوابقِ استفادهاش در امتیازدهیِ سالهای بعد لازم است؛ تغییرهایی که روی امتیاز اثر میگذارند (سابقه، عائله، ایثارگری) پیش از اعمال در گزارشِ تفاوت به کارشناسِ رفاه نشان داده میشوند؛ و مهمتر از همه، در بازهٔ قفلِ فهرست همگامسازی روی فهرستِ قفلشده اثر نمیگذارد. فهرستِ دوره در لحظهٔ قفل عکسبرداری میشود، همان فهرستی که قرعهکشی روی آن اجرا و اثرانگشتش منتشر میشود، و همگامسازیِ بعدی فقط رکوردِ زنده را عوض میکند، نه فهرستی که اثرانگشتش منتشر شده.
# ستونهای حداقلیِ فایلِ زمانبندیشده (CSV، UTF-8، سطرِ اول عنوان)
employee_id, full_name, unit_code, employment_start, employment_status,
dependents_count, veteran_status, email
# قاعدهٔ واردکردن
for row in file:
rec = find(employee_id=row.employee_id)
if rec: update(rec, row) else: create(row)
for rec in all(): if rec.employee_id not in file: deactivate(rec) # حذف نه
diff = scoringFieldsChanged(before, after) -> reportToWelfareOfficer(diff)فیلدهایی که واحدِ رفاه واقعاً لازم دارد (و آنچه نباید منتقل شود)
قاعده ساده است: هر فیلد باید به یک بندِ آییننامهٔ امتیازدهی یا یک نیازِ عملیاتیِ مشخص جواب بدهد، وگرنه منتقل نمیشود. کمترین داده یعنی کمترین چیزی که در نشتِ احتمالی از دست میرود و کمترین چیزی که در بازرسی باید توضیح داده شود.
| فیلد | چرا لازم است | منتقل شود؟ |
|---|---|---|
| کدِ پرسنلی | کلیدِ همهچیز | بله |
| نام و نامِ خانوادگی | نمایش و صورتجلسهٔ داخلی | بله |
| واحد یا شعبه | سهمیهٔ شعبه، گزارشِ توزیع | بله |
| تاریخِ شروعِ خدمت | امتیازِ سابقه | بله |
| وضعیتِ استخدامی (شاغل، بازنشسته، منتقل) | شمول و سهمیهٔ بازنشستگان | بله |
| تعدادِ عائلهٔ تحتِ تکفل | امتیازِ عائله و ظرفیتِ واحدِ مهمانسرا | بله، فقط عدد؛ نه نام و مشخصاتِ افراد |
| وضعیتِ ایثارگری | اولویتِ قانونی، اگر آییننامه دارد | فقط اگر لازم است؛ حساس |
| ایمیل یا شمارهٔ همراه | اطلاعرسانی | یکی کافی است |
| حقوق و مزایا | هیچ | خیر |
| کدِ ملی | هیچ؛ کدِ پرسنلی کلید است | خیر، مگر الزامِ مشخص |
| نشانی، اطلاعاتِ پزشکی، شمارهٔ حساب | هیچ | خیر |
اینکه این داده در سامانهٔ رفاهی چطور نگهداری میشود و ده پرسشی که باید پیش از قرارداد از فروشنده بپرسید، مقالهٔ امنیتِ دادهٔ پرسنلی است. کیفیتِ همین فیلدهاست که در نهایت به فهرستِ قفلشدهٔ قرعه میرسد؛ الگوریتمِ قرعه درستیِ فهرستِ ورودی را ثابت نمیکند و آن را به همین همگامسازی و مهلتِ اعتراض واگذار میکند.
بررسیِ فنیِ کوتاه پیش از قرارداد؛ چکلیست
یک جلسهٔ یکساعته با فروشنده، پیش از امضا، با این ده پرسش. پاسخها کتبی در پیوستِ فنیِ قرارداد میآید، تا «دامنهٔ یکپارچگی» بعداً محلِ اختلاف نباشد.
- دایرکتوریِ ما چیست (AD، OpenLDAP، دیگر) و فروشنده دقیقاً با کدام کار کرده؟ LDAPS یا StartTLS اجباری است؟
- حسابِ سرویس فقطخواندنی و محدود به کدام base DN است؟ فهرستِ دقیقِ صفتهایی که میخواند؟
- نقشها (کارشناسِ رفاه، ناظر، مدیر) از گروههای دایرکتوری خوانده میشود یا دستی تعریف میشود؟
- اگر سامانه روی سرورِ فروشنده است، مسیرِ شبکه به دایرکتوری چیست: آیپیِ ثابت، VPN، یا نسخهٔ DMZ؟ چه کسی آن را نگه میدارد؟
- اگر دایرکتوری از دسترس خارج شد، سامانه چه میکند: ورود قطع میشود، یا حالتِ اضطراری با رمزِ محلی برای نقشهای مدیریتی هست؟
- همگامسازیِ داده با API است یا فایل؟ قالبِ دقیقِ فایل و مسیرِ امنِ تبادل چیست؟ چه کسی فایل را تولید میکند؟
- فهرستِ فیلدهای منتقلشده، با دلیلِ هر کدام؛ و تأیید که حقوق، کدِ ملی و نشانی منتقل نمیشود؟
- رکوردِ حذفشده در منبع چه میشود (غیرِ فعال، نه حذف)؟ گزارشِ تفاوت پیش از اعمال به چه کسی میرسد؟
- همگامسازی روی فهرستِ قفلشدهٔ دورهٔ جاری اثر نمیگذارد؟ چطور تضمین میشود؟
- انتقالِ سوابقِ سالهای گذشته (از اکسل یا سیستمِ قبلی) بخشی از راهاندازی است؟ چه کسی صحتِ فهرستِ منتقلشده را پیش از اولین دوره تأیید میکند؟
پاسخِ سرای سازمانی، کوتاه
ورود با حسابِ سازمانی با LDAP یا Active Directory و همگامسازیِ اطلاعاتِ پرسنلی پشتیبانی میشود؛ اگر سیستمِ پرسنلیِ فعلی درگاهِ برنامهنویسی دارد اتصالِ مستقیم، و اگر ندارد، فایلِ استانداردِ زمانبندیشده. دامنهٔ دقیقِ یکپارچگی پس از همان بررسیِ فنیِ کوتاه تعیین و در قرارداد نوشته میشود؛ این را پرسشِ پرتکرارِ یکپارچگی هم به همین صراحت میگوید. برای مسیرِ شبکه، هر سه گزینهٔ یادداشتِ بالا ممکن است و در شکلهای استقرار گزینهٔ نصب روی سرورِ خودِ سازمان هم هست، با هزینهٔ بیشترش. انتقالِ سوابقِ اکسل بخشی از راهاندازی است و فهرستِ منتقلشده پیش از اولین دورهٔ واقعی برای بازبینی تحویلِ سازمان میشود؛ مقالهٔ اکسل میگوید چه چیزی از اکسلِ فعلی ارزشِ انتقال دارد.