Search code examples
databasesaasaccount

How to handle expired free-accounts in a SaaS environment


This is a bit philosophical, however, here is the scenario and the related question. Suppose you sell premium accounts and at the same time offer time-limited free accounts. Users register and log in using their email address. Creating a free account does not require handing over any overly sensitive data (just the email). Free users have X days to evaluate your service then either upgrade to a premium account or see their free account expire.

The question is: how to best handle that "expired" database-wise?

You could:

1) keep the account in your global "user" table marking it is as expired

  • PRO: username/email is always unique and one cannot re-register with the same email
  • CON: one cannot re-register with the same email (maybe he wants to do just that after a new feature he is interested in is added)
  • PRO: all accounts are in one place, easier handling of stats retrieval
  • CON: user table can only get bigger over time

2) remove the account, possibly moving it to a user_history or expired_user table

  • PRO: your user table is smaller and contains only data from "live" users
  • CON: username/email of an expired account is re-usable (your logs are likely to get messed up, and you have to always log the userID other then the username since that would not be unique anymore)
  • PRO: username/email of an expired account is re-usable (expired users that want to give the trial another run after new features are added can do so without being forced to pick another email address)
  • CON: user stats gathering gets more complicated

Has anyone faced the same problem?


Solution

  • I'd suggest splitting the schema into two:

    TABLE: users
    user_id (PK)
    email_address
    password_hash
    ....
    
    TABLE: user_status
    user_status_id (PK)
    user_id (FK)
    status_date
    status_value
    

    The current status of a given account is the one with the latest status date. When the user signs up for a "free" account, you insert a record into user_status with status value "new_free_status"; when the account expires, you insert a record with status value "free_account_expired". You use the status to check whether a user can log in or not; if you want to allow people to sign up at least one month after their free account last expired, you check the user status record to see when their account was closed.

    You can, of course, create another lookup table called "status", and join to a table with "account_type" - that way, your data becomes more self-describing.

    The key thing in this design is that you want to separate the user profile from the current status, and keep track of that status over time. This allows you to answer questions like "how many people signed up for a paid account after having a trial?", "how long between signing up for a free account do people upgrade?", "how many users come back for another trial?" etc.