hasgeek / hasjob

Hasjob, the Hasgeek job board
https://hasjob.co
GNU Affero General Public License v3.0
240 stars 80 forks source link

Promoted listings #165

Open jace opened 9 years ago

jace commented 9 years ago

Promoted (pinned based on targeting criteria) listings on Hasjob require multiple components to be in place. First, assumptions:

  1. Listings will be targeted by whether the user is logged in, the user's location, and optionally, similarity to another job they are looking at.
  2. Listings can be promoted in the index page or in related listings when looking at a job, or both. Since only about 25% of traffic comes to the home page, related listings are a significant opportunity with breadth of inventory. However, the current positioning below a listing isn't optimal; they should be on the side.
  3. Promotions are counted in session-impressions with a limit of two sessions per user. An impression is when a job stickie is displayed to a user. The user may or may not click on an impression. Since this is subject to the quality of the headline written, HasGeek can't be responsible for its performance.
  4. Each session-impression is charged one or more credits, depending on the bid placed. Repeated impressions within the same session are not charged (user refreshing page, etc). However, repeated impressions are not guaranteed if a competing bid is found.
  5. There are only three pinned listings on any page and the highest bidders that match target criteria are selected.
  6. It's unclear whether we should allow targeting by whether the user is logged in or not. Maybe anon impressions can be free to protect from mischief such as repeatedly opening an incognito window and refreshing.

To achieve this, we'll need the following models:

  1. CreditTransaction an increase or decrease of credits available to the user. The credit balance is always calculated as the sum of credit transactions. Transactions may have a financial value if linked to a payment gateway, but could also be grants from an admin, or could be system generated (free credits for signing up, etc).
  2. PinnedBid is a bid for having a job pinned against target criteria. It's linked to a JobPost, specifies a bid value (credits per impression, higher = greater chance of winning), has a start and end date, has a CreditTransaction via which it is funded, and has a credit_balance that's updated via a batch job. When the date expires and if there's any balance left, a second CreditTransaction refunds the balance to the user.
  3. The existing JobImpression gets a new foreign key to PinnedBid that records when an impression was the result of a bid and a new boolean column not_anon that contains JobImpression.event_session.user is not None as a convenience cache value to make counting faster.
  4. UserJobView and UserAnonView get a session_count column mirroring CampaignView and CampaignAnonView's session_count. New models UserBidImpression and AnonBidImpression mirror the function of CampaignView and CampaignAnonView, including session_count columns. These are used to determine when a PinnedBid should no longer be considered for a given user. Since counting is only triggered on an impression, a limit of two session-impressions per user will mean there will be at least one impression in a third session, with the pinned stickie disappearing immediately afterwards (since session_count is no longer <= 2). This is not good news for the bidder as it increments their session-impressions by one without receiving full visibility for that session. That makes session_count harder unless we change the session_count update to trigger on session timeout (periodic cronjob) or new session creation (within EventSession.get_session).
  5. A PinnedBid's credit balance can drop below zero if session counting took too long to complete. This is okay and can be written off. If there is a positive balance after the end time expires, that's refunded.
  6. Any user can place a bid to promote any job, but credits can't be transferred or refunded as cash. Unused credits may expire, but that is out of scope for this ticket.
jace commented 9 years ago

Idea: If the session was initiated by the promoter (campaign tag matches), don't charge for the impression. Tricky to implement if there are multiple active bids, or the referral link continues to send traffic long after an initial campaign has run.

jace commented 9 years ago

Perhaps this will be easier if credits are for number of users reached rather than number of session-impressions, since our other metrics are all about users.

jace commented 9 years ago

Flip side to charging for users: we cannot meaningfully charge for anonymous users, and one of the promotion opportunities is embedded listings on third party websites, where the likelihood of a logged in user showing up is very small. We'll have to charge for anonymous impressions there.

ghost commented 9 years ago

What about keyword targetting? (because exposing flags related to visibility to users, employers would confuse employers).

jace commented 9 years ago

PinnedBid implies the bid is for pinning alone. We may have other forms of bidding for visibility in future, including featuring on network sites, in email alerts and more. I propose renaming the model to just Bid, with a bid_type column indicating the bid is for pinning. The rest of this issue describes the framework required for pinning and so can remain as is.

jace commented 9 years ago

As a temporary workaround for the Mar 19 comment above, since the Bid model has a bid_type column, we could have a "pin" type now that only charges for users, making anonymous impressions free (but selected by bid), while a future type could charge for impressions and so be suitable for use on third party websites.

We'll have to work out how we present this choice to employers placing bids.

jace commented 8 years ago

Performance dependencies that need to be closed first: #309 and #318.

iambibhas commented 6 years ago

Performance dependencies that need to be closed first: #309 and #318.

Update: #318 is closed. #309 is not.