Skip to content
Merged
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
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
# Keeps local dependencies, secrets, build output, and editor state out of Git.
node_modules/
dist/
coverage/
Expand All @@ -11,4 +12,3 @@ coverage/
Thumbs.db
.idea/
.vscode/
apps/api/drizzle/
3 changes: 2 additions & 1 deletion apps/api/drizzle.config.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/** Configures Drizzle Kit schema discovery and PostgreSQL migration output. */
import 'dotenv/config';
import { defineConfig } from 'drizzle-kit';

Expand All @@ -7,7 +8,7 @@ if (!process.env.DATABASE_URL) {

export default defineConfig({
dialect: 'postgresql',
schema: './src/db/schema.ts',
schema: './src/db/schema/index.ts',
out: './drizzle',
dbCredentials: { url: process.env.DATABASE_URL },
strict: true,
Expand Down
7 changes: 7 additions & 0 deletions apps/api/drizzle/0000_curved_salo.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
CREATE TABLE "sessions" (
"sid" varchar PRIMARY KEY NOT NULL,
"sess" json NOT NULL,
"expire" timestamp (6) NOT NULL
);
--> statement-breakpoint
CREATE INDEX "sessions_expire_idx" ON "sessions" USING btree ("expire");
66 changes: 66 additions & 0 deletions apps/api/drizzle/meta/0000_snapshot.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
{
"id": "14e1489f-6ad1-4119-aad3-bb8e2db293a3",
"prevId": "00000000-0000-0000-0000-000000000000",
"version": "7",
"dialect": "postgresql",
"tables": {
"public.sessions": {
"name": "sessions",
"schema": "",
"columns": {
"sid": {
"name": "sid",
"type": "varchar",
"primaryKey": true,
"notNull": true
},
"sess": {
"name": "sess",
"type": "json",
"primaryKey": false,
"notNull": true
},
"expire": {
"name": "expire",
"type": "timestamp (6)",
"primaryKey": false,
"notNull": true
}
},
"indexes": {
"sessions_expire_idx": {
"name": "sessions_expire_idx",
"columns": [
{
"expression": "expire",
"isExpression": false,
"asc": true,
"nulls": "last"
}
],
"isUnique": false,
"concurrently": false,
"method": "btree",
"with": {}
}
},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
}
},
"enums": {},
"schemas": {},
"sequences": {},
"roles": {},
"policies": {},
"views": {},
"_meta": {
"columns": {},
"schemas": {},
"tables": {}
}
}
13 changes: 13 additions & 0 deletions apps/api/drizzle/meta/_journal.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"version": "7",
"dialect": "postgresql",
"entries": [
{
"idx": 0,
"version": "7",
"when": 1787007119704,
"tag": "0000_curved_salo",
"breakpoints": true
}
]
}
2 changes: 0 additions & 2 deletions apps/api/src/db/schema.ts

This file was deleted.

2 changes: 2 additions & 0 deletions apps/api/src/db/schema/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
/** Exposes the complete Drizzle schema from feature-focused table modules. */
export * from './sessions.js';
12 changes: 12 additions & 0 deletions apps/api/src/db/schema/sessions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
/** Defines the PostgreSQL table used for server-side authentication sessions. */
import { index, json, pgTable, timestamp, varchar } from 'drizzle-orm/pg-core';

export const sessions = pgTable(
'sessions',
{
sid: varchar('sid').primaryKey(),
sess: json('sess').notNull(),
expire: timestamp('expire', { mode: 'date', precision: 6 }).notNull(),
},
(table) => [index('sessions_expire_idx').on(table.expire)],
);
27 changes: 13 additions & 14 deletions docs/database.md
Original file line number Diff line number Diff line change
Expand Up @@ -114,23 +114,24 @@ in the MVP.

| Field | Type | Purpose |
|---|---|---|
| `id` | UUID or sufficiently strong opaque identifier | Session identifier placed in the browser cookie. If the implementation stores only a hash of the cookie value, this field contains that hash instead. |
| `user_id` | UUID, FK → `users.id` | User authenticated by the session. |
| `expires_at` | TIMESTAMPTZ | Absolute time after which the session is invalid. |
| `created_at` | TIMESTAMPTZ | When the session was created. |
| `last_accessed_at` | TIMESTAMPTZ, nullable | Optional timestamp for idle-expiration or session-management behavior if adopted during implementation. |
| `sid` | VARCHAR | Opaque session identifier used by `connect-pg-simple`. |
| `sess` | JSON | Serialized server-side session state, including the authenticated GoForLift user ID after login. |
| `expire` | TIMESTAMP(6) | Absolute time after which the session is invalid. |

### Constraints and Lifecycle

- `id` is the primary key or uniquely indexed lookup value.
- `user_id` references `users.id`.
- `sid` is the primary key and session lookup index.
- The table shape intentionally matches `connect-pg-simple`; application user
identity is stored inside `sess` rather than in a separate normalized column.
- Session identifiers must be generated using a cryptographically secure source.
- Expired sessions must not authenticate requests and should be removed
periodically.
at least daily by the configured session store.
- Logout deletes or invalidates the matching session.
- Deleting a user must invalidate that user's sessions.
- An index on `user_id` supports user-wide session revocation.
- An index on `expires_at` may support expiration cleanup.
- Deleting a user must invalidate that user's sessions through application-owned
session cleanup.
- An index on `expire` supports expiration pruning.
- Drizzle owns table creation and migration. Runtime table creation through
`connect-pg-simple` remains disabled.


# 5. Exercises
Expand Down Expand Up @@ -619,9 +620,7 @@ Likely query patterns should guide additional indexes.

Potential candidates include:

sessions.user_id

sessions.expires_at
sessions.expire

routines.user_id

Expand Down