Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
-- CreateEnum
CREATE TYPE "LearningFrequency" AS ENUM ('QUICK', 'REGULAR', 'DEEPDIVE');

-- CreateTable
CREATE TABLE "user_profiles" (
"user_id" UUID NOT NULL,
"created_at" TIMESTAMPTZ(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updated_at" TIMESTAMPTZ(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"learning_frequency" "LearningFrequency",
"is_subscribed" BOOLEAN NOT NULL DEFAULT false,

CONSTRAINT "user_profiles_pkey" PRIMARY KEY ("user_id")
);

-- CreateTable
CREATE TABLE "user_interests" (
"user_id" UUID NOT NULL,
"collection_id" UUID NOT NULL,
"created_at" TIMESTAMPTZ(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updated_at" TIMESTAMPTZ(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,


CONSTRAINT "user_interests_pkey" PRIMARY KEY ("user_id","collection_id")
);

-- AddForeignKey
ALTER TABLE "user_profiles" ADD CONSTRAINT "user_profiles_user_id_fkey" FOREIGN KEY ("user_id") REFERENCES "users"("id") ON DELETE CASCADE ON UPDATE CASCADE;

-- AddForeignKey
ALTER TABLE "user_interests" ADD CONSTRAINT "user_interests_user_id_fkey" FOREIGN KEY ("user_id") REFERENCES "user_profiles"("user_id") ON DELETE CASCADE ON UPDATE CASCADE;

-- AddForeignKey
ALTER TABLE "user_interests" ADD CONSTRAINT "user_interests_collection_id_fkey" FOREIGN KEY ("collection_id") REFERENCES "collections"("id") ON DELETE CASCADE ON UPDATE CASCADE;
38 changes: 37 additions & 1 deletion prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,28 @@ model User {
avatarURL String @map("avatar_url")

// Relations.
userProfile UserProfile?
learningJourneys LearningJourney[]
threads Thread[]
sentiments LearningUnitSentiments[]

@@map("users")
}

model UserProfile {
userId String @id @map("user_id") @db.Uuid
createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz(3)
updatedAt DateTime @default(now()) @updatedAt @map("updated_at") @db.Timestamptz(3)
learningFrequency LearningFrequency? @map("learning_frequency")
isSubscribed Boolean @default(false) @map("is_subscribed")

// Relations.
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
interests UserInterest[]

@@map("user_profiles")
}

Comment on lines +30 to +43
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

First time encountering using the PK of the parent table as the PK of the dependent table for one-to-one relationship, I did some research on the web and it's a good strategy to implement strict one-to-one relationships with the storage efficiency and performance benefits due to taking advantage of PK default unique constraint instead of additional FK and unique index. 🚀

model Collection {
id String @id @default(dbgenerated("uuid_generate_v7()")) @map("id") @db.Uuid
createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz(3)
Expand All @@ -37,7 +52,8 @@ model Collection {
type CollectionType @map("type")

// Relations.
learningUnit LearningUnit[]
learningUnit LearningUnit[]
userInterests UserInterest[]

@@map("collections")
}
Expand Down Expand Up @@ -247,3 +263,23 @@ model QuestionAnswer {

@@map("question_answers")
}

enum LearningFrequency {
QUICK
REGULAR
DEEPDIVE
}

model UserInterest {
userId String @map("user_id") @db.Uuid
collectionId String @map("collection_id") @db.Uuid
createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz(3)
updatedAt DateTime @default(now()) @updatedAt @map("updated_at") @db.Timestamptz(3)

// Relations.
userProfile UserProfile @relation(fields: [userId], references: [userId], onDelete: Cascade)
collection Collection @relation(fields: [collectionId], references: [id], onDelete: Cascade)

@@id([userId, collectionId])
@@map("user_interests")
}
10 changes: 5 additions & 5 deletions src/hooks.server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,26 +15,26 @@ const requestLoggingHandle: Handle = async ({ event, resolve }) => {
event.setHeaders({ 'X-Request-Id': requestId });
event.locals.logger = logger.child({ requestId });

return await resolve(event);
return resolve(event);
};

/**
* A handle that enforces authentication on protected routes.
* - Requests to `/api/*` are always allowed through
* - Authenticated users visiting `/login` are redirected back to `/`
* - Authenticated users visiting `/login` are redirected back to HOME_PATH
* - Unauthenticated users are redirected to `/login`
*/
const routeProtectionHandle: Handle = async ({ event, resolve }) => {
if (event.url.pathname.startsWith('/api/')) {
return await resolve(event);
return resolve(event);
}

if (event.locals.session.isAuthenticated) {
if (event.url.pathname === '/login') {
return redirect(302, HOME_PATH);
}

return await resolve(event);
return resolve(event);
}

if (
Expand All @@ -44,7 +44,7 @@ const routeProtectionHandle: Handle = async ({ event, resolve }) => {
event.url.pathname === '/terms' ||
event.url.pathname === '/privacy'
) {
return await resolve(event);
return resolve(event);
}

return redirect(303, `/login?return_to=${encodeURIComponent(event.url.pathname)}`);
Expand Down
Binary file added src/lib/assets/cycling-man.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/lib/assets/onboarding-bites.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading