diff --git a/.env b/.env index a56f5fe..358ba6c 100644 --- a/.env +++ b/.env @@ -1,3 +1,10 @@ POSTGRES_USER=thoughts_user POSTGRES_PASSWORD=postgres -POSTGRES_DB=thoughts_db \ No newline at end of file +POSTGRES_DB=thoughts_db + +HOST=0.0.0.0 +PORT=8000 +DATABASE_URL="postgresql://thoughts_user:postgres@database/thoughts_db" +PREFORK=1 +AUTH_SECRET=secret +BASE_URL=http://0.0.0.0 \ No newline at end of file diff --git a/compose.yml b/compose.yml index 7c62dd9..e45acc8 100644 --- a/compose.yml +++ b/compose.yml @@ -25,6 +25,9 @@ services: restart: unless-stopped env_file: - .env + environment: + - RUST_LOG=info + - RUST_BACKTRACE=1 depends_on: database: condition: service_healthy @@ -34,9 +37,13 @@ services: build: context: ./thoughts-frontend dockerfile: Dockerfile + args: + NEXT_PUBLIC_API_URL: http://localhost/api restart: unless-stopped depends_on: - backend + environment: + - NEXT_PUBLIC_SERVER_SIDE_API_URL=http://proxy/api proxy: container_name: thoughts-proxy diff --git a/thoughts-backend/.env b/thoughts-backend/.env index b91bd78..0593f13 100644 --- a/thoughts-backend/.env +++ b/thoughts-backend/.env @@ -5,3 +5,4 @@ DATABASE_URL="postgresql://postgres:postgres@localhost/thoughts" #DATABASE_URL=postgres://thoughts_user:postgres@database:5432/thoughts_db PREFORK=0 AUTH_SECRET=your_secret_key_here +BASE_URL=http://0.0.0.0 \ No newline at end of file diff --git a/thoughts-backend/.env.example b/thoughts-backend/.env.example index 1ac0b90..87dccd6 100644 --- a/thoughts-backend/.env.example +++ b/thoughts-backend/.env.example @@ -1,7 +1,6 @@ HOST=0.0.0.0 PORT=3000 -DATABASE_URL="sqlite://dev.db" -# DATABASE_URL="postgresql://postgres:postgres@localhost/clean-axum" +DATABASE_URL="postgresql://postgres:postgres@localhost/clean-axum" PREFORK=1 AUTH_SECRET=your_secret_key_here BASE_URL=http://localhost:3000 \ No newline at end of file diff --git a/thoughts-backend/Dockerfile b/thoughts-backend/Dockerfile index b697c2b..3b0ac8c 100644 --- a/thoughts-backend/Dockerfile +++ b/thoughts-backend/Dockerfile @@ -1,10 +1,14 @@ FROM rust:1.89-slim AS builder + +RUN apt-get update && apt-get install -y libssl-dev pkg-config && rm -rf /var/lib/apt/lists/* + RUN cargo install cargo-chef --locked WORKDIR /app COPY Cargo.toml Cargo.lock ./ COPY api/Cargo.toml ./api/ COPY app/Cargo.toml ./app/ +COPY common/Cargo.toml ./common/ COPY doc/Cargo.toml ./doc/ COPY migration/Cargo.toml ./migration/ COPY models/Cargo.toml ./models/ @@ -22,6 +26,8 @@ RUN cargo build --release --bin thoughts-backend FROM debian:13-slim AS runtime +RUN apt-get update && apt-get install -y openssl && rm -rf /var/lib/apt/lists/* + RUN groupadd --system --gid 1001 appgroup && \ useradd --system --uid 1001 --gid appgroup appuser diff --git a/thoughts-backend/common/Cargo.toml b/thoughts-backend/common/Cargo.toml index 3891a21..e28a054 100644 --- a/thoughts-backend/common/Cargo.toml +++ b/thoughts-backend/common/Cargo.toml @@ -3,6 +3,10 @@ name = "common" version = "0.1.0" edition = "2021" +[lib] +name = "common" +path = "src/lib.rs" + [dependencies] serde = { workspace = true } utoipa = { workspace = true } diff --git a/thoughts-backend/migration/Cargo.toml b/thoughts-backend/migration/Cargo.toml index 3e907e8..5546c32 100644 --- a/thoughts-backend/migration/Cargo.toml +++ b/thoughts-backend/migration/Cargo.toml @@ -12,7 +12,4 @@ path = "src/lib.rs" models = { path = "../models" } async-std = { version = "1.13.1", features = ["attributes", "tokio1"] } -sea-orm-migration = { version = "1.1.12", features = [ - "sqlx-sqlite", - "sqlx-postgres", -] } +sea-orm-migration = { version = "1.1.12", features = ["sqlx-postgres"] } diff --git a/thoughts-backend/models/Cargo.toml b/thoughts-backend/models/Cargo.toml index 383df32..7e2cae5 100644 --- a/thoughts-backend/models/Cargo.toml +++ b/thoughts-backend/models/Cargo.toml @@ -13,7 +13,6 @@ serde = { workspace = true } serde_json = { workspace = true } sea-orm = { workspace = true, features = [ "sqlx-postgres", - "sqlx-sqlite", "runtime-tokio-rustls", "macros", ] } diff --git a/thoughts-backend/src/tokio.rs b/thoughts-backend/src/tokio.rs index bcac908..359f8e5 100644 --- a/thoughts-backend/src/tokio.rs +++ b/thoughts-backend/src/tokio.rs @@ -1,5 +1,5 @@ use api::{setup_config, setup_db, setup_router}; -use utils::{create_dev_db, migrate}; +use utils::migrate; async fn worker(child_num: u32, db_url: &str, prefork: bool, listener: std::net::TcpListener) { let conn = setup_db(db_url, prefork).await; @@ -19,7 +19,6 @@ async fn worker(child_num: u32, db_url: &str, prefork: bool, listener: std::net: #[cfg(feature = "prefork")] fn run_prefork(db_url: &str, listener: std::net::TcpListener) { let db_url: &'static str = Box::leak(db_url.to_owned().into_boxed_str()); - create_dev_db(db_url); let num_of_cores = std::thread::available_parallelism().unwrap().get() as u32; let is_parent = prefork::Prefork::from_resource(listener) @@ -34,8 +33,6 @@ fn run_prefork(db_url: &str, listener: std::net::TcpListener) { } fn run_non_prefork(db_url: &str, listener: std::net::TcpListener) { - create_dev_db(db_url); - let rt = tokio::runtime::Runtime::new().unwrap(); rt.block_on(worker(0, db_url, false, listener)); } diff --git a/thoughts-backend/utils/src/file.rs b/thoughts-backend/utils/src/file.rs deleted file mode 100644 index c443eb8..0000000 --- a/thoughts-backend/utils/src/file.rs +++ /dev/null @@ -1,22 +0,0 @@ -use std::process::Command; - -fn touch(file_name: &str) { - if cfg!(target_os = "windows") { - Command::new("cmd") - .args(["/C", &format!("type nul >> {}", file_name)]) - .output() - .expect("failed to execute touch"); - } else { - Command::new("touch") - .arg(file_name) - .output() - .expect("failed to execute touch"); - } -} - -pub fn create_dev_db(db_url: &str) { - let prefix = "sqlite://"; - if let Some(file_name) = db_url.strip_prefix(prefix) { - touch(file_name); - } -} diff --git a/thoughts-backend/utils/src/lib.rs b/thoughts-backend/utils/src/lib.rs index f73fed9..1c79795 100644 --- a/thoughts-backend/utils/src/lib.rs +++ b/thoughts-backend/utils/src/lib.rs @@ -1,6 +1,4 @@ mod db; -mod file; pub mod testing; pub use db::migrate; -pub use file::create_dev_db; diff --git a/thoughts-frontend/Dockerfile b/thoughts-frontend/Dockerfile index f1ae8ff..3d9ab77 100644 --- a/thoughts-frontend/Dockerfile +++ b/thoughts-frontend/Dockerfile @@ -1,30 +1,27 @@ -FROM oven/bun:1 AS base +FROM node:22-slim AS builder WORKDIR /app -FROM base AS install -RUN mkdir -p /temp/dev -COPY package.json bun.lock /temp/dev/ -RUN cd /temp/dev && bun install --frozen-lockfile +ARG NEXT_PUBLIC_API_URL +ENV NEXT_PUBLIC_API_URL=$NEXT_PUBLIC_API_URL -RUN mkdir -p /temp/prod -COPY package.json bun.lock /temp/prod/ -RUN cd /temp/prod && bun install --frozen-lockfile --production +# Install dependencies with Bun for speed +COPY --chown=node:node package.json bun.lock ./ +RUN npm install -g bun +RUN bun install --frozen-lockfile -FROM base AS prerelease -COPY --from=install /temp/dev/node_modules node_modules -COPY . . +# Copy the rest of the app and build with Node's Next.js runtime +COPY --chown=node:node . . ENV NODE_ENV=production RUN bun run build -FROM base AS release +FROM node:22-slim AS release -COPY --from=prerelease /app/public ./public -COPY --from=prerelease /app/.next/standalone ./ -COPY --from=prerelease /app/.next/static ./.next/static +COPY --from=builder /app/public ./public +COPY --from=builder /app/.next/standalone ./ +COPY --from=builder /app/.next/static ./.next/static -USER bun EXPOSE 3000 -CMD ["bun", "run", "server.js"] +CMD ["node", "server.js"] diff --git a/thoughts-frontend/app/page.tsx b/thoughts-frontend/app/page.tsx index c95dc9f..495e0d3 100644 --- a/thoughts-frontend/app/page.tsx +++ b/thoughts-frontend/app/page.tsx @@ -14,7 +14,6 @@ import { PopularTags } from "@/components/popular-tags"; import { ThoughtThread } from "@/components/thought-thread"; import { buildThoughtThreads } from "@/lib/utils"; import { TopFriends } from "@/components/top-friends"; -import InstallPrompt from "@/components/install-prompt"; export default async function Home() { const token = (await cookies()).get("auth_token")?.value ?? null; diff --git a/thoughts-frontend/lib/api.ts b/thoughts-frontend/lib/api.ts index 0c9c56e..bb33815 100644 --- a/thoughts-frontend/lib/api.ts +++ b/thoughts-frontend/lib/api.ts @@ -111,7 +111,10 @@ export type ApiKey = z.infer; export type ApiKeyResponse = z.infer; export type ThoughtThread = z.infer; -const API_BASE_URL = process.env.NEXT_PUBLIC_API_URL || "http://localhost:8000"; +const API_BASE_URL = + typeof window === "undefined" + ? process.env.NEXT_PUBLIC_SERVER_SIDE_API_URL // Server-side + : process.env.NEXT_PUBLIC_API_URL; // Client-side async function apiFetch( endpoint: string, @@ -119,6 +122,10 @@ async function apiFetch( schema: z.ZodType, token?: string | null ): Promise { + if (!API_BASE_URL) { + throw new Error("API_BASE_URL is not defined"); + } + const headers: Record = { "Content-Type": "application/json", ...(options.headers as Record), @@ -128,7 +135,8 @@ async function apiFetch( headers["Authorization"] = `Bearer ${token}`; } - const response = await fetch(`${API_BASE_URL}${endpoint}`, { + const fullUrl = `${API_BASE_URL}${endpoint}`; + const response = await fetch(fullUrl, { ...options, headers, });