diff --git a/Day 13-14 (prototyping)/Campus Visit Prototype.epgz b/Day 13-14 (prototyping)/Campus Visit Prototype.epgz index c5e09a6..4ee80ea 100644 Binary files a/Day 13-14 (prototyping)/Campus Visit Prototype.epgz and b/Day 13-14 (prototyping)/Campus Visit Prototype.epgz differ diff --git a/Day 13-14 (prototyping)/clickable prototype/index.html b/Day 13-14 (prototyping)/clickable prototype/index.html index bd19ce2..aab8916 100644 --- a/Day 13-14 (prototyping)/clickable prototype/index.html +++ b/Day 13-14 (prototyping)/clickable prototype/index.html @@ -1,2 +1,2 @@ -Campus Visit Prototype

Campus Visit Prototype

Exported at: Sat Sep 28 2024 08:28:10 GMT-0400 (Eastern Daylight Time)

MetaMenu



Login

Users

Availability

EditAvailability

DeleteUser

Visits

VisitDetails

EmailSettings

EmailClient

EmailChoice

EmailChoiceConfirmed

ConfirmNonVolunteer

\ No newline at end of file +Campus Visit Prototype

Campus Visit Prototype

Exported at: Fri Oct 11 2024 14:08:21 GMT-0400 (Eastern Daylight Time)

MetaMenu



Login

Users

Availability

EditAvailability

DeleteUser

Visits

VisitDetails

EmailSettings

EmailClient

EmailChoice

EmailChoiceConfirmed

ConfirmNonVolunteer

