Database
August 24, 2025 ยท View on GitHub
PostgrSQL was chosen, because it offers ACID transactions. There will only be hundreds of users and materials. Material files can be pdf-, word-, powerpoint, excel or picture files or a link to another webpage. Most of them have single page. Because of that it was decided to upload material files to Postgres as blobs.
Schema
Schema is based around materials. Each material has a single user who has uploaded that material to the database. Each material can have several tags which mark what the material is used for. Each user has a favorites list where they can mark their favorite materials.
erDiagram
%% Schemas and Tables
Materials {
SERIAL id
VARCHAR(50) name
VARCHAR(500) description
BOOLEAN visible
INTEGER user_id
BOOLEAN is_URL
VARCHAR(120) URL
BYTEA material
VARCHAR(255) material_type
TIMESTAMP created_at
TIMESTAMP updated_at
}
Users {
SERIAL id
VARCHAR(128) username
VARCHAR(128) first_name
VARCHAR(128) last_name
VARCHAR(128) password
VARCHAR(50) role
TIMESTAMP created_at
TIMESTAMP updated_at
}
Tags {
SERIAL id
VARCHAR(50) name
VARCHAR(10) color
}
Favorites {
SERIAL id
INTEGER material_id
INTEGER user_id
}
Tags_Materials {
INTEGER material_id
INTEGER tag_id
}
Packages {
SERIAL id
VARCCHAR(100) name
TEXT description
}
Packages_Materials {
INTEGER package_id
INTEGER material_id
INTEGER position
}
%% Relationships
Users ||--o{ Favorites : "user_id"
Materials ||--o{ Favorites : "material_id"
Materials ||--o{ Tags_Materials : "material_id"
Materials ||--o{ Packages_Materials : "material_id"
Tags ||--o{ Tags_Materials : "tag_id"
Users ||--o{ Materials : "user_id"
Packages ||--o{ Packages_Materials : "package_id"
There are timestamps on materials and users. Timestamps for users give information when the password has been renewed last time. Password is forced to renew at least once a year. Timestamps for materials have no use at the moment, but are inserted for future use. PostgreSQL triggers are used to update timestamps updated_at.
Sequelize is used for queries. It does not handle database-level triggers. The schema has been run directly to the database. To avoid problems do not use sequelize.sync() with force or alter options.
Here is the PostgerSQL schema.