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
3 changes: 1 addition & 2 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,7 @@

PUBLIC_BASE_URL="http://localhost:3000"

DATABASE_URL="file:/<absolute_url>/local.db"
DATABASE_AUTH_TOKEN=""
DATABASE_URL="postgresql://solid:solid@localhost:5432/solid_launch?schema=public"

GITHUB_CLIENT_ID=""
GITHUB_CLIENT_SECRET=""
Expand Down
8 changes: 5 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,13 +84,15 @@ cd <your-app-name>
cp .env.example .env
```

3. Replace the `<absolute_url>` in the local database with:
3. Start Postgres (or point `DATABASE_URL` at your existing database):

```sh
pwd # If it outputs: /User/Projects/solid-launch
docker compose up -d
```

```sh
# Replace the .env with:
DATABASE_URL="file:/User/Projects/solid-launch/local.db"
DATABASE_URL="postgresql://solid:solid@localhost:5432/solid_launch?schema=public"
```

4. Generate
Expand Down
3 changes: 1 addition & 2 deletions bun.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

19 changes: 19 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
version: "3.8"

services:
postgres:
image: postgres:16
container_name: solid-launch-postgres
restart: unless-stopped
ports:
- "5432:5432"
environment:
POSTGRES_USER: "solid"
POSTGRES_PASSWORD: "solid"
POSTGRES_DB: "solid_launch"
# DATABASE_URL="postgresql://solid:solid@localhost:5432/solid_launch?schema=public"
volumes:
- postgres_data:/var/lib/postgresql/data

volumes:
postgres_data:
3 changes: 1 addition & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@
"@corvu/drawer": "^0.2.4",
"@hono/standard-validator": "^0.2.2",
"@kobalte/core": "^0.13.11",
"@libsql/kysely-libsql": "^0.4.1",
"@node-rs/argon2": "^2.0.2",
"@paralleldrive/cuid2": "^3.3.0",
"@photonjs/hono": "^0.1.12",
Expand All @@ -51,7 +50,7 @@
"hono-openapi": "^1.2.0",
"hono-rate-limiter": "^0.5.3",
"kysely": "^0.28.10",
"kysely-bun-worker": "^1.2.1",
"pg": "^8.16.3",
"prisma": "^7.3.0",
"prisma-kysely": "^3.0.0",
"solid-js": "1.9.11",
Expand Down
24 changes: 12 additions & 12 deletions prisma/migrations/20251120203018_auth/migration.sql
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,15 @@ CREATE TABLE "user" (
"email_verified" BOOLEAN NOT NULL DEFAULT false,
"password_hash" TEXT NOT NULL,
"metadata" JSONB,
"joined_at" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updated_at" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
"joined_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updated_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP
);

-- CreateTable
CREATE TABLE "session" (
"id" TEXT NOT NULL PRIMARY KEY,
"user_id" TEXT NOT NULL,
"expires_at" DATETIME NOT NULL,
"expires_at" TIMESTAMP(3) NOT NULL,
"revoke_id" TEXT NOT NULL,
"active_organization_id" TEXT,
"ip_address" TEXT,
Expand All @@ -36,7 +36,7 @@ CREATE TABLE "oauth_account" (
CREATE TABLE "onetime_token" (
"token" TEXT NOT NULL PRIMARY KEY,
"code" TEXT,
"expires_at" DATETIME NOT NULL,
"expires_at" TIMESTAMP(3) NOT NULL,
"identifier" TEXT NOT NULL,
"purpose" TEXT NOT NULL,
"metadata" JSONB
Expand All @@ -49,17 +49,17 @@ CREATE TABLE "organization" (
"slug" TEXT,
"logo_object_id" TEXT,
"metadata" JSONB,
"created_at" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updated_at" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
"created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updated_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP
);

-- CreateTable
CREATE TABLE "organization_member" (
"user_id" TEXT NOT NULL,
"organization_id" TEXT NOT NULL,
"role" TEXT NOT NULL DEFAULT 'member',
"created_at" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updated_at" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updated_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,

PRIMARY KEY ("organization_id", "user_id"),
CONSTRAINT "organization_member_organization_id_fkey" FOREIGN KEY ("organization_id") REFERENCES "organization" ("id") ON DELETE CASCADE ON UPDATE CASCADE,
Expand All @@ -73,10 +73,10 @@ CREATE TABLE "organization_invitation" (
"email" TEXT NOT NULL,
"role" TEXT NOT NULL DEFAULT 'member',
"invited_by_id" TEXT NOT NULL,
"expires_at" DATETIME NOT NULL,
"accepted_at" DATETIME,
"rejected_at" DATETIME,
"created_at" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"expires_at" TIMESTAMP(3) NOT NULL,
"accepted_at" TIMESTAMP(3),
"rejected_at" TIMESTAMP(3),
"created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT "organization_invitation_organization_id_fkey" FOREIGN KEY ("organization_id") REFERENCES "organization" ("id") ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT "organization_invitation_invited_by_id_fkey" FOREIGN KEY ("invited_by_id") REFERENCES "user" ("id") ON DELETE CASCADE ON UPDATE CASCADE
);
Expand Down
2 changes: 1 addition & 1 deletion prisma/migrations/migration_lock.toml
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
# Please do not edit this file manually
# It should be added in your version-control system (e.g., Git)
provider = "sqlite"
provider = "postgresql"
3 changes: 2 additions & 1 deletion prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,6 @@ generator kysely {
}

datasource db {
provider = "sqlite"
provider = "postgresql"
url = env("DATABASE_URL")
}
6 changes: 0 additions & 6 deletions src/env.private.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,6 @@ export const privateEnv = createEnv({
// Database
/** Development|Prod. Url of the database. */
DATABASE_URL: z.string(),
/** Development(Optional)|Prod. https://docs.turso.tech/local-development#sqlite. */
DATABASE_AUTH_TOKEN: z
.string()
.optional()
.refine((val) => (process.env.NODE_ENV !== "development" ? !!val : true)),

// Auth
/** Development|Prod. GitHub OAuth client ID. */
GITHUB_CLIENT_ID: z.string(),
Expand Down
29 changes: 7 additions & 22 deletions src/server/db/kysely.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,30 +4,15 @@
// = For develop, we use the Bun dialect.
// ===========================================================================

import { LibsqlDialect } from "@libsql/kysely-libsql"
import { Kysely } from "kysely"
import { BunWorkerDialect } from "kysely-bun-worker"
import { Kysely, PostgresDialect } from "kysely"
import { Pool } from "pg"
import { privateEnv } from "@/env.private"
import type { DB } from "./types" // Generated by prisma.

const getDialect = () => {
const isLocal = privateEnv.DATABASE_URL.includes("file:")

if (isLocal) {
console.log("Found file local database. Using BunWorkerDialect.")
// Can swap this with better-sqlite-3 if not Bun. (Node).
return new BunWorkerDialect({
url: privateEnv.DATABASE_URL,
})
}

console.log("Found remote database. Using LibsqlDialect.")
return new LibsqlDialect({
authToken: privateEnv.DATABASE_AUTH_TOKEN,
url: privateEnv.DATABASE_URL,
})
}

export const db = new Kysely<DB>({
dialect: getDialect(),
dialect: new PostgresDialect({
pool: new Pool({
connectionString: privateEnv.DATABASE_URL,
}),
}),
})
26 changes: 13 additions & 13 deletions src/server/db/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ export type OneTimeToken = {
* Optional shorter digit alias, scoped to user (so not globally unique)
*/
code: string | null
expires_at: string
expires_at: Timestamp
identifier: string
/**
* e.g. 'password_reset', 'magic_link', 'otp', etc. (managed in application layer)
Expand All @@ -45,19 +45,19 @@ export type Organization = {
* For additional metadata i.e. org settings, billing, features, handled in application layer
*/
metadata: unknown | null
created_at: Generated<string>
updated_at: Generated<string>
created_at: Generated<Timestamp>
updated_at: Generated<Timestamp>
}
export type OrganizationInvitation = {
id: string
organization_id: string
email: string
role: Generated<string>
invited_by_id: string
expires_at: string
accepted_at: string | null
rejected_at: string | null
created_at: Generated<string>
expires_at: Timestamp
accepted_at: Timestamp | null
rejected_at: Timestamp | null
created_at: Generated<Timestamp>
}
export type OrganizationMember = {
user_id: string
Expand All @@ -66,16 +66,16 @@ export type OrganizationMember = {
* owner, admin, member (handled in application layer)
*/
role: Generated<string>
created_at: Generated<string>
updated_at: Generated<string>
created_at: Generated<Timestamp>
updated_at: Generated<Timestamp>
}
export type Session = {
/**
* Never send this to the frontend (except http-only cookie)
*/
id: string
user_id: string
expires_at: string
expires_at: Timestamp
/**
* an alternative id strictly for revoking (not validating) so it's safe to send to frontend
*/
Expand All @@ -93,11 +93,11 @@ export type Session = {
export type User = {
id: string
email: string
email_verified: Generated<number>
email_verified: Generated<boolean>
password_hash: string
metadata: unknown | null
joined_at: Generated<string>
updated_at: Generated<string>
joined_at: Generated<Timestamp>
updated_at: Generated<Timestamp>
}
export type DB = {
oauth_account: OAuthAccount
Expand Down
Loading