\ No newline at end of file diff --git a/Day 13-14 (prototyping)/clickable prototype/pages/emailsettings.png b/Day 13-14 (prototyping)/clickable prototype/pages/emailsettings.png index 298c2cc..fb496d8 100644 Binary files a/Day 13-14 (prototyping)/clickable prototype/pages/emailsettings.png and b/Day 13-14 (prototyping)/clickable prototype/pages/emailsettings.png differ diff --git a/Day 13-14 (prototyping)/clickable prototype/pages/metamenu.png b/Day 13-14 (prototyping)/clickable prototype/pages/metamenu.png index d00a966..36ee2d8 100644 Binary files a/Day 13-14 (prototyping)/clickable prototype/pages/metamenu.png and b/Day 13-14 (prototyping)/clickable prototype/pages/metamenu.png differ diff --git a/Day 13-14 (prototyping)/clickable prototype/pages/visitdetails.png b/Day 13-14 (prototyping)/clickable prototype/pages/visitdetails.png index a767ab6..251ce5e 100644 Binary files a/Day 13-14 (prototyping)/clickable prototype/pages/visitdetails.png and b/Day 13-14 (prototyping)/clickable prototype/pages/visitdetails.png differ diff --git a/Day 13-14 (prototyping)/clickable prototype/pages/visits.png b/Day 13-14 (prototyping)/clickable prototype/pages/visits.png index fd7b8ec..7b0b207 100644 Binary files a/Day 13-14 (prototyping)/clickable prototype/pages/visits.png and b/Day 13-14 (prototyping)/clickable prototype/pages/visits.png differ diff --git a/Day 22-23 (architecture)/Programming language selection.txt b/Day 22-24 (architecture)/Programming language selection.txt similarity index 100% rename from Day 22-23 (architecture)/Programming language selection.txt rename to Day 22-24 (architecture)/Programming language selection.txt diff --git a/Day 22-23 (architecture)/SystemArchitecture.md b/Day 22-24 (architecture)/SystemArchitecture.md similarity index 76% rename from Day 22-23 (architecture)/SystemArchitecture.md rename to Day 22-24 (architecture)/SystemArchitecture.md index 14769aa..2d9afc1 100644 --- a/Day 22-23 (architecture)/SystemArchitecture.md +++ b/Day 22-24 (architecture)/SystemArchitecture.md @@ -17,7 +17,7 @@ For a database engine, SQLite was compared with MySQL, as both are free. Accord #### Backups -SQLite works based on a single database file, so it will be straightforward to schedule automatic backups. For simplicity of deployment, the plan is to implement this in the Node.js server script itself. +SQLite works based on a single database file and it has built-in functionality for making a backup, so it will be straightforward to schedule automatic backups. For simplicity of deployment, the plan is to implement this in the Node.js server script itself. ### Client-server data communication: JSON over AJAX @@ -29,6 +29,8 @@ JSON will be used for client-server data communication (e.g. visit and user data ## Major database tables +There will only need to be 3 main database tables: Users, Visits, and Committments. These tables will implement the internal model supposed in the user interface document. There will also be a table for storing configuration data; see https://stackoverflow.com/questions/2300356/using-a-single-row-configuration-table-in-sql-server-database-bad-idea for a discussion of two possible implementations of the configuration table. + ## Performance ## Scalability diff --git a/Day 24-27 (database)/CampusVisits.db b/Day 24-27 (database)/CampusVisits.db new file mode 100644 index 0000000..d7ddbb4 Binary files /dev/null and b/Day 24-27 (database)/CampusVisits.db differ diff --git a/Day 24-27 (database)/Database selection.txt b/Day 24-27 (database)/Database selection.txt new file mode 100644 index 0000000..dd13a6b --- /dev/null +++ b/Day 24-27 (database)/Database selection.txt @@ -0,0 +1,49 @@ +DBMS = Database Management System (e.g. MySQL, MariaDB, PostgreSQL, Oracle, Access, MongoDB) + +SQL: + This should be your default option for most applications + Relational database with predefined schema + Data organized in tables, rows, and columns + Uses SQL as a common language, but some features may be DBMS-specific (MySQL vs PostgreSQL, etc.) + Well-suited for multi-table transactions + +NoSQL: + Useful when you need high-performance at a huge scale, with little or no relation between tables + Allows storing data with no schema + Well-suited for documents, JSON, time series data, data dumps, and logs + Records can have internal structure (such as an array or tree-like structure) + Lack of good support for joins can be circumvented by storing joined data multiple times in different records + This sacrifices memory for time + Maintaining data consistency is more challenging + Some NoSQL DMBSs have limited support for joins and transactions + +Note: If you just need to dump a bunch of JSON data (or something similar) from your application and fetch it back at a later time, you may not need a detailed database model. You may just want to store the JSON data directly (which both SQL and NoSQL databases can do). + +SQLite: + From their website: "SQLite does not compete with client/server databases. SQLite competes with fopen()" + Benefits: + Simple to setup + Low latency, even for large sequences of SQL statements + Transactional + Serverless + Single data file + Lightweight processing + Drawbacks: + Any write operation requires a lock on the whole database; many simultaneous writes will slow it down + Lacks stored procedures + Lacks user management (e.g. who has permission to write to which table) + +Transaction: + A unit of work on the database (possibly with multiple actions), treated independently of other such units. + If you are using a database, you must learn how to use transactions + Properties (ACID): + Atomic - either all of the transaction takes affect, or none of it (including under power failures and crashes) + Consistent - database invariants are maintained (constraints, triggers, referential integrity, etc.) + Isolated - transactions are executed as if they were sequential + Durable - committed transactions are never forgotten (i.e. they stored to non-volatile memory) + +Basic operations (CRUD) and their associated SQL statements: + Create (INSERT) + Retrieve (SELECT) + Update (UPDATE) + Delete (DELETE) diff --git a/Day 24-27 (database)/notes.txt b/Day 24-27 (database)/notes.txt new file mode 100644 index 0000000..93c553c --- /dev/null +++ b/Day 24-27 (database)/notes.txt @@ -0,0 +1,107 @@ +Naming conventions I'll be using: + UpperCamelCase tables and columns + Plural table names (less likely to conflict with reserved words) + Singular column names + Associative table names: + The names the other two tables joined by an underscore: either can be singular or plural as the relationship dictates. + Primary keys are named [SingularTableName]ID, and identically when appearing as a foreign key. + When needed, add a prefix: SourceWarehouseID and DestinationWarehouseID + +Some SQLite specific commands + .open CampusVisit.db + .tables + PRAGMA table_info(TableName); + PRAGMA foreign_keys = ON; /* Need this one to define foreign key contraints. */ + +CREATE TABLE Users( + UserID INTEGER PRIMARY KEY, + Name VARCHAR(100) UNIQUE NOT NULL, + Email VARCHAR(20) UNIQUE NOT NULL, + PasswordHash VARCHAR(64) NOT NULL, + IsAdmin BOOLEAN NOT NULL, + IsFaculty BOOLEAN NOT NULL, + IsCoordinator BOOLEAN NOT NULL, + Availability INTEGER DEFAULT -9223372036854775808 /* 64 bits. LSB is Sunday 8am, then 9am, 10, ... Monday 8am, 9am, .... Sign bit is "other time" category. */ +); + +CREATE TABLE Visits( + VisitID INTEGER PRIMARY KEY, + UserID INTEGER, /* DEFAULT NULL is implicit in SQLite. NULL values are allowed with the foreign key. */ + StudentInfo VARCHAR(100) NOT NULL DEFAULT '', + OtherVisitors VARCHAR(100) NOT NULL DEFAULT '', + Hometown VARCHAR(50) NOT NULL DEFAULT '', + Day VARCHAR(10) NOT NULL, /* YYYY-MM-DD */ + Availability INTEGER NOT NULL DEFAULT 0, /* Same format as Users.Availability */ + DecidedTime INTEGER, /* Same format as Users.Availability */ + Status VARCHAR(9) CHECK(Status IN ('proposed','assigned','confirmed','completed','canceled')) NOT NULL DEFAULT 'proposed', + Notes VARCHAR(500) NOT NULL DEFAULT '', + NotificationFrequency INTEGER NOT NULL DEFAULT 2, + FOREIGN KEY(UserID) REFERENCES Users(UserID) +); + +CREATE TABLE Visits_Users ( + VisitID INTEGER, + UserID INTEGER, + Willingness VARCHAR(10) CHECK(Willingness IN ('cannot', 'prefer not', 'can do')) NOT NULL, /* unknown if pair is missing from the table */ + PRIMARY KEY (VisitID, UserID), + FOREIGN KEY(VisitID) REFERENCES Visits(VisitID), + FOREIGN KEY(UserID) REFERENCES Users(UserID) +); + +CREATE TABLE Settings( + Key VARCHAR(100) PRIMARY KEY, + Value VARCHAR(100) NOT NULL DEFAULT '' +); + +Initialization: + Initial values for global settings (hyperlink lifetime and notification frequency) + INSERT INTO Settings VALUES ('HyperlinkLifetime','7'); + INSERT INTO Settings VALUES ('CoordinatorNotificationFrequency','3'); +Login screen: + Check username/password + SELECT COUNT() FROM Users WHERE Email='mkowalcz@nmu.edu' AND PasswordHash='secret'; +Visits tab: + Create new visit + INSERT INTO Visits (StudentInfo,Day) VALUES ('Joe Bloggs, Major: CS', '2025-04-15'); + Get list of all visits, joined with faculty guides + SELECT Visits.VisitID,Visits.StudentInfo,Users.name FROM Visits LEFT JOIN Users ON Visits.UserID=Users.UserID; + Delete a visit + DELETE FROM Visits WHERE VisitID='1'; + +Visit detail window: + Get committment levels for all faculty for a given visit + SELECT VisitID, Users.UserID, Name, Email FROM Visits_Users INNER JOIN Users ON Visits_Users.UserID=Users.UserID WHERE VisitID=2; + Find intersection of visit availability with each faculty availability + SELECT Users.UserID, Name, Visits.Availability & Users.Availability FROM Visits INNER JOIN Users WHERE VisitID=1; /* Note that this is using the bitwise and operator "&" because of the way we are storing availability. */ + Set email frequency for a particular visit + UPDATE Visits SET NotificationFrequency=4 WHERE VisitID=2; + Set committment level for a given faculty member + INSERT INTO Visits_Users VALUES (1,1,'prefer not'); + Claim a visit and a time + UPDATE Visits SET DecidedTime=4, Status='assigned' WHERE VisitID=1 AND Status='proposed'; + INSERT INTO Visits_Users VALUES (1,1,'can do') ON CONFLICT (VisitID,UserID) DO UPDATE SET Willingness='can do' WHERE (VisitID,UserID)=(1,1); + Update visit details + UPDATE Visits SET UserID=1 WHERE VisitID=3; +User tab: + Get list of users, including faculty availability + SELECT * FROM Users; + Create new user + INSERT INTO Users(Name,Email,PasswordHash,IsAdmin,IsFaculty,IsCoordinator) VALUES ('DrKow', 'mkowalcz@nmu.edu', 'secret', TRUE, TRUE, TRUE); + INSERT INTO Users(Name,Email,PasswordHash,IsAdmin,IsFaculty,IsCoordinator) VALUES ('Randy', 'rappleto@nmu.edu', 'secret', FALSE, TRUE, FALSE); + Update user attributes + UPDATE Users SET PasswordHash='secret',IsAdmin=TRUE WHERE Name='DrKow'; + Update faculty availability + UPDATE Users SET Availability=-9223372036854775801 WHERE Email='rappleto@nmu.edu'; + Delete user + DELETE FROM Users WHERE UserID=2; + Update global settings + UPDATE Settings SET Value='5' WHERE Key='HyperlinkLifetime'; + UPDATE Settings SET Value='5' WHERE Key='CoordinatorNotificationFrequency'; + +References: + https://stackoverflow.com/questions/7662/database-table-and-column-naming-conventions + https://dev.to/ovid/database-naming-standards-2061 + https://stackoverflow.com/questions/3037188/naming-of-boolean-column-in-database-table + https://stackoverflow.com/questions/2300356/using-a-single-row-configuration-table-in-sql-server-database-bad-idea + https://www.sqlite.org/foreignkeys.html + https://www.sqlite.org/lang.html