Розробка мобільного додатка для HR та рекрутингу
HR-додаток обслуговує два принципово різні сценарії одночасно: рекрутер вступає воронку кандидатів та планує інтерв'ю, а новий працівник проходить онбординг та заповнює документи. Обидва сценарії потребують різних UX-паттернів, різних прав доступу та різних push-сповіщень. Більшість архітектурних рішень виникають на цьому перетині.
Ролева модель та архітектура
Мінімум три ролі: HR-менеджер/рекрутер, кандидат, працівник (після пропозиції). У кожної — своя навігаційна потік та набір екранів.
// iOS — NavigationRouter на основі ролі
enum AppRole {
case recruiter
case candidate
case employee
}
func buildRootNavigation(for role: AppRole) -> UIViewController {
switch role {
case .recruiter: return RecruiterTabBarController()
case .candidate: return CandidateOnboardingFlow()
case .employee: return EmployeePortalController()
}
}
Роль користувача приходить в JWT-токені після логіну. При зміні ролі (кандидат став працівником) — перебудуємо навігацію без перезавантаження програми.
Воронка кандидатів: Kanban для рекрутера
Воронка рекрутингу — це Kanban: Новий → Телефонний скринінг → Технічне інтерв'ю → Пропозиція → Відмова. На мобільному — горизонтально прокручувані колонки.
// Android — стан воронки через ViewModel
data class RecruitingFunnelState(
val stages: List<FunnelStage>,
val selectedStageIndex: Int = 0,
val candidates: Map<String, List<Candidate>> // stageId → candidates
)
class FunnelViewModel(private val repo: CandidateRepository) : ViewModel() {
val state = MutableStateFlow(RecruitingFunnelState(stages = emptyList()))
fun moveCandidateToStage(candidateId: String, targetStageId: String) {
viewModelScope.launch {
repo.updateCandidateStage(candidateId, targetStageId)
// Оптимістичне оновлення UI
state.update { current ->
val updated = current.candidates.toMutableMap()
// переносимо кандидата між списками
current.copy(candidates = updated)
}
}
}
}
Drag-and-drop між колонками — через ItemTouchHelper з кастомним ViewHolder.onDragOver. Простіше — tap-to-move через bottom sheet з вибором стадії.
Планування інтерв'ю
Інтерв'ю вимагає: вибір слота, запрошення інтерв'юера, надсилання посилання на зустріч, push-нагадування за 15 хвилин.
Інтеграція з Google Calendar через Google Calendar API або CalDAV, з Microsoft через Graph API. Мобільний клієнт запитує доступні слоти:
func fetchAvailableSlots(interviewerId: String, date: Date) async throws -> [TimeSlot] {
// Запит до бекенду, який агрегує Google Calendar + внутрішній календар
return try await api.getAvailableSlots(interviewerId: interviewerId, date: date)
}
Push-нагадування планується при створенні інтерв'ю — заплановане сповіщення через FCM або OneSignal з deliver_after.
Онбординг нового працівника
Онбординг — це послідовний потік: заповнення персональних даних, завантаження документів (паспорт, ІД, трудовий договір), ознайомлення з політиками компанії, виконання завдань першого дня.
Прогрес онбордингу — чек-лист зі статусом кожного пункту. На сервері зберігається JSON-схема онбордингу (набір кроків), клієнт рендирує її динамічно:
data class OnboardingStep(
val id: String,
val type: StepType, // FORM, DOCUMENT_UPLOAD, QUIZ, VIDEO, TASK
val title: String,
val isRequired: Boolean,
val completedAt: Long?
)
enum class StepType { FORM, DOCUMENT_UPLOAD, QUIZ, VIDEO, TASK }
Завантаження документів — multipart form data з прогресом:
func uploadDocument(_ data: Data, type: DocumentType) async throws -> DocumentId {
return try await api.upload(
endpoint: "/employee/documents",
file: data,
filename: "\(type.rawValue)_\(Date().timestamp).pdf",
mimeType: "application/pdf"
) { progress in
self.uploadProgress = progress
}
}
Push-сповіщення в HR-контексті
| Подія | Одержувач | Пріоритет |
|---|---|---|
| Новий відгук на вакансію | HR-менеджер | Високий |
| Інтерв'ю призначено | Кандидат + інтерв'юер | Високий |
| Нагадування про інтерв'ю (за 15 хв) | Всі учасники | Критичний |
| Пропозиція відправлена кандидату | Кандидат | Високий |
| Крок онбордингу потребує дії | Новий працівник | Середній |
| Термін пробації спливає | HR-менеджер | Середній |
Корпоративна комунікація
Внутрішній чат або інтеграція з існуючими інструментами (Slack API, Microsoft Teams webhooks). Для MVP — внутрішній чат через WebSocket:
class HRChatSocket(private val token: String) {
private val client = OkHttpClient()
private var ws: WebSocket? = null
fun connect(roomId: String, onMessage: (ChatMessage) -> Unit) {
val request = Request.Builder()
.url("wss://api.yourhr.app/ws/chat/$roomId")
.header("Authorization", "Bearer $token")
.build()
ws = client.newWebSocket(request, object : WebSocketListener() {
override fun onMessage(webSocket: WebSocket, text: String) {
onMessage(json.decodeFromString(text))
}
})
}
}
Графік
MVP HR-додатка (воронка кандидатів, карточки кандидатів, базовий онбординг, push-сповіщення) — 10–14 тижнів. Повна функціональність з планувальником інтерв'ю, інтеграцією календарів, корпоративним чатом та аналітикою — 20–28 тижнів.







