Topic: How Kakama Works: a quick technical overview
Topic type: Topic
A quick technical overview of the various functions of each of Kakama's models (targeted towards Ruby on Rails developers).
I can't document everything, but here is a brief overview of the various important complex models. Please excuse the unformated scriblings :-) Each model has integration tests in features. There are as isolated as they can be (that is, event tests won't only test role related stuff, they'll stick to code in the event model as much as possible).
Availability
An availability belongs to a staff member, and staff have many availabilities. Staff can edit them, and so can admins. Each availability has a start date and end date, and hours, which is a serialized hash containing :mon-:sun symbols at the top level, followed by an array under each, containing a hash of :start (hour), :end (hour) and :comment (for that particular time). It is done this way because a staff member might have multiple time blocks on a given day. Here is an example of the hours column for monday of someone who works 9am-12pm, then 3pm-6pm). Times are in 24 hour integer format, with leading 0's stripped:
{
:mon => [
{ :start => 9, :finish => 12, :comment => 'I have an appointment soon after this' },
{ :start => 15, :finish => 18, :comment => 'An appointment before this might run late' }
]
}
Event
An event belongs to a venue, and venues have many events. Events have a name, description, start date and time, end date and time, an organiser (the person who made the event), and an approver (the person who approved the events roster). It also contains a serialized roles column, containing a hash with role id's at the top level, and the amount required for each as the value, which is used when trying to fill roles. e.g.
{
1 => 10
2 => 5
}
When an event is approved, the event is responsible for checking people assigned are available, assigning more staff if needed, and notifying people of the change.
Notifier, EmailLog, and PDFGenerator
The main model for contacting staff is Notifier. All mail goes through the Notifier.deliver_email_or_pdf_of method. This either emails the person if they have an email, or generates a PDF and emails it to a site admin email for snail mail delivery.
The PDF Generator uses Prawn for generate PDF's. The model itself is a subclass of the PdfGeneration class (lib/pdf_generation.pdf) which gives an ActionMailer style interface to generating PDF's.
Every email sent is logged to the EmailLog, with the staff id, event id and information related to the emailing, for debugging purposed and record keeping.
Rostering
This is what ties everything together. When an event is made, staff are found in the event model, but then they are rostered through this. Rostering is a very simple table. staff id, event id, role id, and state. A rostering can be unconfirmed (the staff member was rostered but not done anything about it), confirmed (staff member confirmed they will be there), rejected (admin doesn't want that staff member), declined (staff member can't/won't come), cancelled (staff member no longer needed), and no show (staff member was assigned but never came).
A lot of interaction between the rostering and event models happens here. The integration tests (features/rosterings.feature) give a pretty good idea of what goes on in the model. In particular, the queue_expiration method is important. The system is deigned to auto-delcine a rostering after a certain amount of time. delayed job is used to do this. The Rostering#queue_expiration method enqueues the job required to do this, and needs to be as simple/fast as possible to accomodate potentially 100's in one go.
Staff
Staff logins are managed via authlogic. There isn't too much different from most other user models. There is a start_date of when each staff members starts, which eventually will be used to allow staff to be created before they join, and not be selected for work until events after that time, but current doesn't nothing other than display. The admin_notes column is for admin eyes only, used for work related notes like no shows and comments about performance. Staff have many availabilities, many rosterings, many events through rosterings, they have many roles, and have many staff details (like phone number, address etc).
Other
Whenever (the gem for making cron jobs) is used to make sure things are run every days. Namely:
- Every computer reboot, it'll start up delayed_job so you don't have to remember to
- every day (usually 12am) it'll run Event.fill_all_empty_roles
Event.fill_all_empty_roles is the method used to find all events that haven't yet been filled, and try to find some staff to fill the role. If it finds some, it'll send our notifications when needed. This keeps the system pretty easy to manage (i.e. you set what you want and over time it'll fill them, so you don't need to manage each event every day).
The Schedule model and schedule_id on events is unused. Eventually it would be nice to have events that reoccur, but original budget did not allow for this work to be complete, but what had been done has been left in.
Code Structure
The code uses strict guidelines. Most tests are full cucumber features. Models are layed out in the same order (see app/models/MODEL_STRUCTURE). Models do nearly everything. Controllers do not do any mailing. They take params, pass them in, and redirect with flash messages. So a lot of the coding you'll do for fixes or new features will be in app/models and features directories.

