Recruitment System Guide
Recruitment System Guide
Business Requirements
Contents
Basic Concepts.............................................................................................................................................2
Initial Assumptions..................................................................................................................................2
Commercial Terms...................................................................................................................................3
System User.............................................................................................................................................4
Company Profile......................................................................................................................................4
Course Category......................................................................................................................................4
Tag (Topic)...............................................................................................................................................4
Context....................................................................................................................................................4
Course.....................................................................................................................................................5
Course Tag...............................................................................................................................................5
Course Scores..........................................................................................................................................6
Skills and Skill Dictionary.........................................................................................................................6
Payments.................................................................................................................................................6
Course RCH Score Calculation..................................................................................................................7
Profile Tag Score Calculation (System Auto Tag Endorsement).............................................................11
Billing Process........................................................................................................................................12
Instructor Course Transaction Processing.............................................................................................12
Payment Gateway Integration...............................................................................................................13
Job Posts................................................................................................................................................14
User Interface and basic flow definitions..................................................................................................14
User Registration...................................................................................................................................14
Home (My Profile Tab)...........................................................................................................................16
Payment Gateway Accounts..................................................................................................................17
Claim Course Material Fraud.................................................................................................................19
Message Exchange among the users.....................................................................................................19
Instructor’s Functionality.......................................................................................................................22
Candidate’s Functionality......................................................................................................................24
Recruiter’s Functionality........................................................................................................................35
Administrator’s Functionality................................................................................................................48
Basic Concepts
Initial Assumptions
1. We have 4 roles: ADMIN, INSTRUCTOR, CANDIDATE and RECRUITER. Dashboard is the general default
view for each guest which does not provide access to the content, but provides general view of the
services.
2. Each participant can take any combination of the roles above.
3. Roles are defined with different tabs after user login; based on the preferences we can define the
default tab.
4. User registration and user management will be managed thru the site.
5. Candidates receive preview of the materials for free out of the box (if provided by the instructor). Also
some of the exam questions are available for free. The remaining materials as well as the full exam are
paid (or free) in the following manner:
a) Free
b) Fixed Cost (as defined by 6 –b)
c) Pay in advance for a fee of a nominal fee of X (this is related with 6-c, i.e. revenue sharing)
d) Pay upon hire for a fee of Z=Y*X which is significantly higher than X, the sum paid upon hire
is calculated as sum of all pending Z sums (related with 6-c, i.e. revenue sharing).
e) Progressive cost with each sequential exam.
6. Instructors will provide instruction materials as well exams based on the following fee structure:
a) Free
c) Revenue sharing
7. Recruiters will provide monthly, quarterly or yearly fee. Recruiters will take a discount if they tell us
they hired a candidate.
a) Instructor creates the Course entity (name, description, category, tags, commercial term etc.).
c) Submit the Course (category, tags, material and test) for approval
d) The administrator will review the content for decency and validated based on the category
(smart admin)
Commercial Terms
The system shall define the following Commercial Term types:
ID=0, FREE (used by Instructors when specifying the Course’s Commercial Term and Candidates when
taking the Course)
ID=1, FIXED_COST (used by Instructors when specifying the Course’s Commercial Term and Candidates
when paying for the Course)
ID=2, REVENUE_SHARING (used by Instructors when specifying the Course’s Commercial Term)
ID=3, NOMINAL_FEE (used by Candidates when paying for a Course or additional Exam(s))
ID=4, PAY_UPON_HIRE (used by Candidates when paying for a Course or additional Exam(s))
ID=5, RECRUITER_L1_MONTHLY (used by Recruiters for 1 month subscription for Basic system access)
ID=6, RECRUITER_L1_QUARTERLY (used by Recruiters for 3 month subscription for Basic system access)
ID=7, RECRUITER_L1_YEARLY (used by Recruiters for 1 year subscription for Basic system access)
ID=8, RECRUITER_L2_MONHTLY (used by Recruiters for 1 month subscription for Intermediate system
access)
ID=10, RECRUITER_L2_YEARLY (used by Recruiters for 1 year subscription for Intermediate system
access)
ID=11 RECRUITER_L3_MONTHLY (used by Recruiters for 1 month subscription for Advanced system
access)
ID=12, RECRUITER_L3_QUARTERLY (used by Recruiters for 3 month subscription for Advanced system
access)
ID=13, RECRUITER_L3_YEARLY (used by Recruiters for 1 year subscription for Advanced system access)
ID=14 RECRUITER_L4_MONTHLY (used by Recruiters for 1 month subscription for Complete system
access)
ID=15, RECRUITER_L4_QUARTERLY (used by Recruiters for 3 month subscription for Complete system
access)
ID=16, RECRUITER_L4_YEARLY (used by Recruiters for 1 year subscription for Complete system access)
ID=17, CANDIDATE_LOCK_PARTIAL (used by Candidates in order to revoke System rights to share exam
related information with Advanced and Complete Recruiters for Courses marked with status PARTIAL)
System User
The System has its own user that will represent the System itself whenever an identity is required
(payments System for example). This user is automatically created upon system bootstrap, has ID=0 and
can’t be deleted.
Company Profile
Company Profile is RCH entity that groups several Recruiters. Each Company Profile has the following
attributes:
Name
Code (UUID)
Discount (decimal number between 0 and 1 (percent) for Recruiter level subscription cost)
Representative email
When the Company Profile is created by the Administrator the UUID Code is generated randomly by
the RCH system. En email is sent to the Company’s representative containing the Company attributes:
Name, Code, Discount and Representative E-Mail.
The Company representative will share the Code with its Recruiters. This is verbal, i.e. out of band
communication.
Each Recruiter on his profile can claim relationship with the Company Profile by entering the following
Company Profile info that must match (case sensitive):
The Name
The Code
If the parameters entered match those saved in the database, the Recruiter will be associated with the
Company Profile. An Email shall be sent after that to the Company representative with notification
containing information about the Recruiter that “joined” the Company. After that moment, each cost for
Recruiter subscription shall be decreased by the Company Profile associated discount.
Course Category
The Course Category types are defined by the system. The Course Category shall be a global point of
interest like: Java, .NET, Mobile, Tibco etc.
Tag (Topic)
Each Tag is independent from the Course Category. Tags can be attached on each Course no matter of
its category (for example the XML tag can be attached on Course having category Java, as well as on
Course having Category .NET). Each tag is something that describes the content. The number of tags
defined in the system can be very large and we shall always use autocomplete fields for choosing
particular tag. When we search by Tags (Topics), the system shall consider all of them grouped by logical
AND (the Course shall have tag T1 and T2 and T3).
Context
The Context is environmental description for entities like Course, Job Post. In other words some Course
or Job Post can be related to different environmental contexts: Engineering, IT, Telecom etc. One or
multiple Contexts can be attached to each Course or Job Post. Context shall be taken into account when
searching for Courses and Candidates, as well as Job Posts.
Course
The Course is the central point in the whole system. Each Course defines metadata for its name,
description, tags, category etc.
For each Course the system collects statistical metadata defined as follows:
1. Number of Candidate Views: how many times candidates have viewed the course material
(preview or the complete material).
2. Number of Recruiter Views: how many times recruiters have viewed the course material
(preview or the complete material).
3. Candidate Favored: how many times candidates have favored the course material (preview or
the complete material) - Liking functionality
4. Recruiter Favored: how many times recruiters have favored the course material (preview or the
complete material) – Liking functionality
5. Candidate Average Rating: Average rating of the candidates that have taken the course
6. Recruiter Average Rating: Average rating of the recruiters
7. Aggregate Exam Score: Average score for the all candidates that have passed the exam
8. Total Hires: The number of the Candidate confirmed Hires
9. System Verified: This is a flag set by the system in the case the system engages third party
expert to verify the Course’s content.
10. RCH Score: The “magic” formula calculated by the system
Course Tag
Each Course can be associated with multiple tags. That way the Course can be searched by tags. For
each Course-Tag association we keep the number of endorsements for that Tag for that Course. The
Candidates that have taken the course (paid for that course) can endorse the Tag for that Course. The
system calculates the weighted endorsement for each Tag under the whole Course context (all tags).
The following rules apply:
An Example:
Let we have a Course in the Category Java having the following tags: Spring, Web and Hibernate.
The Candidate Marjan has taken the Course and endorsed the tags Spring and Web for the Course.
The Candidate Jovica has taken the Course and endorsed the tags Web and Hibernate for the Course.
The total number of users that have endorsed the Course is 3: Instructor+Marjan+Jovica
The Tag endorsement counts and weightings for the Course are:
Initially when the Course is created each Course Tag shall have weighting of 1.
Course Scores
Each Course has aggregate exam score associated. It is an average from all COMPLETED (PASSED or
FAILED) courses by ALL candidates.
Each Candidate Course has associated aggregate exam score too. It is calculated as weighted average
(exponential attenuation) from all PASSED exams by that Candidate for that Course.
Each Skill shall be converted into uppercase before it is used in RCH. Each Skill shall be inserted into the
Skill table for endorsement and grading purposes described further in this document. Before saving the
Skills we shall query the Dictionary if the skills exist. The non-existent skills shall be saved into the
Dictionary.
Note: There is concurrency issues when saving the same Skills into the Dictionary from multiple threads.
The application shall handle the concurrency by catching unique name constraint exceptions.
Payments
Each payment is registered into the table Payment. User to User payments are NOT allowed. The
payments are always from SYSTEM to Profile and Profile to SYSTEM.
The payment flow has the following steps:
1. Payment record is registered into the Payment table with status INITIALIZED.
2. The User is redirected to the Payment Gateway. The Reference Id sent to the external Payment
Gateway is underscore concatenation of the following information saved into the Payment
table:
a. Reference Id Type
b. Reference Id
c. Created On (timestamp)
3. The User pays the amount specified and the Payment Gateway redirects the User to the
application.
4. The incoming external reference id string is parsed into its constituting parts that are further
used to find appropriate pending payment if any. The payment is marked as completed.
The Reference Id is always system generated UUID. In Candidate payments new Reference Id is
generated for each payment. For SYSTEM to Instructor payments, the Reference Id is the same for
particular Instructor Course (however the combination Reference Id Type+Reference Id+Created On is
always unique). In the case or CLP payment the Reference_Id equals to the Candidate Course
partialLockedReferenceId which is UUID too.
One of the key attributes in the Course table is the attribute rchScore. This factor is the key when
calculating REVENUE SHARING cost of particular Course.
The rchScore can NOT be calculated only with the attributes of the Course itself. Rather, the calculation
of per Course rchScore requires scanning and gathering information from all other Courses in the
system.
min_recruiter_views=0; max_recruiter_views=0;
min_candidate_favored=0; max_candidate_favored=0;
min_recruiter_favored=0; max_recruiter_favored=0;
min_total_hires=0; max_total_hires=0;
#The first full scan will find min-max ranges for integer valued attributes
IF course.candidate_views>max_candidate_views THEN
max_candidate_views=course.candidate_views
END_IF
IF course.candidate_views<min_candidate_views THEN
min_candidate_views=course.candidate_views
END_IF
IF course.recruiter_views>max_recruiter_views THEN
max_recruiter_views=course.recruiter_views
END_IF
IF course.recruter_views<min_recruiter_views THEN
min_recruiter_views=course.recruiter_views
END_IF
IF course.candidate_favored>max_candidate_favored THEN
max_candidate_favored=course.candidate_favored
END_IF
IF course.candidate_favored<min_candidate_favored THEN
min_candidate_favored=course.candidate_favored
END_IF
IF course.recruiter_favored>max_recruiter_favored THEN
max_recruiter_favored=course.recruiter_favored
END_IF
IF course.recruter_favored<min_recruiter_favored THEN
min_recruiter_favored=course.recruiter_favored
END_IF
IF course.total_hires>max_total_hires THEN
max_total_hires=course.total_hires
END_IF
IF course.total_hires<min_total_hires THEN
min_total_hires=course.total_hires
END_IF
END FOR
#The second full scan run calculates rchScore for each Course
norm_candidate_views=
(course.candidate_views-min_candidate_views)/
(max_candidate_views-min_candidate_views)
norm_recruiter_views=
(course.recruiter_views-min_recruiter_views)/
(max_recruiter_views-min_recruiter_views)
norm_candidate_favored=
(course.candidate_favored-min_candidate_favored)/
(max_candidate_favored-min_candidate_favored)
norm_recruiter_favored=
(course.recruiter_favored-min_recruiter_favored)/
(max_recruiter_favored-min_recruiter_favored)
norm_total_hires=
(course.total_hires-min_total_hires)/
(max_total_hires-min_total_hires)
rchScore=
k1 * norm_candidate_views +
k2 * norm_recruiter_views +
k3 * norm_candidate_favored +
k4 * norm_recruiter_favored +
k5 * course.candidateRatingAverage/5 +
k6 * course.recruiterRatingAverage/5 +
k7 * course.aggregateExamScore +
k8 * norm_total_hires +
k9 * system_verified
END FOR
In the case of relational SQL database both scans can be sublimated on 2 SQL statements.
The coefficients k1, k2, k3, k4, k5, k6, k7, k8, k9 are system global parameters.
If we say that recruiters are more competent than candidates and their role is more important in the
system and if we agree that rating is more significant than favoring, favoring is more significant than
viewing than one possible choice of the coefficients is:
k1=1 (candidate views)
k3=2(candidate favored)
Once the rchScore is calculated, the cost for Courses having REVENUE SHARING Commercial Term is set
by the system (for that day). The calculation is based on the amount and amountDelta of the
NOMINAL_FEE Commercial Term:
Example
amount=50
amountDelta=49
If rchScore=0 then cost=1
1. Course rchScore
2. Course Tag endorsementWeighting
3. Candidate Course aggregateExamScore
tagRchNormalizatior=[]
profileTagScore=tagScoreMap[Tag]
rchNormalizator= tagRchNormalizator[Tag]
profileTagScore = profileTagScore +
+Course.rchScore *
CourseTag.endorsementWeighting *
CandidateCource.aggregateExamScore
rchNormalizator=rchNormalizator+Course.rchScore
tagScoreMap[Tag]=profileTagScore
tagRchNormalizator[Tag]=rchNormalizator
tagScore=rchTagMap[Tag]
rchNormalizator=rchNormalizatorMap[Tag]
tagScore=tagScore/rchNormalizator
Most Relevant Tags for Candidate are the first 10 tags with highest scores after the calculation. In the
table CandidateTagScore we shall keep only the Most Relevant Tags for particular user, i.e. the rest of
them shall be deleted from the database. These tags are shown on the User’s profile tabs under the
label System Graded Tags.
The calculation job shall run on a daily basis or whatever period configured in the system.
Billing Process
Once in a month the system shall execute the Billing process. The Billing process shall:
Process all Pay Upon Hire pending payments: When the Candidate is hired with concrete hiring
date, there is an interval of 30 days for hire/dispute resolution. If the status of the hire is HIRED
or CONFIRMED after that period, the next billing process shall process for that candidate all
pending payments with date less or equal to the hiring date. For all pending payments the
system will auto deduct the total amount from the Candidate’s account and will generate the
same payment info as in the case when Candidate pays at his will. The status of the Hire after
that shall be set to BILLED which is final state (In the case of Candidate Hire Dispute, the
Administrator will resolve the issue by transition HIRED =>CONFIRMED or
HIRED=>BOOKMARKED)
Generate credit record into the table InstructorCourseTransaction table for each
InstructorCourse having amount greater than 0. The columns amount and payment in the table
InstructorCourseTransaction initially will be null. After the transaction record is processed by
scheduled batch process, these columns will be filled with the Payment generated and the
amount transferred to the Instructor).
Each Billing process has a record in the table Billing. There is one record for each month for each year.
The status of the billing record will be INITIALIZED until all the operations, Pay Upon Hire processing and
credit record generation, has been processed for that month. If the current schedule of the billing
process has crashed, the next scheduler (after one hour for example) will find the last committed
(processed) state in the database. In particular:
For Pay Upon Hire processing we have always information based on the Hire status (BILLED or
HIRED or CONFIRMED) and the hire date.
For credit record generation we can always find the last instructorCourseId for
InstructorCourseTransaction credit record created that month and continue from that point
further.
When everything is processed, the billing record shall go into the state COMPLETED.
This table is processed periodically by scheduled process. This process will fetch unprocessed records,
ordered by id. Each record shall be processed the following way:
For DEBIT records, the InstructorCourse’s accruedAmount shall be increased by the specified
amount
For CREDIT records the system shall:
o Generate Payment record from SYSTEM to INSTRUCTOR with
amount==accruedAmount and status COMPLETED and execute the Payment, i.e. debit
that amount in the Instructor’s bank account. After that, we shall update the columns
amount and payment in the InstructorCourseTransaction credit record with
appropriate values found in the Payment record
o Reset InstructorCourse’s accruedAmount to zero (0).
o All of this processing must be inside database transaction where interaction with the
Payment gateway is last, i.e. in the case of remote payment system failure we can roll
back the local transaction.
Each DEBIT or CREDIT record processed shall be marked as COMPLETED and this action is part of the
database transaction that corresponds to that record processing.
The Payment Gateway interface abstraction shall support the following operations:
Verify User Existence: check if the user with his email, first name and last name exists in the
payment gateway external system.
Generate Preapproval Key: the user shall be able to setup preapproval key so the system can
automatically charge the user (Pay Upon Hire scenario for hired user). The preapproval key shall
be valid for N automatic payments where each payment transaction shall not exceed the
preapproved maximum amount of M.
Charge User: Automatic charge of the user (Candidate) in the case he was hired and there are
pending Pay Upon Hire payments.
Pay to User: The system shall be able to transfer money to the user (Instructor). This transfer is
once in a month, i.e. for each Billing process cycle.
Interactive Digital Goods Payment: support flow for all immediate payments by candidates and
recruiters where Payment Gateway shall provide success and cancel redirect URL as well process
and verify the returned results with the external gateway in order to ensure the payment was
successfully completed. The operations involved here are:
o Setup Digital Goods Payment
o Generate Digital Goods Payments Redirect URL
o Finish Digital Goods Payment
For more info and details regarding Pay Pal Integration, see the sample POC project located at:
https://confluence/confluence/display/Java/PayPal+Integration
Job Posts
Recruiters can submit Job Posts. Each Job Post is associated with Course Category, Tags, Contexts, City,
States etc. For Jobs in SUBMITTED state the system will associate related Courses. RCH defines use cases
where Candidates can reach the Job Posts from associated Courses, search for Job Posts etc. Candidates
can favor and rate each job post.
User Registration
We shall allow the users to register themselves. On the application default (landing page) we shall have
a registration form (use similar look and feel as in existing Social Networks like Facebook or LinkedIn).
The form shall contain the following info:
1. Email Address
2. First Name
3. Last Name
4. Location
a. State
b. City
5. Roles: Instructor, Candidate, Recruiter
6. Password
7. Confirm Password
The User can press the button Join Now. When this button is clicked:
1. The System shall generate User record and Profile record. The User passwords in the
database must be salted and hashed. The initial status of the User is 0 (CREATED). The
system also generates random confirmation_code.
2. The System shall send account confirmation e-mail to the user (use SSL to the mail server).
The confirmation link must contain the following parameters:
a. confirmation_code
b. confirmation_timestamp (now)
c. confirmation_token: this token is HASH(confirmation_timestamp || User Id ||
Email Address || First Name || Last Name || Location State|| Location City)
When the user receives the account confirmation mail and clicks on the confirmation link, the System
shall:
1. Check if the confirmation_token received matches the info for that user in the database. The
confirmation_timestamp received shall not be older 1 day.
a. If the confirmation is ok, the User status shall set to 1: (CONFIRMED), the User’s
Security Context shall be populated as he was logged through login form and he shall be
redirected to the My Profile page.
b. If the confirmation is not ok, the user shall be redirected to the default, landing page
with appropriate error message that states that user account can’t be confirmed.
2. In both cases the confirmation_code in the User record shall be reset to null. This is extremely
important because confirmation_code MUST be used only once.
If the confirmation mail was somehow lost, we shall allow the user to ask the System for another
confirmation mail. We need another link on the default, landing page saying: Account Confirmation.
When the user presses this link we shall present him another page where he can enter his E-mail and
press the button Send Confirmation E-Mail. The system shall:
LinkedIn Integration
The user shall be able to register with his LinkedIn account too. On the default landing page we shall also
have a link Join With Your LinkedIn Account. If the user clicks on that link we shall execute the flow as
described at:
https://confluence/confluence/display/Java/LinkedIn+Integration
When the user is redirected back to our application and the OAuth2 authentication has been successful
the system shall:
1. Query the user’s LinkedIn profile for attributes like: first name, last name, e-mail, picture url,
positions, skills, educations, certifications, languages, interests etc.
2. Generate User and Profile records based on that info. From the skills, educations, positions and
the rest of the LinkedIn information retrieved generate and save resume in html format (JSON-
>XML->XSLT->HTML). Note that the User account status is 1, i.e. in this case we don’t need
further account information because we trust LinkedIn that the e-mail received is a correct one.
Populate the user’s Security Context as if he was logged through the login form.
3. Redirect the user to the Create Password page where he must enter his Password for the first
time.
4. After Create Password page the user shall land on the My Profile page where we can add
(change) his Roles in the system.
The application shall have lost password functionality. On the default landing page we shall have link:
Forgot Password. When the user clicks on that link we shall present him a page where he can enter his
e-mail and press on the button Reset Password. If the user clicks on the Reset Password button, the
system shall:
When the user receives the mail and clicks on the link, the system shall:
1. Check if the confirmation_timestamp is not older than one day and confirmation_token
matches the User’s info in the table
2. If they user’s data matches, the User’s Security Context holder shall be populated as if the User
was logged thru the login form. The confirmation_code shall be reset to null (one time use, one
time password).
3. The user shall be redirected to the Change Password page (the Old password shall not be
present in this UI because the user does not know it).
Change Password
The user shall be able to change his password. In order to change his password, he must enter his Old
Password too.
1. First Name
2. Last Name
3. Location
4. Willing to Travel (percentage)
5. Photo
6. Roles
7. Resume
8. Video presentation
9. Password (this shall be separate screen).
The user shall be also capable to upload his photo as well as to take a photo using his Web camera.
Resynchronize his resume by pressing a link Synchronize Resume with LinkedIn. The
data will be fetched and new XML resume shall be generated and stored in the storage
service. We are going to use the XML format used by LinkedIn for that purpose.
The user shall be able to create and edit his resume and store it again in our Storage
Service.
Each user shall be able to upload his introductory self-presentation short video.
All profile related data (photo, resume, video…) shall be contained into per profile storage folder having
a unique id.
User shall be able to upload his video resume and the other users shall be able to see that video on his
profile.
The system won’t encode the uploaded video. Instead, the system shall save it in the uploaded format
and size. It must be into mp4 format ( or ???webm) format (put these formats into property file). The
system shall restrict the size of the uploaded video. The cutoff size shall be specified into properties file.
For example, we can start with restriction of 100 MB per video. It should be enough for low resolution 1
minute presentation of the user.
On the user’s profile page, the other users shall be able to watch the video (if it exists) by pressing the
link: Video Resume, below their photo. We shall present the video into lightbox popup with HTML5
video tag.
The Profile Page shall enlist all of the roles the user has. Besides the basic roles, in the case of Recruiters,
the current subscription level (dynamic role) shall be visible too. This info on the profile page shall be
visible only for the user owing that profile, not for the rest of the world.
For an example how to progressively download video from JAX-RS service, see the services located at
the following location:
https://confluence/confluence/display/Java/Common+Technologies
https://confluence/confluence/download/attachments/22478873/hdfs-file-storage.zip
Users having the role Recruiter associated shall be able to optionally associate themselves with a
Company Profile.
The user profile Edit page shall contain a link Associate with Company Profile. By pressing on that link, a
window shall popup where the user can enter:
The entered Name and Code shall be sent to the server in order to find a match with such company
profile. If the Company Profile with that Name and Code exists, the Recruiter shall be associated with
the Company Profile and from that point further he will have subscription discounts (for the payments
after that).
Whenever a Recruiter is associated with a Company Profile a notification email shall be sent to the
Company Representative.
Important: Send the email only after the transaction was committed successfully. In order to accomplish
start from service method that is not transactional, call transactional save method and send the mail
after that through the notification service.
Payment Gateway Accounts
The user shall be able to create, edit and delete payment gateway accounts. This page shall be a sub
menu item in the Profile tab. In the first phase we are dealing only with Pay Pal, so only one payment
gateway account per user is expected. The user shall not be able to create multiple payment gateway
accounts of the same type. If the system supports multiple types of payment gateways and if the user
has created multiple payment gateway accounts, only one has to be a default one.
The user has to enter the following info for each payment gateway account:
Gateway Account Type== PAY PAL (chose the type only when creating, when editing it is read
only).
Email
First Name
Last Name
Default ==yes
Whenever user saves the payment gateway account, it must be verified with the Payment Gateway
service. Only verified payment gateway accounts shall be used in all system transactions.
The payment gateway accounts are listed into accordions containing the following information:
Type
Email
First Name
Last Name
Existence Verified
Default
Max Number of Preapproved Payments
Max Amount per Preapproved Payment
The account related area shall contain a link: Generate Preapproval Key. When the user clicks that link a
popup will show where user can chose the following parameters:
Maximum Amount per Preapproved Payment: this is drop down with options $500, $1000, $2000,
$3000, $5000.
The popup shall contain a button with name Generate. When the user clicks on this button the form
shall be submitted regularly (not Ajax) and the system will execute the following steps:
The Billing process shall automatically charge users for Pay Upon Hire use case ONLY if:
Whenever preapprovalKey is used and the transaction has successfully completed, the field
maxNumberOfPreapprovedPayments shall decrease by 1 (down to 0).
Note that we don’t keep persistent history for this claim notifications. The system just sends an email to
the administrators having the following information:
1. The email, first name and the last name of the user which is reporting for fraudulent courses.
2. The Id of the Course considered fraudulent
3. The Name of the Course considered fraudulent
4. The claim description
For user roles like candidate, recruiter and administrator that have possibility to search for courses we
shall provide shortcut to the Claim Course Material Fraud. When the user searches for Courses we have
a list of Courses matching the criteria. In the Course related popup we need to place a link to the Claim
Course Material Fraud page. The link shall contain the Course Id parameter that allow the system to
partially fill some of the fields in the Claim submission form.
2. Recruiter can initiate message conversation with each bookmarked Candidate. In the last, action,
column we need an e-mail link (button) for each bookmarked (or hired) candidate.
By pressing on the e-mail link a popup window with title New Message will appear where user can see
or enter the following information:
1. To: The message receiver (read-only field from the receiver’s first and last name)
2. Send me a copy: Send copy of the message to the sender
3. Subject: the subject of the message
4. Content: the text of the message
On the server side each New Message will be assigned brand new Conversation Id which is system
generated UUID. The concept of Conversation Id along with the message creation time is crucial for
maintaining and presenting conversation threads.
MessageContent
Message
+id: long
+id: long +conversationId: string
+from: Profile +subject: string
+to: Profile +content: string
+messageContent: Message
+folder: string[0..1]
Candidates and Recruiters can access their associated messages by clicking on the e-mail link (button)
located in the top bar, on the left from the logged in user name.
This link will take the user to the My Messages page. Note: This page is not accessible thru the
dropdown menu.
The first one, Inbox, shall enlist all messages where the current user appears in the To field. The
messages shall be presented into server side paginated Ajax table. By default the messages are ordered
by the message creation time in descending order. The table will have the following columns:
1. From
2. Subject
3. Received (message creation time)
The table shall be sortable by all of the above columns. The Inbox shall be searchable by all of the
columns in the table (From, Subject, >= Received).
The second tab, Outbox, shall enlist all messages where the current user appears in the From field. The
messages shall be presented into server side paginated Ajax table. By default the messages are ordered
by the message creation time, descending. The table will have the following columns:
1. To
2. Subject
3. Sent (message creation time)
The table shall be sortable by all of the above columns. . The Outbox shall be searchable by all of the
columns in the table (From, Subject, >= Sent).
The search filter shall be common for both folders: Inbox and Outbox. The From/To and Received/Sent
labels shall change along with the active tab.
In both of the tables defined, the user can click on particular message that triggers window popup. The
content of this window does NOT consist of the clicked message only. Rather, the window shall show
the Conversation Thread that particular message is bound to. This window shall include all messages
with the same Conversation Id (that equals to the Conversation Id of the clicked message) where
current user appears in the From or To fields. The message list is sorted by the message creation time in
descending order. Despite the fact that this window shows the whole conversation thread, initially the
window shall be scrolled to the message clicked.
Figure 3. Message Conversation Thread
User can reply to the conversation thread by pressing the button Reply located on the top-right of the
window. The Reply Message window shall appear and that window is the same with the New Message
window. Application shall automatically add “Re:” to the previous message subject (the one located at
the top of the conversation thread). The user can press Send or Cancel in the Reply Message window. If
the message has been successfully sent, the Conversation Thread shall be updated accordingly (put the
last reply message at the top). The server side processing logic for reply messages shall re-use the
conversation id, i.e. new conversation id is not generated for Reply messages.
Instructor’s Functionality
The user interface tab Instructor contains the functionality related to the Instructor role.
When the instructor logs in, the tab Instructor shall be visible.
By default we shall present the courses created in the last 3 months (date descending order). However
we will provide search criteria to find all Instructor’s courses. The search functionality shall contain the
following filter criteria:
Each course shall be presented with expand/collapse panel (+/-). The user interface shall allow multiple
courses to be expanded at once.
The page shall provide a button or link for creating a new course, at the top and the bottom of the page.
When creating new course, the user interface shall provide two-step wizard.
In the first step the Instructor shall provide the metadata for the course and choose appropriate
Commercial Term, Course Category, Tags etc.
In the second step, the Instructor can upload the material, preview (which is optional) and the exam
itself. After the content is uploaded, the Instructor shall press the buttons: Save or Submit. After the
button is pressed, the system shall redirect the Instructor to the list of courses.
Each course can be into the following states: CREATED, EDITED, SUBMITTED, APPROVED, REJECTED,
DEPRECATED.
Each course panel shall contain buttons for specific actions: EDIT, SUBMIT, DEPRECATE.
Each Course can be edited only if it is in the states CREATED, EDITED, REJECTED, And DEPRECATED. In
the state DEPRECATED the Instructor can ONLY change the description of the course.
For each state transition the Instructor or Administrator can provide additional comment which will be
visible using lazy loading if required.
INSTRUCTOR
INSTRUCTOR
INSTRUCTOR
EDITED SUBMITTED
ADMINISTRATOR
INSTRUCTOR ADMINISTRATOR
REJECTED
INSTRUCTOR APPROVED
INSTRUCTOR
SYSTEM
DEPRECATED
SYSTEM
SYSTEM_DEPRECATED
Note: In the state SUBMITTED, the Administrator shall not be allowed to reject the Course if the Course
has been approved at least once. This is necessary condition because once the Course goes in the public
we have no right to change the significant Course attributes like: Category, Tags, Material, Exam etc.
In the first step, the Instructor fills the Course metadata like:
1. Name
2. Description
3. Category
4. Tags : Shall be Autocomplete list because of the large number of possible tags defined in the
system
5. Contexts: Shall be Autocomplete list because of the large number of possible contexts defined in
the system
6. Commercial Term (FREE, FIXED_COST, REVENUE_SHARING)
7. Price: for FIXED_COST the price is required, for REVENUE_SHARING the price is defined by the
system (The candidate will see NOMINAL_FEE which is calculated by the system and
PAY_UPON_HIRE which is defined and calculated by the system)
In the second step the Instructor shall be able to upload:
Revenue
By default the Payments tab will show the realized payments for the last 3 months. Each monthly
revenue can be expanded in order to show per Course payments for that month.
We will have alternate view for the Revenue with initial list consisting of per Course payments
aggregation. Each Revenue per Course can be further expanded in order to show per month payments
for that Course. (Note: use existing control for the view swap functionality if we can find such).
The Payments tab shall contain filtering capabilities that will allow the Instructor to change the date
time interval he is filtering for.
The Pending Payments tab shall enlist all pending per Course accrued amount from the last billing cycle
up to that moment. Instead of the Month/Year, the label shall read Next Billing Cycle Payment. For this
only section we shall enlist per Course accrued amount.
The user interface shall allow multiple expanded elements in one moment.
Candidate’s Functionality
The tab Candidate contains the functionality related to the Candidate role.
When the Candidate logs in, the tab Candidate shall be visible.
Search for Courses shall offer two types of searches: Basic Search and Advanced Search.
Accordingly the screen shall consists of tabbed pane with 2 tabs: Basic Search and Advanced Search.
The Basic Search tab is default one and will have only one input field with autocomplete functionality. In
this field the candidate shall be able to enter multiple space separated words. Autocomplete
functionality shall offer term filtered list constructed from the Topic, Context and Category names.
However, Candidate can enter free form word too.
http://jqueryui.com/autocomplete/#multiple-remote
The implementation on the server side shall be implemented with Full Text Search.
The search shall be an AJAX call that will return up to 500 results in JSON format. The returned results
shall fit into table with sortable columns and in-memory (browser) pagination.
The result shall include the default set of columns like Couse Name, Category etc.
The Advanced Search shall allow filtering and ordering criteria based on:
Course Id
Course Category
Creation Date
Tags with endorsement weighting above some threshold (logical AND among the tags)
Contexts (logical OR among the contexts)
Name
Number of Candidate Views
Number of Recruiter Views
Number of Candidate Favored (Likes)
Number of Recruiter Favored (Likes)
Recruiter Average Rating
Candidate Average Rating
Aggregate Exam Score
Total Hires
System Verified
RCH Factor
Has Job Posts
The filtering and ordering have to be dynamically constructed in the user interface.
The Candidate can choose the filtering criteria from auto complete dropdown select list (Filter Course
By). When Candidate chooses particular criteria item from this dropdown list, the criteria “balloon” shall
enter the search area bellow. All Criteria chosen are in place editable.
Figure 5. Search for Courses
For example: the user can choose the following filtering and ordering criteria:
1. Category Java
2. Tag XML with Relevance Not Applicable (Courses tagged with XML any endorsement weight)
3. Average Recruiter Rating more than 2.5
The search shall be an AJAX call that will return up to 500 results in JSON format. The returned results
shall fit into table with sortable columns and in-memory (browser) pagination.
If Course Category is NOT included in the Search Filter, then Course Category MUST be a sortable
column in the results table.
If the search filter includes at least one Course Tag, then the result table MUST include a column with
name Tags Total Endorsement Weight and the results table shall be sorted by this column in descending
order (the most relevant courses at the top).
The Courses that have Job Posts associated shall be marked with Job Post icon in both of the table row
and Course details popup.
The Candidate shall be able to save his Course search queries into persistent store. One of the queries is
the Default one. The default query is always loaded when the search page has been opened. The rest of
saved queries have name chosen by the user. In particular the system shall implement the following
behavior:
When the user fetches his queries of particular type (course, candidate, job post), if no query
exists the System shall:
o Generate a query with name 'System Default'
o Mark that query as 'defaultQuery'
o Save that query
o Return that query to the user
In the User interface:
o The current query shall be highlighted in the drop down list of available queries
o The user shall be able to add new query
o The user shall be able to save the current query
o The user shall be able to delete each query which is NOT default one. If the current
query is the default one, the delete button shall be disabled (grayed)
o The user shall be able to delete the 'System Default' query if it is not default anymore
o The user shall be able to mark each query as default. Note that the service call shall set
all queries of that type as non-default and then mark the current as default
o If the current query is deleted (and this is not a default query), the next query to be
shown on the screen shall be the default none.
The same logic shall apply for Search for Courses queries, Search for Candidates queries and Search for
Jobs queries.
The buttons for query state manipulation: ‘add’ and ‘save’ shall reside in a button group. The buttons
‘delete’ and ‘make default’ shall reside next to each query in the query drop down menu.
When the Candidate clicks on the Course link in one of the table rows returned, a popup window shall
show the Course details along with links to the preview material if any, preview exam etc. The popup
window shall also have an indicator if the Course has associated job posts or not. The Candidate can
choose to take that course (if note taken before) by pressing the link: Take the Course which is a
beginning of a flow that starts on a new page (different page from the search page). That flow consists
of the following alternative paths:
1. If the Course is FREE the system will create the Candidate-Course with marker paid=true, the
first Candidate Exam with marker paid=true, association and redirects the Candidate to the My
Courses tab where the Course taken is listed first (it is the last one, descending ordering).
2. If the Course is not FREE but with commercial term of FIXED_COST or REVENUE_SHARING the
flow proceeds the following way:
a. If the Course has FIXED_COST:
i. The system generates REFERENCE_ID, create Candidate-Course association
having that REFERENCE_ID, create Candidate-Exam having that REFERENCE_ID,
creates Payment record with that REFERENCE_ID and Candidate is redirected to
the Payment Gateway. Note: If the Candidate-Course and Candidate-Exam
exist but are never paid (something wrong happened during the payment
processes), reuse the Candidate-Course and Candidate–Exam entity and update
them with new REFERENCE_ID and cost.
ii. The Candidate pays the required amount in the Payment Gateway.
iii. The Payment Gateway redirects the Candidate to our application where the
Payment (identified by the REFERENCE_ID) is completed. The Candidate Course
and the first Course Exam are marked as paid as well.
iv. The amount paid for the Course is added to the InstructorCourse’s
accruedAmount:
accruedAmount=accruedAmount + amount * (1- commercialTerm.margin).
v. The Candidate is redirected to the My Courses tab where the Course taken is
listed as first.
b. If the Course has REVENUE_SHARING Commercial Term:
i. The Candidate must choose the Commercial Term first: NOMINAL_FEE or
PAY_UPON_HIRE.
ii. If the Candidate chooses NOMINAL_FEE, the process continues as in in the case
of FIXED_COST. The cost paid is the cost of the Course at the moment the
Course was taken. The cost of the Course per Candidate is always saved into the
Candidate-Course association.
iii. If the Candidate chooses PAY_UPON_HIRE, the system will generate Candidate-
Course association with cost calculated as the NOMINAL_FEE for that Course
multiplied by the factor defined in PAY_UPON_HIRE Commercial Term. The
first Candidate-Exam entity is created as well. In this use case we don’t care if
the Course cost increases or decreases in the future. REFERENCE_ID is NOT
generated. Payment record is NOT generated. The Candidate is redirected to
the My Courses tab where the Course taken is listed as first.
Candidates shall be able to search for Jobs. The page shall allow the candidate to search for Jobs and
filter by Category, Tags along with their associated weight, Contexts, Recruiter’s email, Job Start Date
(>=) and Job End Date (<=) as well as Location. The functionality is similar to the Search for Courses
functionality. The tables queried here are: JobPost and JobPostTag. Only Job Posts in SUBMITTED state
shall be returned. Job Posts in CREATED and COMPLETED state are not relevant for the search query.
The results shall be ordered by the Job Post start date, in descending order. The system shall return at
most 500 Job Posts and the system will present these Job Posts in the client side paginated data table.
The table row shall contain the following information:
Recruiter’s email
Course Category
Start Data
End Date
Description (truncated)
If the search filter includes at least one Job Post Tag, then the user interface shall include one additional
sortable column: Tags Total Weight.
When some Candidate clicks on the Job Post, a popup window shall show up.
The Job Post Details tab shall present all information that relates directly to the Job Post:
Description
Course Category
Start Date
End Date
Recruiter info (email, first name, last name and his photo)
Job Post Contexts
Job Post Tags along with their weights (these are created by the Recruiter)
Job Post Tags by Candidate Feedback (these are aggregated by the system based on the
Candidates feedback)
Job Location
The number of Candidate Views
The number of Candidate Favors
Average Candidate Rating
The Job Post Details tab shall allow the candidate to favor and rate the Job Post. The favored Job Posts
shall appear under new Candidate page My Favored Job Posts.
The Related Courses tab shall enlist the associated Courses to that Job Post. This is a query to the
association entity CourseJobPost. The list shall be sorted by the Course’s rchScore, descending order.
We shall return at most 500 Courses presented in the client side paginated data table. Each table row
shall contain these Course related fields: Id, Name, Commercial Term, System Score (rchScore), and the
cost (if any). If the Candidate clicks on the Course row, the system shall redirect the Candidate to the
Search for Courses page with automatic search by the Course Id.
My Courses
By default we shall present the Courses the Candidate took in the last 3 months (date descending
order).
The courses available for listing are Candidate Courses which status paid==true or Commercial Term==
PAY_UPON_HIRE (Not that FREE courses are marked as paid=true)
However we will provide search criteria to find all Candidate courses. The search functionality shall
contain the following filter criteria:
Each Course shall be presented with expand/collapse panel (+/-).The user interface shall allow multiple
courses to be expanded in one moment.
1. Course Material
2. Preview Exam
3. Course Exam(s)
4. A link (button) to buy another Course Exam. This link shall not be visible and the Add New
Course Exam action not allowed if there is a pending Course Exam which is NOT completed yet.
Note that the first Course Exam is ALWAYS paid along with Course.
If the Course has associated Job Posts at the moment, a link with name Job Posts shall be visible. If the
Candidate clicks on that link, a popup window shall enlist all associated job posts in a server side paged
accordion (query the table CourseJobPost). The Job Posts shall be ordered by their start date,
descending order and only Job Posts in SUBMITTED state shall be considered.
The accordion panel content shall show all Job Post related info:
Description
Course Category
Start Date
End Date
Location (State and City if any, they are optional)
Recruiter info (email, first name, last name and his photo)
Job Post Contexts
Job Post Tags with their weights (these are created by the Recruiter)
Job Post Tags with their by Candidate Feedback (these are aggregated by the system based on
the Candidates feedback)
For each Job Post, Candidate shall be able to provide feedback related to the Job Post’s tags and their
weights. That functionality shall be implemented the following way:
The tag select drop down will allow the Candidate to choose a tag. The select drop down is
prefix based Ajax filter that won’t offer tags already included in the Candidate’s feedback.
When the user selects a tag it shall be added to the “submission” area.
The user shall be able to adjust the weight next to the tag.
The user shall be able to remove the Tag from the feedback (from the submission area)
The user shall be able to click the button Save in order to persist the Feedback on the server.
The system shall periodically average the feedback from all of the Candidates by averaging the table
CandidateJobPostTagFeedback (group by Job Post and Tag).
Important: Only Job Posts in SUBMITTED state shall take part into this aggregation query.
The Candidate must be able to change the Course Visibility (when Recruiters score Candidates). The
Course visibility can be:
PUBLIC: All Exams for that Candidate Course are visible to the Recruiters and the Scoring
system
(Description: Your Course and Exams are always visible for Recruiters in accordance with their
level of privileges)
PARTIAL: The Candidate Course takes part when Recruiters score the Candidates, the
aggregated Exam Score can be seen by all Recruiters of level Advanced or Complete, but the
Exams are visible only for Recruiters of level Complete.
(Description: Your Course and Exams are always visible for Recruiters, but the information for
each particular Exam is hidden from Recruiters with lower privileges)
PARTIAL_LOCKED: The Candidate Course takes part when Recruiters score the Candidates, the
aggregated Exam Score can be seen by all Recruiters of level Advanced or Complete, but the
Exam(s) information is NOT available to the Recruiters no matter of their role. NOTE: This status
is not in the status drop down list if the flag partialLockedPaid is not true. When the partial
locked payment is finished the system automatically will set the status to PARTIAL_LOCKED.
After that the Candidate can change the status as he wish into one of 4 available statuses.
(Description: Your Course and Exams are always visible for Recruiters in accordance with their
level of privileges, but if you have paid, the information for each particular Exam is hidden from
any Recruiters)
PRIVATE: The Candidate Course is visible only for the Candidate and it is not counted when the
Recruiters score the Candidates.
(Description: Your Course is invisible for Recruiters)
If the Candidate marks the Course as PARTIAL, the System still has the right to share the Exam
information with Recruiters of level Complete. However, the Candidate can always pay a fee
(immediately, no matter of the Candidate Course Commercial Term) and revoke the System right to
share Exam related information with Recruiters with Complete level of subscription. When the payment
is completed, the System will set the status of the Candidate Course into PARTIAL_LOCKED.
The Candidate can press the link Lock Partial Visibility which starts payment flow. The flow is:
The system generates UUID, updates the partialLockedReferenceId in the Candidate Course
association with the generated UUID, creates Payment record with that UUID as
REFERENCE_ID and Candidate is redirected to the Payment Gateway. The amount to be
paid is defined as Commercial Term.
The Candidate pays the required amount in the Payment Gateway.
The Payment Gateway redirects the Candidate to our application where the Payment
(identified by the REFERENCE_ID) is completed. The Candidate Course is marked with
partialLockedPaid as true.
The Candidate Course status is set to PARTIAL_LOCKED.
There are visibility states that are controlled by the system:
HIDDEN_NOT_PAYED: Set by the system in the case when Candidate Course or one of its Exams
with PAY_UPON_HIRE commercial term were not paid in a predefined time period (one year)
DEPRECATED: Set by the system automatically after predefined time period since the Course
Exam was first passed (3 years, Candidate Course aging)
The Candidate can’t change the Candidate Course status if the status is HIDDEN_NOT_PAYED or
DEPRECATED.
The Candidate can change the Candidate Course’s visibility by selecting appropriate visibility from drop
down box. Use dropdown box on change event for Ajax update call.
Clicking on Course Exam link shows the Exam into a popup window if completed or starts a page where
Candidate answers the Exam questions.
If the Course Exam is completed already, the panel shall provide the info for that Exam: Score, Time
Started, Time Completed, Passed and Score. Note that we never show to the user which questions
were correct or wrong!
If the Course Exam is NOT completed yet, the Candidate shall continue with the next Question not
answered in the Course Exam into new page (part of the question answer wizard).
During the Exam the system will send proofs to the Server that can serve as Candidate verification. For
example we can capture snapshots on random time interval by using JPEGCAM:
http://code.google.com/p/jpegcam/
For n successfully passed exams, the aggregate exam score for the whole Course is calculated as:
SCR_i: the score for the i-th exam which was passed successfully
ST_i: the Start Time for the i-th exam which was passed successfully
ST_0=INFINITY by convention
Aggregate Exam Score= SUM(SCR_i*e(-i+1)(1+1/(ST_i-ST_i-1))/SUM (e(-i+1)(1+1/(ST_i-ST_i-1))=
=(SCR_1*e(-1+1)(1+1/(ST_1-ST_0)+SCR_2*e(-2+1)(1+1/(ST_2-ST_1)+ SCR_3*e(-3+1)(1+1/(ST_3-ST_2)+…)/
(e(-1+1)(1+1/(ST_1-ST_0)+e(-2+1)(1+1/(ST_2-ST_1)+e(-3+1)(1+1/(ST_3-ST_2)+…)
The formula above represents some kind of weighted average that takes into count the following
requirements:
Each sequential exam shall have lower contribution to the aggregated exam store
The validity of the repeated exam increases with the time period between that exam and the
previous one passed successfully
The Start Time difference is calculated in days. If two Exams are taken in the same days set Start Time
Difference as one day.
For n successfully passed exams, the aggregate proof weight for the whole Course is calculated as the
quotient PROOFABLE_EXAMS/TOTAL_EXAMS where:
PROOFABLE_EXAMS is the number of successfully passed Candidate Exams with associated Exam
Proofs
If the Course Exam was not started yet, the Candidate shall press the Start Button (Link) and follow the
Exam questions as described above.
When the Candidate needs additional Course Exam (in the case when he didn’t pass the initial one or he
wants to improve his scoring) he can buy another one.
For each Commercial Term there is a factor known as Exam Percent Cost. This cost is calculated on the
accumulated cost paid (or planned to be paid).
For example:
The initial cost of Course is 100$ and Exam Percent Cost is 0.2.
The second exam (the first comes along with the materials when the course has been taken) costs
100*0.2=20$.
If the Candidate clicks on the Add New Course Exam the flow is:
Each Course’s Tag can be Endorsed by the Candidate (we don’t keep history of endorsements per user
per course-tag in the database, in the aggregator maybe)(or we shall discuss multiple endorsement
scenario prevention….)
This page shall enlist the Job Posts favored by the Candidate.
The data shall presented in server side AJAX paginated Accordion. The Job Posts shall be sorted by the
Job Post’s Start Date.
Each Accordion content shall consists of 2 tabs: Job Post Details and Related Courses. The content and
the layout of the data in these tabs shall be the same as described in the Search for Jobs section.
Whenever particular Job Post is fetched from the server the number of Candidate Views shall increase.
My Payments
By default the Candidate Payments tab will show the Candidate payments in the last 3 months.
Each row is a payment for particular Course or Bulk of Courses (in the case of Pay upon Hire) or Partial
Locked Payment. For each payment the Candidate can expand the payment in order to see what Course
and (or) Exams were covered with the payment.
The user interface shall allow multiple expanded elements in one moment.
The tab shall contain filtering capabilities that will allow the Candidate to change the date time interval
he is filtering for.
Another tab named Pending Payments shall enlist per Course pending payment information as well as
the total amount to be paid by the Candidate. If there are Candidate hires with status CONFIRMED, but
not BILLED, the UI shall group pending payments per Hire. A Hire includes all pending payments from
the previous hire date +1 day (if any) up to (inclusive) this Hire date. If no previous hire date exists, the
time shall be considered as infinity in the past.
For example if have 2 Hires which are not BILLED (this can’t happen in practice if we run the Billing
process regularly), the UI shall show:
This tab shall have a buttons named Pay Now: One Global (for All Pending Payments) and one per Hire
Section. . By pressing that button :
The system will generate common REFERENCE_ID for all (or per Hire Section) PAY_UPON_HIRE
Courses and Exams the Candidate has taken in the past and are not paid yet. The
REFERENCE_ID is saved into each Course and Exam determined as pending. The total sum to be
paid is calculated as well.
The system generates Payment record with the amount and REFERENCE_ID calculated above.
The system redirects the Candidate to the Payment Gateway
The Candidate pays the amount required
The Payment Gateway redirects the Candidate to our application
The system updates all Courses and Course Exams marked with the REFERENCE_ID returned
from the Payment Gateway as paid. The Payment itself is marked as completed as well.
The amount paid for each Course is added to the InstructorCourse’s accruedAmount:
accruedAmount=accruedAmount+amount*(1-commercialTerm.margin)
The Candidate is redirected to the Candidate Payments tab.
Recruiter’s Functionality
Each Recruiter pays for one of the following level of service:
Basic is the most restrictive level of visibility that a recruiter can have. This level provides only
limited candidate information which is often provided on candidate profiles, their general
skillset, experiences and some general knowledge information like most relevant tags based on
the Candidate Course information.
(Description: The most restrictive level of visibility that a recruiter can have. This level provides
only limited candidate information which is often provided on candidate profiles, their general
skillset, experiences and some general knowledge information like most relevant tags based on
the Candidate Course information)
Intermediate is the intermediate visibility level. This level allows the recruiter to see the courses
that the candidate has taken and passed but we are not presenting the Recruiter the passing
score, i.e. just the information that the course is passed. In addition, this level will not be able to
show any courses which the candidate has not passed.
(Description: Intermediate visibility level. This level allows the recruiter to see the courses that
the candidate has taken and passed but we are not presenting you the passing score, i.e. just the
information that the course is passed. In addition, this level will not be able to show any courses
which the candidate has not passed)
Advanced is the advanced visibility level. This level has all the visibility from the previous levels
and it also includes average candidate exam scores for all of the courses that the candidate has
taken and passed. With this level Recruiter will be able to see courses which the candidate has
passed along with each particular passed exam info (score, duration) except for Course marked
as PARTIAL. For Courses marked as PARTIAL by the candidate only average exam score is
available.
(Description: Advanced visibility level. This level has all the visibility from the previous levels and
it also includes average candidate exam scores for all of the courses that the candidate has
taken and passed. With this level you will be able to see courses which the candidate has passed
along with each particular passed exam info (score, duration) except for courses where
candidate has paid to hide exams information.)
Complete is the most permissive level of service and gives to Recruiter a complete access into
candidate's information. Anything that the candidate wanted to use or information that is
relevant about the candidate is made visible for the Recruiter. This level of service gives the
Recruiter detailed information about each course question and the answer that the candidate
provided on every exam taken, exam proof photos…
(Complete: The most permissive level of service and gives you a complete access into candidate's
information. Anything that the candidate wanted to use or information that is relevant about
the candidate is made visible for you. This level of service gives you detailed information about
each course question and the answer that the candidate provided on every exam taken, exam
proof photos and similar details)
Each Recruiter payment can be for one Month, Quarter and Year.
The Recruiter payments are registered into the table Payment under the following referenceIdTypes:
RECRUITER_L_1 (Basic)
RECRUITER_L_2 (Intermediate)
RECRUITER_L_3 (Advanced)
RECRUITER_L_4 (Complete)
The user interface tab Recruiter contains the functionality related to the Recruiter role.
When the Recruiter logs in, the tab Recruiter shall be visible.
Recruiters shall be able to search for Courses. This way the Recruiter can check what kind of Courses the
system offers, their quality etc.
The Search for Courses shall allow filtering and ordering criteria based on:
Course Id
Course Category
Creation Date
Tags with endorsement weighting above some threshold (logical AND)
Contexts (logical OR)
Name
Number of Candidate Views
Number of Recruiter Views
Number of Candidate Favored (Likes)
Number of Recruiter Favored (Likes)
Recruiter Average Rating
Candidate Average Rating
Aggregate Exam Score
Total Hires
System Verified
RCH Factor
The filter construction logic is the same as described before for the Candidate role.
Each Course can be Favored and Rated by the Recruiter. Specifically, Recruiter can favor the Course
only once. Recruiter can rate the Course and change the rating after that.
Each Course raw contains link: Show Candidates (icon, the most left column in the row). This link will
take the Recruiter to the Search for Candidates page with prepopulated filter for Course Id and run that
query automatically.
The Course popup Windows shall have additional search for Candidate shortcuts:
By Course Id
By Course Context(s)
By Course Tag(s)
By Course Category
The Recruiter shall be able to save his Course search queries into persistent store. One of the queries is
the Default one. The default query is always loaded when the search page has been opened. The rest of
saved queries have name.
This page is the heart of the system. This is a page where Recruiter can retrieve relevant, scored list of
candidates that have passed Exams for Courses in some Category or tagged by combination of Tags.
Also the Recruiter shall be able to search for Candidates based on their profile information regardless if
they have taken Courses or not.
In the most simplistic form the system have to execute statistical query that will:
1. Filter the Courses relevant for the Recruiter: by category, by tag and its relevance (endorsement
weight), creation date, number of views and all other Course filters as defined elsewhere in the
document.
2. Based on the Courses found in step 1, find the Candidate Courses passed successfully. The
query can filter Candidate Courses by aggregateExamScore, passingDate, examProofWeight,
systemSuspected (never consider Candidate Courses with visibility set to PRIVATE,
HIDDEN_BY_SYSTEM and DEPRECATED) and Candidate Profile filter if present.
3. Group Candidate Courses found in step 2 by Candidate and SUM their exam scores as:
SCORE=SUM(COURSE_SCORE_FACTOR * EXAM_SCORE)
4. Order the list of Candidates based on the SCORE found in step 3.
= > Search
The search user interface has to provide TWO filtering dropdown select lists to the Recruiter:
Filter Course By
Filter Candidate By
The dropdown filtering select lists have the following criteria items included:
Filter Course By: This filter has identical structure and organization as in the Search for Courses
page described previously. It shall contain unique (recognizable) color in the user interface. The
criteria balloons produced from this filtering drop down shall have the same color with the drop
down list.
Filter Candidate By: Defines filtering criteria for particular Candidate Courses by
aggregateExamScore, passingDate, examProofWeight, the flag systemSuspected and
Candidate Profile related items like: Name, Location and Mail. This filter also contains the
criteria Exclude Hired Candidates After which will provide Date Picker control in order to
specify if the Recruiter wants to filter out all of the candidates that were hired after specified
Date. For example: Take into account the candidates that were not hired in the last 6 months.
Course Relevance By: This criteria contains multiple selection drop down list where Recruiter
can choose what Course column(s) represents the COURSE_SCORE_FACTOR in the query. The
Recruiter can choose a combination of the following relevance items: candidateViews,
recruiterViews, candidateFavored, recruiterFavored, recruiterRatingAverage,
candidateRatingAverage, totalHires and rchFactor. We shall weight each relevance item
included with coefficient in the range from 0 to 1. The left most relevance item is the most
significant one and the right most relevance item is the less significant one. So for example, if
we have 3 relevance items, the bin intervals are 1/3, the first relevance item from the left has
weight 1, the second from the left has weight 0.66 and the third one from the left has weight
0.33.
Some of the relevance items are long integers and some of them are double numbers between 0
and 1. Before summing up these relevance items, we have to scale each relevance item’s value
in the range [0,1].The search query shall use COURSE_SCORE_FACTOR which is normalized in
the range from 0 to 1.
The Relevance Items from left to right are: recruiterFavored, recruiterRatingAverage, rchFactor.
recruiterRatingAverage=4
rchFactor=0.8
Max(recruiterFavored)=500
=(100-0)/(500-0)=0.2
RI_2=norm(recruiterRatingAverage)=4/5=0.8
RI_3=rchFactor=0.8
RI_2: W_2=0.66
RI_3: W_3=0.33
COURSE_SCORE_FACTOR=(W_1*RI_1+W_2*RI_2+W_3*RI_3)(W_1+W_2+W_3)=
=(1*0.2+0.66*0.8+0.33*0.8)/(1+0.66+0.33)=0.814/2=0.4
If only Candidate Profile related criteria (Location, Mail, Name) is present in the search, the query shall
search the Candidates directly, without considering if they have taken some Courses or not (without
considering any Course related relational joins).
If the search contains both Course and Candidate Profile related criteria, the Candidate Profile based
filtering is applied through the Candidate Course’ candidate field.
The Recruiter shall be able to his Candidate search queries into persistent store. One of the queries is
the Default one. The default query is always loaded when the search page has been opened. The rest of
saved queries have name.
When the Recruiter presses the button Search, the System will present to the Recruiter paginated list of
Candidates ordered by SCORE.
The search action is an AJAX call that returns JSON list of up to 500 results. These results shall fit into
data table with sortable columns as well as in-memory (browser) pagination.
The last column of the results table shall contain View Details link.
Recruiter can press on View Details. The system shall present the Candidate’s info into a popup
window. This popup window will show information that depends on the Recruiter’s subscription level as
defined in the section above.
The Popup window shall have title: “Candidate: <The name of the candidate>".
Relevant Courses: Only show those courses which are relevant for the search criteria; the server
shall return all the courses and we shall filter those courses against the search filter criteria using
JavaScript (this is in the browser filtering because search query is expensive operation to be repeated
if not needed).
All Courses: Shows all the courses.
Profile: User general info and contact information
The courses in the Relevant Courses and All Courses tabs shall be presented into accordion (expand/collapse)
bar. The courses bars should show the name (as is now), the Avg Exam Score and Candidate Exam Score.
These 3 identifiers should be in the collapsible bar.
The tabs Relevant Courses and All Courses are visible only if the Recruiter has role Intermediate and
above.
The popup window must have a button Bookmark. If the Recruiter presses the button Bookmark, an
association record is created in the table Hire with status BOOKMARKED.
We have to provide a side by side comparison for multiple candidates and a checkbox next to each candidate
in the result list as well as a Compare link or button on the lower right of the search filter.
The comparison would first need to normalize the candidate data, sort it by course first, then by exam
results, and then by question. Once we have the data we'll show it side by side and we'll allow collapsing of
the comparison by person (some personal info, location, years of experience etc.)/course (# of courses taken,
average scores)/exam results/questions. The companion document CandidateCompare.xslx shows the
comparison matrix.
The comparison matrix shall be available for recruiters having a role of Intermediate or above with the same
exam details restriction as explained before.
Candidate Hires
The Recruiter shall be able to announce to the system when some Candidate is hired by the Recruiter. If
the Candidate confirms that he was hired by the Recruiter, the System will give to the Recruiter some
Incentives.
By default we shall present the Hire records announced in the last 3 months (date descending). The
page shall also offer filtering of the Hires by:
Date
Status
BOOKMARKED
HIRED
CONFIRMED
DISPUTED
HIRED_DISPUTED
BILLED
BILLED
System
System
Recruiter Candidate
BOOKMARKED HIRED CONFIRMED
Candidate
Recruiter
DISPUTED
Administrator
Administrator
Recruiter
HIRED_DISPUTED
When the button Hire is pressed, the Recruiter shall be present a popup dialog where he will enter the
date when the Candidate was hired.
Whenever the hire status transitions to CONFIRMED (by Candidate accepting the hire or Administrator
that resolves Candidate Hire Dispute), the totalHires field shall be increased for all CandidateCourses
with passing date before the hire date.
Recruiter shall be able to endorse the skills announced on the Candidate’s profile. These are the Skills
that are not confirmed by the system, i.e. imported from LinkedIn or manually entered on the user’s edit
profile page.
In each row in the Hires display table, the Recruiter shall be able to click the link Endorse. By clicking on
this link the system shall show a popup screen where Recruiter can drag from Candidate’s existing skills
and drop the selected skills into a field that can be submitted. This is the same mechanism used when
Candidates and Recruiters endorse course tags. The result of the endorsement is saved into the table
RecruiterCandidateSkillEndorsement. The system shall not allow drag and drop for already endorsed
skills. When saving endorsement, the previous “orphaned” endorsements shall be deleted (these are
endorsements that Recruiter has revoked in the UI or the Candidate has removed them from their
profile)
Note that the Candidate’s skills are saved as part of the Profile Resume which is not kept into database
but into XML saved by the Storage Service. In order to show in the UI the Candidate’s existing Skills we
need to parse XML and extract the Skills from there. Retrieving and parsing that XML all the time is not
practical and efficient. We shall optimize the process by keeping the Candidate’s Skills into Hazelcast
memory bounded and item expire-able map. The items in that map shall be keyed by profile id. The
value is a list of Skills. We shall keep at most M entries in this map (M=100 for example). In order to
keep consistency in the system, the cache map entry shall be cleared whenever user updates his
resume.
Recruiter endorsements take part into the user interaction service which has a purpose of calculating
interactions into some kind of aggregated value (direct user interaction service for demo, real time
purposes and production aggregating user interaction service based on a scheduled execution).
The system shall process these endorsements and the aggregated values per Candidate Skill shall be
saved into the table CandidateSkillScore. The scores are calculated the same way we calculate
endorsement weights for Course Tags.
Job Posts
Recruiter shall be able to submit Job positions that are open in his company. This page enlists all Job
Posts in descending order by the Job’s start date. Each Job Post has the following attributes:
Description
Start Date
End Date
State (CREATED, SUBMITTED, COMPLETED)
Category
Contexts
Tags (collection of tag name plus tag weighting)
Location (State and City, there are optional)
The system shall allow the Recruiter to filter Job Posts by Description, Start Date, End Date, State,
Course Category, City and State.
The Recruiter shall be able to add new Job Post. When Create button is pressed, a popup dialog shall
appear where Recruiter enters the Job Post’s attributes. The tags collection is specific. Besides selecting
tags, the Recruiter shall enter the tags weight too. The user interface shall use the same Balloon type for
course tags as in the Search for Courses or Search for Candidates screens. Multiple tags with the same
name are not allowed.
Rule: The Job Post shall not span more than 3 months. This way we will prevent the system to keep and
maintain never ending Job Posts for which the system has to calculate associated courses
Recruiter shall be able to edit Job Post. Only Job Post in CREATED state are completely editable. For Job
Posts in SUBMITTED the Recruiter can change the End Date only. Job Posts in COMPLETED state can’t
be edited. When the Recruiter clicks on the Edit button (command buttons shall be located in the right
most “action” column), the same popup dialog as in the create use case shall appear. If the course is in
SUBMITTED state then only End Date is editable.
Recruiter shall be able to delete Job Post. Only Job Posts in CREATED state can be deleted.
Recruiter shall be able to submit the Job Post through a button in the Job Post’s table row.
After the Job is submitted, the Recruiter shall be able to add Confirmed Hires to the Job Post. If the
Recruiter clicks on the link Hires (that exists for each Job Post in SUBMITTED or COMPLETED state) a
popup window shall show up. This window enlists in a client side paginated data table at most 500 hires
associated with the job post (the latest hires ordered by hire date, descending). Recruiter shall be able
to add hire to the Job Post by selecting the Hire from select drop down list and pressing the button Add.
The list is populated with all candidates that are not associated with the Job Post already. When
recruiter adds the Job to the Post the state of the Hire will change in the following cases:
If the state of the hire is BOOKMARKED it shall transit to HIRED. In addition the UI shall popup
window where Recruiter will choose the Hire Date.
If the state of the hire is DISPUTED it shall transit to HIRED_DISPUTED.
Also, the Hire shall be disassociated from the Job Post automatically under the following circumstances:
The value in the list shall be Candidate Name+[hireDate]. This drop down shall be dynamic, prefix based
Ajax filtering of hires by the Candidate’s name. The Recruiter shall be also able to disassociate the Hire
from the Job Post by pressing the delete button next to the Hire in the data table.
A scheduled background process shall periodically process the Jobs posted in SUBMITTED state and
associate or de-associate each Job Post with relevant/irrelevant Courses if any.
1. Maintain the state of the Job Posts those End Date has been passed:
a. Query the ids of all Job Posts in the state SUBMITTED and passed End Date (separate
transaction). These are Job Posts that will go into the COMPLETED state.
b. Process the Job Post ids in batches, single transaction (100 for example):
i. Update the state to COMPLETED for all Job Posts with id in the job post id list
currently processed.
ii. From the table CourseJobPost select grouped courses using the following
PSEUDO SQL:
SELECT courseId, COUNT(courseId) as decreaseCount from CourseJobPost
WHERE postId in (job post id list) GROUP BY courseId
iii. In memory group the courseId by their associated decreaseCount returned
above. The map shall logically represent decreaseCount to coursId list lookup.
For example if the query returned the following courseId, decreaseCount list:
1, 3
2, 1
3, 1
4, 2
5, 3
6, 2
1 => [2, 3]
2=> [4, 6]
3=> [1, 5]
iv. Delete all entries in the CourseJobPost table with job post id in the job post id
list currently processed.
v. Update the Course table based on the decreaseCount to courseId list map the
following way:
UPDATE Course set numberOfJobPosts= numberOfJobPosts -decreaseCount
where courseId in (courseId list)
We shall run the above update query for each key in the in-memory map
constructed.
2. For Each Job Post in SUBMITTED state (query in separate transaction that will return job post
ids):
a. Search for Courses based on the Job Post’s Category, Tags and Contexts. The weight of
the tags shall be included in the query. The query shall return the top 500 Courses
ordered by the Course’s rchScore (use separate transaction for this search, i.e. release
the Course table as fast as possible).
b. Based on the Courses returned, the CourseJobPost association shall be updated the
following way (single transaction):
i. If the Course-Job Post association already exists in the table do nothing.
ii. If the Course-Job Post association does not exist in the table, create new
association.
iii. Delete all remaining Course-Job Post associations because they are not relevant
any more.
c. Finally, after all Job Posts are processed, from the table CourseJobPost select grouped
courses using the following PSEUDO SQL (separate transaction):
Similarly as explained above, create in-memory map jobPostCount=> courseId List and
for all different jobPostCount keys in the map execute the Course related update query:
Group all updates in transactions that do not include more than predefined number of
course updates (1000 for example).
For example:
The updates for the in-memory map above, shall be divided into transactions this way:
Recruiter Payments
This page is a simply listing of the Recruiter’s payments in the last 3 years. The page shall also offer date
filter for adjusting the time period the payments are fetched for.
The payments shall be enlisted into a table. The payment (usually the last one) that defines the
Recruiter’s subscription level at the moment shall be highlighted and we need to add word Current in
the Level column. For example:
Complete (Current)
Basic
This page shall also contain a button named Add New Payment. By pressing that button, the Recruiter
initializes a flow to pay his next subscription fee.
If the current subscription is not exhausted and the recruiter wants to pay for lower or equal level as the
current subscription level, the system shall notify the recruiter (warning popup) that he is going to pay
for something that he already has.
When the Add New Payment button is clicked a new page shall be presented where Recruiter will
choose what kind of fee he is going to pay (Commercial Terms from ID=5 to ID=16). The Recruiter
proceeds by clicking the button Pay. After that system goes through the payment cycle:
The system generates REFERENCE_ID and a new Payment is entered into the system. The
amount to be paid depends on the Commercial Term chosen before.
The system redirects the user to the Payment Gateway.
The user will pay the amount required.
The Payment Gateway will redirect the user back to our system.
The payment is completed.
The user’s Security Context Holder shall be renewed with a new Authentication that will reflect
the Granted Authorities (if any) available after the Recruiter has paid a new subscription fee.
The user is redirected to the Recruiter Payments page.
Recruiter Incentives
The Recruiter can have more than one not exhausted subscriptions at one moment. However only one
subscription is active (prevail) at particular time instant.
En example:
At January the first, the Recruiter has paid for 1 year, L1 subscription. On March the fifteen, the same
year, the Recruiter has paid for 3 months, L4 subscription. The active subscription at particular moment
will be:
L1 L4 L1
Each CONFIRMED hire belongs to one and only subscription active at that moment. For example, hire
in April will belong to the L4 subscription period, but not to the L1 subscription period. The system will
count the number of hires per subscription period. Each Recruiter will receive some incentive at the end
of the month (money transferred on his account). The incentive depends on the number of hires made
for some subscription period.
The incentive is measured in percent and the money transferred to the Recruiter’s account is
subscription amount multiplied with that percent.
RCH shall contain an administrator page, Recruiter Incentives, where Administrator will define for each
level and subscription period combination the following parameters:
1. Min Percent
2. Max Percent
3. Max Hires
The table that holds this info is the table RecruiterIncentive and its record changes shall be audited the
same way the system audits the Commercial Term value changes.
The formula for Recruiter’s Incentive percent is linear, threshold function that depends on the number N
of hires for particular subscription period:
FOR N<=0:
INCENTIVE=0
FOR N>MAX_HIRES:
INCENTIVE=MAX_PERCENT
Incentive percent
25
20
Number of Hires
15
10
0
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14
Incentive Percent
Example:
Recruiter has Complete Subscription that costs $500 an year. The Recruiter has 5 hires up to this
moment. The above formula for 5 hires gives Incentive of 14%, or in dollars=$70. The trend will increase
up to 10 hires and the maximum incentive of 20%, or in dollars=$100.
New Subscription record shall be created into the table ReruiterSubscription whenever Recruiters
makes a new subscription payment.
RecruiterSubscription
+id: long
+version: int
+recruiter: Profile
+commercialTerm: CommercialTerm
+startDate: dateTime
+endDate: dateTime
RecruiterIncentive +subscriptionAmount: double
+incentiveMinPercent: int
+id: long +incentiveMaxPercent: int
+version: int +incentiveMaxHires: int
+commercialTerm: CommercialTerm +subscriptionHires: int
+minPercent: int +amountPaid: double
+maxPercent: int +updated: boolean
+maxHires: int
RecruiterSubscriptionHireTransaction
+id: long
+version: int
+recruiterSubscription: RecruiterSubscription
+type: string (enum=debit/credit)
+payment: Payment
+billing: Billing
+status: enum
1. commercialTerm: the recruiter’s subscription level (one of the 4*3=12 types we have)
4. incentiveMinPercent: minPercent copied from the table Recruiter Incentive for the same commercial
term, i.e. the system will use incentive definition that was valid at the moment when some subscription
has been created
5. incentiveMaxPercent: maxPercent copied from the table Recruiter Incentive for the same
commercial term, i.e. the system will use incentive definition that was valid at the moment when some
subscription has been created
6. incentiveMaxHires: maxHires copied from the table Recruiter Incentive for the same commercial
term, i.e. the system will use incentive definition that was valid at the moment when some subscription
has been created
7. subscriptionHires: the number of confirmed hires bound to this subscription, i.e. confirmed hires
those date matches the time range interval(s) when this subscription was considered as active one (the
strongest subscription level).
8. amountPaid: the incentive amount paid to the Recruiter up to some moment, incentive are
transferred to Recruiters on monthly basis (see the algorithm below how to determine how much to pay
to the Recruiter each month).
9. updated: boolean flag that indicates if this record has been updated and shall be processed by the
process that transfers incentive credits to the Recruiter.
1. Find Recruiter Subscription record based on the Hire’s date using the following algorithm:
a. Check if there is Recruiter Subscription rs with rs.startDate<=hireDate<=rs.endDate; if
such Recruiter Subscription exist choose the one with the highest level and return it.
b. If not, check if there exists rs with rs.startDate>=hireDate; if one or more Recruiter
Subscriptions exist, return the one with the smallest startDate; if there are multiple
records with the same smallest startDate, choose and return the record with the
highest level.
c. If not, check if there exists rs with rs.endDate<=hireDate, if one or more Recruiter
Subscriptions exist, return the one with the largest endDate; if there are multiple
records with the same largest endDate, choose and return the record with the highest
level
2. If Recruiter Subscription has been found in step 1 then create Recruiter Subscription Hire
Transaction record of type DEBIT that will reference the Recruiter Subscription found in 1). The
status shall be set to INITIALIZED and billing and payment references are null.
The system shall have cluster singleton scheduled process for processing the Recruiter Subscription Hire
Transaction ‘queue’. This process shall run on relatively small period which is configurable (1 hour for
example). The processor shall process records ordered by creation date, ascending.
Once in a month, the billing process shall generate Recruiter Subscription Hire Transaction record of
type CREDIT for ALL Recruiter Subscriptions with status updated=true. The status of the record is
INITIALIZED, it references appropriate billing record, but the payment is null. This record shall be
processed by the same cluster singleton scheduled process responsible for processing the Recruiter
Subscription Hire Transaction ‘queue’.
incentive =
(maxPercent-minPercent)/ (maxHires -1) * (subscriptionHires-1) + minPercent
ELSE
incentive=maxPercent
incentiveAmount=incentive*subscriptionAmount
paymentAmount=incentiveAmount-amountPaid
3. If paymentAmount>0
a. Transfer the paymentAmount to the Recruiter’s account.
b. Create Payment record and reference that record inside Recruiter Subscription Hire
Transaction.
c. Set Recruiter Subscription’s field amountPaid=incentiveAmount.
4. Set Recruiter Subscription’s field updated=false.
5. Set the Recruiter Subscription Hire Transaction status to COMPLETED.
Administrator’s Functionality
The Administrator tab is visible for users having the Administrator role. This tab provides access to the
following pages:
1. Submitted Courses
2. Categories
3. Tags
4. Commercial Terms
5. Hire Disputes
Submitted Courses
We shall present the courses in SUBMITTED state (date ascending order by Last Updated On). The Page
also provides filtering functionality by:
Each course shall be presented with expand/collapse panel (+/-). When the course row is clicked, the
Course information shall be expanded. The administrator shall be able to see the Course information
and all the links related to that Course:
1. Preview Material
2. Material
3. Exam
4. Comments
For each Course, the Administrator shall be able to press one of these 2 buttons: Approve, Reject.
If the Course was never approved before, the Administrator can execute both actions. If the Course was
Approved once (it was public), the Administrator can only Approve the Course (this is the situation
when the Course was Deprecated and re-submitted after that).
After pressing the button Approve or Reject, the page shall be reloaded with the next Course available
for approval.
Categories
Administrators shall be able to view, create, edit and delete categories. The number of categories in the
system is not large, so this page shall fetch and paginate the categories inside the browser.
Tags
Administrators shall be able to view, create, edit and delete tags. The number of categories in the
system is large, so this page shall fetch and paginate the categories from the server.
Commercial Terms
Administrators shall be able to update the values of the system’s commercial terms. The administrators
can’t add new commercial terms or delete existing ones through the user interface. Also not all values
for individual commercial terms are relevant. The following matrix depicts the relevant (editable) values
for each commercial term defined in the system.
CommercialTermAuditLog
+id: long
+CommercialTerm: CommercialTerm
+changeUuid
+fieldName: String
+oldValue: double
+newValue: double
+changedBy: long
Only changed values are audited. If multiple values are changed into the same save action, they are
grouped under the same changeUuid.
Hire Disputes
The administrator shall query for all hires that are in the state HIRED_DISPUTED. The oldest one shall be
located on the top.
The administrator shall be able to change the status into CONFIRMED or BOOKMARKED.
Each row has information about the candidate and the recruiter, hire date etc. (i.e. all the elements
already present on the hires screen). The administrator shall be able to click on candidate and recruiter
and he shall be presented with popup window. The candidate popup shall be the same as the popup we
use in the Search for Candidates screen for L4 (Advanced) recruiter level. The recruiter popup shall have
2 tabs: Profile and Hires. The Hires tab shall present all previous confirmed hires and hires in the state
DISPUTED or HIRED_DISPUTED. The screen shall group the hires on the screen based on their status:
Confirmed, Disputed, Hired Disputed.
Administrator shall be able to search for Courses. The Search for Courses functionality is the same as the
Search for Courses functionality implemented for Candidates and Recruiters. The Administrator can
bookmark some course (this is the same the same favoring button found in the UI elsewhere).
In addition Administrator shall be able to mark some course as System Verified. System Verified is a
mechanism to boost some Course relevance if the system has verified in a special manner that the
course is relevant (out of band check by hired educators to check the quality of the materials). The
System Verified widget shall be a checkmark with 2 facets: filled that means course is verified and empty
or grayed (just the contours) that means unverified.
The Administrator has the same Candidate and Candidate Exam visibility as Level 4 (Complete)
Recruiter.
The Administrator shall be able to mark some Candidate Courses (in the Candidate popup) as System
Suspected. Use some icon for visual presentation: (the suspicions icon for example). Use the grayed
icon version for Candidate Courses that are not system suspected.
Bookmarks
The Bookmarks page shall have 2 tabs: Bookmarked Courses and Bookmarked Candidates. The content
in both of these tabs shall have server side pagination.
The Bookmarked Courses tab shall have the same functionality as Recruiter’s or Candidate’s Favorite
Courses tab. Here too, Administrator shall be able to set/unset the System Verified flag on the Courses
shown.
The Bookmarked Candidates tab shall have data table look and feel with columns First Name, Last Name
and Email as well as the View Details trigger (the same table structure found in the Search for
Candidates without Relative Rank and Compare columns). The bookmarked Candidates shall be always
fetched initially by creation date, descending.
In the popup present when the View Details link has been pressed, the Administrator shall be able to
set/unset the System Suspected flag for some Candidate Course.
Company Profiles
On the Company Profiles page Administrator shall be able to create, edit and remove Companies.
Company Profile is RCH entity that groups several Recruiters. Each Company Profile has the following
attributes:
Name
Code (UUID)
Discount (decimal number between 0 and 1 (percent) for Recruiter level subscription cost)
Representative email
On this page Administrator shall be able to create, edit and delete Company Profiles.
The Administrator shall be also able to search for Company Profiles by Name, Code, Discount (greater
than some percent) and Representative Email.
The Company Profiles shall be enlisted into table with server side pagination (unbounded number of
Companies can be created, so client side pagination is not an option).
The Company Profile create and edit functionality shall be located into a popup window (the same
window style we use in the other screens).
When the Administrator creates a Company Profile he shall be able to define Name, Discount and
Representative Email. The Code is generated UUID by the System.
There are shall be 4 links in the right most column in each Company Profile related row:
Edit
Delete
Change Code
Recruiters
In the Edit popup dialog the Administrator shall be able to change Company Name, Discount and
Representative Email. When the Company Profile is edited and new information is persisted an email
shall be sent to Representative Email and optionally to the old Representative Email if they don’t
match.
When the Company Profile is deleted, all associated Recruiters shall be disassociated first and after the
deletion an email shall be sent to the deleted Company Representative. An Email shall be sent to the all
disassociated Recruiters too.
When the Code is Changed, an email shall be associated to the Company Representative (this way the
representative will be able to share the info with his Recruiters).
Important: Send the email only after the transaction was committed successfully. In order to accomplish
start from service method that is not transactional, call transactional save method and send the mail
after that through the notification service.
The Recruiters link shall bring up popup containing all associated Recruiters with the Company Profile.
This is a table with client side pagination (we assume the number of Recruiters won’t be more than tens
to several hundreds). The right most column in the table shall contain checkbox for each Recruiter. On
the top of the popup we need a button with name Remove. By pressing this button the selected
Recruiters will be disassociated from the Company and notification email shall be sent to all of them as
well as to the Company Representative.
Company representative reports abuse, i.e. Company Code was somehow revealed to unwanted
persons, or the Recruiter has left the company.
The Administrator will Change the Company Code
The Administrator will Remove the Recruiter(s) from the Company
In the first tab, Hire Past Due Payments, Administrator shall be able to enlist all Candidates which were
Hired but their state is not Billed after the period of 2* payment due date (2*30 days). Note that we will
enlist the candidate only once, even if multiple Hires satisfy the searching condition (not in the Billing
state after predefined period). We are using twice of due date because when the billing starts we don’t
know when it ends (after 1, 2, 5, 10 etc. days). However we know that the Billing must occur every
month, i.e. the system guarantees that the billing process won’t last more than 30 days max.
The users shall be presented with Ajax, server side paginated Accordion. The accordion details shall
present section with 2 tabs: Profile and Payments. The Profile tab shall be the same as the Profile tab on
the other screens (in the Candidate popup windows). The Payments tab shall enlist all Payments related
to Hires those due date has been passed. This shall be the same view as on the Candidate Payments, Pay
Upon Hire related tab.
Note that some users can take Pay Upon Hire Courses and Exams, but they will never be hired. The
system MUST bill those Candidates after some predefined time period (3 years for example).
The second tab on the screen System Past Due Payments is related to this feature. This tab shall enlist
all users that have unpaid PUH payments in a period of more than 3 years (this a system configuration
that comes from a property file). The users shall be enlisted in a server side paginated Accordion. The
user having the oldest unpaid course or exam shall be on the top of the list. The content definition
inside the accordion shall be the same as explained above for the first tab.