In today's exercise we are looking at the Document Kit for PM & UI/UX Designer product. It is a set of resource templates to make it easier to build, research and design a fully digital products. The resource kit is based upon a Notion workspace. What happens if we want to turn this product into a paying SaaS and need a database for it?
To analyze this product, we are heading over to the product's overview. To simplify this exercise, only the first four sections are relevant:
User-Centered Business Canvas
Those section has the following fields
- Problems, Needs
- Existing solutions
- Users
- Early adopters
- User fears
- User goals
- Solution
- Value proposition
- Acquisition channels
- Revenue sources
- Metrics
User Persona

A user persona has
- Name
- Age
- Job title
- Status
- Location
- Some sort of tags
- Some sort favorite brands
- About section
- Goal section
- Pain points
- Needs
- A scala for different aspects of their personality between 0 and 100
User Stories

This is basically a simple issue tracker to identify the requirements of a digital product. A user story
- belongs to a role or person.
- belongs to a category.
- has a goal.
- has a reason.
- can have details.
- can have additional notes or questions.
- can have todos.
User Empathy map
The User Empathy Map is an optional document for a User Persona and consists of the sections
- Think & Feel
- Hear
- See
- Say & Do
- Pains
- Gains
Some notes
As you can see, there can be a lot text entered. Most of the fields contain multiple list items.
For this very exercise, we assume that each list item is not extracted into single database rows.
Solution
- Please note that for a more extendable version we would use a completely different database design. Most of the freetext columns would be extracted and normalized into its own table.
Schema

// the SaaS customer
Table tenant {
id integer [primary key, not null, unique]
// in this case we are using guids as public IDs as this is a multi-tenancy application
guid uuid [primary key, not null, unique]
name char(128) [not null]
}
// a project inside a customer's environment
Table project {
id integer [primary key, not null, unique]
// in this case we are using guids as public IDs as this is a multi-tenancy application
guid uuid [primary key, not null, unique]
name char(128) [not null]
tenant_id integer [not null, ref: > tenant.id]
}
// a project has one business canvas
Table business_canvas {
id integer [primary key, not null, unique]
// no need for guid as the business canvas can not be directly edited as it is tied to the project
problems_needs text [null]
existing_solutions text [null]
users text [null]
early_adopters text [null]
user_fears text [null]
user_goals text [null]
solution text [null]
value_proposition text [null]
acquisition_channels text [null]
revenue_sources text [null]
metrics text [null]
project_id integer [not null, ref: > project.id]
}
// a project has multiple personas
Table persona {
id integer [primary key, not null, unique]
guid uuid [primary key, not null, unique]
name char(255) [not null]
age integer [not null]
job_title char(255) [not null]
location char(255) [not null]
// let's use json for storing metadata. In this context it is probably not so important to find similarities over different personas which would justify dedicated tables for brands and tags
tags json [not null]
favorite_brands json [not null]
about text [not null]
goal text [not null]
pain_points text [not null]
needs text [not null]
// we keep the scaling easy
personality_introvert_extrovert integer [not null]
personality_analytical_creative integer [not null]
personality_busy_time_rich integer [not null]
personality_messy_organized integer [not null]
personality_independent_team_player integer [not null]
project_id integer [not null, ref: > project.id]
}
Table user_story_category {
id integer [primary key, not null, unique]
guid uuid [primary key, not null, unique]
name char(255) [not null]
project_id integer [not null, ref: > project.id]
}
Table user_story_role {
id integer [primary key, not null, unique]
guid uuid [primary key, not null, unique]
name char(255) [not null]
project_id integer [not null, ref: > project.id]
}
Table user_story {
id integer [primary key, not null, unique]
guid uuid [primary key, not null, unique]
goal text [not null]
// optional free text
reason text [not null]
details text [null]
notes_questions text [null]
todos text [null]
// per screenshot, all user stories belongs to one category and one role
user_story_category_id integer [not null, ref: > user_story_category.id]
user_story_role_id integer [not null, ref: > user_story_role.id]
project_id integer [not null, ref: > project.id]
}
Table user_empathy_map {
id integer [primary key, not null, unique]
// no guid as the empathy map is directly bound to a persona and won't be edited on its own
think_feel text [null]
hear text [null]
see text [null]
say_do text [null]
gains text [null]
// explicitly *no* pains columns as this is already present on the persona itself
persona_id integer [not null, ref: > persona.id]
}