diff --git a/documentation.md b/documentation.md index d1e8d04..d0a477b 100644 --- a/documentation.md +++ b/documentation.md @@ -1 +1,85 @@ -# documentation file +# Database Schema & Migration Module + +## Overview + +This module implements the database layer for a project management system using SQLite and Knex.js. + +Includes: +- Database configuration +- migrations +- Seed data +- ER diagram + +### Backend + +- Node.js +- Knex.js + +### Database + +- SQLite + +## Project Structure +text +task-4-database-schema/ +├── src/ +│ ├── config/ +│ │ └── db.js +│ ├── migrations/ +│ │ ├── create_users.js +│ │ ├── create_projects.js +│ │ └── create_project_events.js +│ └── seeds/ +│ └── seed_initial_data.js +├── database.sqlite +├── knexfile.js +├── README.md +├── ER_DIAGRAM.md +└── documentation.md + +## Database Schema + +### Users +- id (Primary Key) +- name +- email (Unique) +- role + +### Projects +- id (Primary Key) +- name +- description +- status +- owner_id (Foreign Key → Users.id) + +### Project Events +- id (Primary Key) +- project_id (Foreign Key → Projects.id) +- event_type +- description +- created_at + +## Relationships +- One User can own multiple Projects. +- One Project can contain multiple Project Events. + +### Install + +```bash +npm install + +### Run Migrations + +```bash +npx knex migrate:latest + +### Run Seed Data + +```bash +npx knex seed:run + +## Features +- Normalized database schema +- Foreign key relationships +- Migration-based schema management +- Seed data for testing diff --git a/task-4-database-schema/ER_DIAGRAM.md b/task-4-database-schema/ER_DIAGRAM.md new file mode 100644 index 0000000..3e0ea90 --- /dev/null +++ b/task-4-database-schema/ER_DIAGRAM.md @@ -0,0 +1,25 @@ +# ER Diagram - Shipyard Task 4 + +## Users +- id (PK) +- name +- email +- role + +## Projects +- id (PK) +- name +- description +- status +- owner_id (FK -> Users.id) + +## Project_Events +- id (PK) +- project_id (FK -> Projects.id) +- event_type +- description +- created_at + +### Relationships +- Users (1) ----< Projects +- Projects (1) ----< Project_Events diff --git a/task-4-database-schema/README.md b/task-4-database-schema/README.md new file mode 100644 index 0000000..3f32d7f --- /dev/null +++ b/task-4-database-schema/README.md @@ -0,0 +1,27 @@ +# Shipyard Technical Evaluation - Task 4 + +## Tech Stack +- Express.js +- SQLite +- Knex + +## Installation + +```bash +npm install + +## Run Migrations + +```bash +npx knex migrate:latest + +## Run Seeds + +```bash +npx knex seed:run + +## Schema + +Users -> Projects -> Project Events +See ER_DIAGRAM.md for details + diff --git a/task-4-database-schema/database.sqlite b/task-4-database-schema/database.sqlite new file mode 100644 index 0000000..eb9a493 Binary files /dev/null and b/task-4-database-schema/database.sqlite differ diff --git a/task-4-database-schema/documentation.md b/task-4-database-schema/documentation.md new file mode 100644 index 0000000..e69de29 diff --git a/task-4-database-schema/knexfile.js b/task-4-database-schema/knexfile.js new file mode 100644 index 0000000..e964535 --- /dev/null +++ b/task-4-database-schema/knexfile.js @@ -0,0 +1,15 @@ +module.exports = { + development: { + client: "sqlite3", + connection: { + filename: "./database.sqlite", + }, + useNullAsDefault: true, + migrations: { + directory: "./src/migrations", + }, + seeds: { + directory: "./src/seeds", + }, + }, +}; diff --git a/task-4-database-schema/package.json b/task-4-database-schema/package.json new file mode 100644 index 0000000..8b20298 --- /dev/null +++ b/task-4-database-schema/package.json @@ -0,0 +1,18 @@ +{ + "name": "task4db", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "keywords": [], + "author": "", + "license": "ISC", + "type": "commonjs", + "dependencies": { + "express": "^5.2.1", + "knex": "^3.2.10", + "sqlite3": "^6.0.1" + } +} diff --git a/task-4-database-schema/src/config/db.js b/task-4-database-schema/src/config/db.js new file mode 100644 index 0000000..a97ea0e --- /dev/null +++ b/task-4-database-schema/src/config/db.js @@ -0,0 +1,11 @@ +const knex = require("knex"); + +const db = knex({ + client: "sqlite3", + connection: { + filename: "./database.sqlite", + }, + useNullAsDefault: true, +}); + +module.exports = db; diff --git a/task-4-database-schema/src/migrations/20260610095832_create_users.js b/task-4-database-schema/src/migrations/20260610095832_create_users.js new file mode 100644 index 0000000..49bffec --- /dev/null +++ b/task-4-database-schema/src/migrations/20260610095832_create_users.js @@ -0,0 +1,20 @@ + /** + * @param { import("knex").Knex } knex + * @returns { Promise } + */ +exports.up = function(knex) { + return knex.schema.createTable("users", (table) => { + table.increments("id").primary(); + table.string("name"); + table.string("email").unique(); + table.string("role"); + }); +}; + +/** + * @param { import("knex").Knex } knex + * @returns { Promise } + */ +exports.down = function(knex) { + return knex.schema.dropTable("users"); +}; diff --git a/task-4-database-schema/src/migrations/20260610095848_create_projects.js b/task-4-database-schema/src/migrations/20260610095848_create_projects.js new file mode 100644 index 0000000..89c3f89 --- /dev/null +++ b/task-4-database-schema/src/migrations/20260610095848_create_projects.js @@ -0,0 +1,25 @@ +/** + * @param { import("knex").Knex } knex + * @returns { Promise } + */ +exports.up = function(knex) { + return knex.schema.createTable("projects", (table) => { + table.increments("id").primary(); + table.string("name"); + table.text("description"); + table.string("status"); + table + .integer("owner_id") + .unsigned() + .references("id") + .inTable("users"); + }); +}; + +/** + * @param { import("knex").Knex } knex + * @returns { Promise } + */ +exports.down = function(knex) { + return knex.schema.dropTable("projects"); +}; diff --git a/task-4-database-schema/src/migrations/20260610095858_create_project_events.js b/task-4-database-schema/src/migrations/20260610095858_create_project_events.js new file mode 100644 index 0000000..e5c4e79 --- /dev/null +++ b/task-4-database-schema/src/migrations/20260610095858_create_project_events.js @@ -0,0 +1,25 @@ +/** + * @param { import("knex").Knex } knex + * @returns { Promise } + */ +exports.up = function(knex) { + return knex.schema.createTable("project_events", (table) => { + table.increments("id").primary(); + table + .integer("project_id") + .unsigned() + .references("id") + .inTable("projects"); + table.string("event_type"); + table.text("description"); + table.timestamp("created_at").defaultTo(knex.fn.now()); + }); +}; + +/** + * @param { import("knex").Knex } knex + * @returns { Promise } + */ +exports.down = function(knex) { + return knex.schema.dropTable("project_events"); +}; diff --git a/task-4-database-schema/src/seeds/seed_initial_data.js b/task-4-database-schema/src/seeds/seed_initial_data.js new file mode 100644 index 0000000..54cc21c --- /dev/null +++ b/task-4-database-schema/src/seeds/seed_initial_data.js @@ -0,0 +1,22 @@ +exports.seed = async function (knex) { + // Deletes ALL existing entries + await knex("project_events").del(); + await knex("projects").del(); + await knex("users").del(); + + // Insert sample users + await knex("users").insert([ + { id: 1, name: "John", email: "john@example.com", role: "admin" }, + { id: 2, name: "Sarah", email: "sarah@example.com", role: "developer" } + ]); + + // Insert sample projects + await knex("projects").insert([ + { id: 1, name: "Shipyard Project", description: "Sample Project", status: "active", owner_id: 1 } + ]); + + // Insert sample project events + await knex("project_events").insert([ + { id: 1, project_id: 1, event_type: "Created", description: "Project created" } + ]); +};