System requirements
Functional:
- web api that allows individual users to buy and sell tickets
- user can view events by location
- user can view events by performer
- user can purchase up to 10 tickets per event
- user can sell previously purchased tickets (only tickets bought on this platform)
- vendors are able to upload/remove tickets
- vendor can add tickets
- vendor can remove tickets
- scalping prevention - limit the number of tickets purchasable by individual users. Also, prevent reselling the ticket at higher rate than the purchase price.
Non-Functional:
- consistency - only 1 user can buy a particular ticket
- highly available
- focus on read performance as user experience consists more of searching for tickets (expected ratio 10:1 reads to writes)
- https to enforce password security
Capacity estimation
- Expected number of daily user sessions is 10000, which is ~3650000 user sessions yearly.
- Individual users buy tickets around 2-3 times monthly, which is 24-36 times yearly.
- Unique user estimation:
- lower bound: 3650000 user sessions / 24 yearly session ~= 152083 users
- upper bound: all sessions are unique first-time users, so 3650000 users
- user table size: 3650000 users * 561 bytes = 2047650000 bytes ~2GB
- Expected number of vendors is 100
- Vendors treated same as user except with different application permissions (upload/remove tickets and venues, no ability to buy or sell)
API design
- UserService
- create-user
- parameters:
- username
- first name
- last name
- password
- type of user (vendor, individual)
- PUT request with parameters in body
- Returns 200 OK on success, 400 BAD REQUEST on failure
- login
- parameters:
- username
- password
- POST request with parameters in body
- Returns 200 OK and JWT on success, 400 BAD REQUEST on failure
- TicketService
- view-tickets
- Requires JWT
- JWT parsed and username extracted
- GET request
- Returns 200 OK and list of all tickets associated with the user (if vendor, these are the uploaded tickets, otherwise for individual, these are the purchased tickets), otherwise 400 BAD REQUEST on failure
- view-venues:
- Optional Parameters:
- name
- city
- state
- country
- postal-code
- Requires JWT
- GET request
- Returns 200 OK and list of all venues (filtered by optional parameters if any), otherwise 400 BAD REQUEST on failure
- add-venue:
- Parameters:
- name
- street-address
- city
- state
- country
- postal-code
- addl-address
- Requires JWT and user to be vendor
- PUT request
- Returns venue id and 200 OK on success, 400 BAD REQUEST on failure
- add-performer:
- Parameters:
- name
- description
- Requires JWT and user to be vendor
- PUT request
- Returns performer id and 200 OK on success, 400 BAD REQUEST otherwise
- view-events:
- Parameters:
- venue-id
- start_time
- end_time
- performer-id
- Requires JWT
- GET Request
- Returns 200 OK and list of events with their performers and venue (filtered by optional parameters) on success, 400 BAD REQUEST otherwise
- add-performer-to-event:
- Parameters:
- performer-id
- event-id
- Requires JWT and user to be vendor
- PUT request
- Returns 200 OK on success, 400 BAD REQUEST on failure
- upload-ticket:
- Parameters:
- event-id
- count
- section
- seat
- price
- PUT request
- Requires JWT and user to be vendor
- Returns ticket id and 200 OK on success, 400 BAD REQUEST on failure
- sell-ticket
- Parameters:
- ticket-id
- count
- Requires JWT and user to be individual
- Removes ticket from user ticket table (decreases count if count > 1) and inserts into user selling ticket table
- Returns 200 OK on success, 400 BAD REQUEST on failure
- buy-ticket:
- Parameters:
- ticket-id
- count
- Requires JWT and user to be individual
- Ensure the user is not attempting to buy beyond the 10 ticket-per-event threshold
- Interacts with 3rd party payment service (e.g. PAYPAL) to procure payment
- Returns 200 OK on success , 400 BAD REQUEST on failure
Database design
- user table
- Contains information about a user.
- columns: user_name VARCHAR(15) NOT NULL, first_name VARCHAR(255), last_name VARCHAR(255), password_hash VARCHAR(31) NOT NULL, user_type CHAR(1) NOT NULL
- row size: 15+1+255+1+255+1+31+1+1=561 bytes
- user_name is unique and serves as PK
- user_type is 'I' for individual, 'V' for vendor
- event table
- Contains information describing events.
- columns: id VARCHAR(15) NOT NULL, venue_id VARCHAR(15) NOT NULL, name VARCHAR(255) NOT NULL, description VARCHAR(511), start_time TIMESTAMP NOT NULL, end_time TIMESTAMP NOT NULL
- row size: 15+1+15+1+255+1+26+26=340 bytes
- id is PK
- venue_id is FK to venue table
- performer table:
- Contains information about a performer.
- columns: id VARCHAR(15) NOT NULL, name VARCHAR(255) NOT NULL, description VARCHAR(511)
- row size: 15+1+255+1+255+1=528 bytes
- performance table:
- Maps 1+ performers to 1+ events
- columns: event_id VARCHAR(15) NOT NULL, performer_id VARCHAR(15) NOT NULL
- row size: 15+1+15+1=32 bytes
- event_id and performer_id form composite PK
- event_id is FK to event table
- performer_id is FK to performer table
- ticket table
- columns: id VARCHAR(15) NOT NULL, event_id VARCHAR(15) NOT NULL, count INTEGER NOT NULL, section VARCHAR(15), seat VARCHAR(15) NOT NULL, price DECIMAL NOT NULL
- row size: 15+1+15+1+8+15+1+15+1+8=80 bytes
- id is PK
- event_id is FK to event table
- user ticket table:
- columns: user_name VARCHAR(15) NOT NULL, ticket_id VARCHAR(15) NOT NULL, count INTEGER NOT NULL, purchase_date TIMESTAMP
- row size: 15+1+15+1+8+26=66 bytes
- user selling ticket table:
- columns: user_name VARCHAR(15) NOT NULL, ticket_id VARCHAR(15) NOT NULL, count INTEGER NOT NULL, purchase_date TIMESTAMP
- row size: 15+1+15+1+8+26=66 bytes
- venue table
- columns: id VARCHAR(15) NOT NULL, name VARCHAR(255) NOT NULL, street_address VARCHAR(255) NOT NULL, city VARCHAR(255) NOT NULL, state VARCHAR(255), country VARCHAR(255) NOT NULL, postal_code VARCHAR(15), addl_address VARCHAR(255)
- row size: 15+1+255+1+255+1=528 bytes
- id is PK
- contains normal fields for street, city, state, country, and postal code as well as an additional address field in case the previous fields are still insufficient
High-level design
flowchart TD
USER[USER] --> LB{LOAD BALANCER}
LB --> API_GATEWAY[API GATEWAY]
API_GATEWAY --> USER_SERVICE[USER SERVICE]
API_GATEWAY --> TICKET_SERVICE[TICKET SERVICE]
USER_SERVICE -- CREATE USER --> MASTER_DB[(MASTER DB)]
USER_SERVICE -- LOGIN --> READ_REPLICA_DB
MASTER_DB --> READ_REPLICA_DB[(READ REPLICA DB)]
TICKET_SERVICE --> TICKET_CACHE[CACHE]
TICKET_CACHE -- VIEW TICKETS/VENUES/EVENTS --> READ_REPLICA_DB
TICKET_CACHE -- ADD/SELL TICKETS/VENUES/EVENTS --> MASTER_DB
TICKET_SERVICE -- BUY TICKET --> PAYMENT_SERVICE[PAYMENT SERVICE]
PAYMENT_SERVICE ----> EXTERNAL_PAYMENT_SERVICE[EXTERNAL PAYMENT SERVICE]
PAYMENT_SERVICE --> MASTER_DB
Request flows
Explain how the request flows from end to end in your high level design. Also you could draw a sequence diagram using the diagramming tool to enhance your explanation...
Detailed component design
Dig deeper into 2-3 components and explain in detail how they work. For example, how well does each component scale? Any relevant algorithm or data structure you like to use for a component? Also you could draw a diagram using the diagramming tool to enhance your design...
Trade offs/Tech choices
Explain any trade offs you have made and why you made certain tech choices...
Failure scenarios/bottlenecks
Try to discuss as many failure scenarios/bottlenecks as possible.
Future improvements
What are some future improvements you would make? How would you mitigate the failure scenario(s) you described above?