feat: update environment configuration, enhance Dockerfiles, and refactor API handling
This commit is contained in:
7
.env
7
.env
@@ -1,3 +1,10 @@
|
|||||||
POSTGRES_USER=thoughts_user
|
POSTGRES_USER=thoughts_user
|
||||||
POSTGRES_PASSWORD=postgres
|
POSTGRES_PASSWORD=postgres
|
||||||
POSTGRES_DB=thoughts_db
|
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
|
@@ -25,6 +25,9 @@ services:
|
|||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
env_file:
|
env_file:
|
||||||
- .env
|
- .env
|
||||||
|
environment:
|
||||||
|
- RUST_LOG=info
|
||||||
|
- RUST_BACKTRACE=1
|
||||||
depends_on:
|
depends_on:
|
||||||
database:
|
database:
|
||||||
condition: service_healthy
|
condition: service_healthy
|
||||||
@@ -34,9 +37,13 @@ services:
|
|||||||
build:
|
build:
|
||||||
context: ./thoughts-frontend
|
context: ./thoughts-frontend
|
||||||
dockerfile: Dockerfile
|
dockerfile: Dockerfile
|
||||||
|
args:
|
||||||
|
NEXT_PUBLIC_API_URL: http://localhost/api
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
depends_on:
|
depends_on:
|
||||||
- backend
|
- backend
|
||||||
|
environment:
|
||||||
|
- NEXT_PUBLIC_SERVER_SIDE_API_URL=http://proxy/api
|
||||||
|
|
||||||
proxy:
|
proxy:
|
||||||
container_name: thoughts-proxy
|
container_name: thoughts-proxy
|
||||||
|
@@ -5,3 +5,4 @@ DATABASE_URL="postgresql://postgres:postgres@localhost/thoughts"
|
|||||||
#DATABASE_URL=postgres://thoughts_user:postgres@database:5432/thoughts_db
|
#DATABASE_URL=postgres://thoughts_user:postgres@database:5432/thoughts_db
|
||||||
PREFORK=0
|
PREFORK=0
|
||||||
AUTH_SECRET=your_secret_key_here
|
AUTH_SECRET=your_secret_key_here
|
||||||
|
BASE_URL=http://0.0.0.0
|
@@ -1,7 +1,6 @@
|
|||||||
HOST=0.0.0.0
|
HOST=0.0.0.0
|
||||||
PORT=3000
|
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
|
PREFORK=1
|
||||||
AUTH_SECRET=your_secret_key_here
|
AUTH_SECRET=your_secret_key_here
|
||||||
BASE_URL=http://localhost:3000
|
BASE_URL=http://localhost:3000
|
@@ -1,10 +1,14 @@
|
|||||||
FROM rust:1.89-slim AS builder
|
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
|
RUN cargo install cargo-chef --locked
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
COPY Cargo.toml Cargo.lock ./
|
COPY Cargo.toml Cargo.lock ./
|
||||||
COPY api/Cargo.toml ./api/
|
COPY api/Cargo.toml ./api/
|
||||||
COPY app/Cargo.toml ./app/
|
COPY app/Cargo.toml ./app/
|
||||||
|
COPY common/Cargo.toml ./common/
|
||||||
COPY doc/Cargo.toml ./doc/
|
COPY doc/Cargo.toml ./doc/
|
||||||
COPY migration/Cargo.toml ./migration/
|
COPY migration/Cargo.toml ./migration/
|
||||||
COPY models/Cargo.toml ./models/
|
COPY models/Cargo.toml ./models/
|
||||||
@@ -22,6 +26,8 @@ RUN cargo build --release --bin thoughts-backend
|
|||||||
|
|
||||||
FROM debian:13-slim AS runtime
|
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 && \
|
RUN groupadd --system --gid 1001 appgroup && \
|
||||||
useradd --system --uid 1001 --gid appgroup appuser
|
useradd --system --uid 1001 --gid appgroup appuser
|
||||||
|
|
||||||
|
@@ -3,6 +3,10 @@ name = "common"
|
|||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
name = "common"
|
||||||
|
path = "src/lib.rs"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
serde = { workspace = true }
|
serde = { workspace = true }
|
||||||
utoipa = { workspace = true }
|
utoipa = { workspace = true }
|
||||||
|
@@ -12,7 +12,4 @@ path = "src/lib.rs"
|
|||||||
models = { path = "../models" }
|
models = { path = "../models" }
|
||||||
|
|
||||||
async-std = { version = "1.13.1", features = ["attributes", "tokio1"] }
|
async-std = { version = "1.13.1", features = ["attributes", "tokio1"] }
|
||||||
sea-orm-migration = { version = "1.1.12", features = [
|
sea-orm-migration = { version = "1.1.12", features = ["sqlx-postgres"] }
|
||||||
"sqlx-sqlite",
|
|
||||||
"sqlx-postgres",
|
|
||||||
] }
|
|
||||||
|
@@ -13,7 +13,6 @@ serde = { workspace = true }
|
|||||||
serde_json = { workspace = true }
|
serde_json = { workspace = true }
|
||||||
sea-orm = { workspace = true, features = [
|
sea-orm = { workspace = true, features = [
|
||||||
"sqlx-postgres",
|
"sqlx-postgres",
|
||||||
"sqlx-sqlite",
|
|
||||||
"runtime-tokio-rustls",
|
"runtime-tokio-rustls",
|
||||||
"macros",
|
"macros",
|
||||||
] }
|
] }
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
use api::{setup_config, setup_db, setup_router};
|
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) {
|
async fn worker(child_num: u32, db_url: &str, prefork: bool, listener: std::net::TcpListener) {
|
||||||
let conn = setup_db(db_url, prefork).await;
|
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")]
|
#[cfg(feature = "prefork")]
|
||||||
fn run_prefork(db_url: &str, listener: std::net::TcpListener) {
|
fn run_prefork(db_url: &str, listener: std::net::TcpListener) {
|
||||||
let db_url: &'static str = Box::leak(db_url.to_owned().into_boxed_str());
|
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 num_of_cores = std::thread::available_parallelism().unwrap().get() as u32;
|
||||||
let is_parent = prefork::Prefork::from_resource(listener)
|
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) {
|
fn run_non_prefork(db_url: &str, listener: std::net::TcpListener) {
|
||||||
create_dev_db(db_url);
|
|
||||||
|
|
||||||
let rt = tokio::runtime::Runtime::new().unwrap();
|
let rt = tokio::runtime::Runtime::new().unwrap();
|
||||||
rt.block_on(worker(0, db_url, false, listener));
|
rt.block_on(worker(0, db_url, false, listener));
|
||||||
}
|
}
|
||||||
|
@@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,6 +1,4 @@
|
|||||||
mod db;
|
mod db;
|
||||||
mod file;
|
|
||||||
pub mod testing;
|
pub mod testing;
|
||||||
|
|
||||||
pub use db::migrate;
|
pub use db::migrate;
|
||||||
pub use file::create_dev_db;
|
|
||||||
|
@@ -1,30 +1,27 @@
|
|||||||
FROM oven/bun:1 AS base
|
FROM node:22-slim AS builder
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
FROM base AS install
|
ARG NEXT_PUBLIC_API_URL
|
||||||
RUN mkdir -p /temp/dev
|
ENV NEXT_PUBLIC_API_URL=$NEXT_PUBLIC_API_URL
|
||||||
COPY package.json bun.lock /temp/dev/
|
|
||||||
RUN cd /temp/dev && bun install --frozen-lockfile
|
|
||||||
|
|
||||||
RUN mkdir -p /temp/prod
|
# Install dependencies with Bun for speed
|
||||||
COPY package.json bun.lock /temp/prod/
|
COPY --chown=node:node package.json bun.lock ./
|
||||||
RUN cd /temp/prod && bun install --frozen-lockfile --production
|
RUN npm install -g bun
|
||||||
|
RUN bun install --frozen-lockfile
|
||||||
|
|
||||||
FROM base AS prerelease
|
# Copy the rest of the app and build with Node's Next.js runtime
|
||||||
COPY --from=install /temp/dev/node_modules node_modules
|
COPY --chown=node:node . .
|
||||||
COPY . .
|
|
||||||
|
|
||||||
ENV NODE_ENV=production
|
ENV NODE_ENV=production
|
||||||
RUN bun run build
|
RUN bun run build
|
||||||
|
|
||||||
FROM base AS release
|
FROM node:22-slim AS release
|
||||||
|
|
||||||
COPY --from=prerelease /app/public ./public
|
COPY --from=builder /app/public ./public
|
||||||
COPY --from=prerelease /app/.next/standalone ./
|
COPY --from=builder /app/.next/standalone ./
|
||||||
COPY --from=prerelease /app/.next/static ./.next/static
|
COPY --from=builder /app/.next/static ./.next/static
|
||||||
|
|
||||||
USER bun
|
|
||||||
EXPOSE 3000
|
EXPOSE 3000
|
||||||
|
|
||||||
CMD ["bun", "run", "server.js"]
|
CMD ["node", "server.js"]
|
||||||
|
|
||||||
|
@@ -14,7 +14,6 @@ import { PopularTags } from "@/components/popular-tags";
|
|||||||
import { ThoughtThread } from "@/components/thought-thread";
|
import { ThoughtThread } from "@/components/thought-thread";
|
||||||
import { buildThoughtThreads } from "@/lib/utils";
|
import { buildThoughtThreads } from "@/lib/utils";
|
||||||
import { TopFriends } from "@/components/top-friends";
|
import { TopFriends } from "@/components/top-friends";
|
||||||
import InstallPrompt from "@/components/install-prompt";
|
|
||||||
|
|
||||||
export default async function Home() {
|
export default async function Home() {
|
||||||
const token = (await cookies()).get("auth_token")?.value ?? null;
|
const token = (await cookies()).get("auth_token")?.value ?? null;
|
||||||
|
@@ -111,7 +111,10 @@ export type ApiKey = z.infer<typeof ApiKeySchema>;
|
|||||||
export type ApiKeyResponse = z.infer<typeof ApiKeyResponseSchema>;
|
export type ApiKeyResponse = z.infer<typeof ApiKeyResponseSchema>;
|
||||||
export type ThoughtThread = z.infer<typeof ThoughtThreadSchema>;
|
export type ThoughtThread = z.infer<typeof ThoughtThreadSchema>;
|
||||||
|
|
||||||
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<T>(
|
async function apiFetch<T>(
|
||||||
endpoint: string,
|
endpoint: string,
|
||||||
@@ -119,6 +122,10 @@ async function apiFetch<T>(
|
|||||||
schema: z.ZodType<T>,
|
schema: z.ZodType<T>,
|
||||||
token?: string | null
|
token?: string | null
|
||||||
): Promise<T> {
|
): Promise<T> {
|
||||||
|
if (!API_BASE_URL) {
|
||||||
|
throw new Error("API_BASE_URL is not defined");
|
||||||
|
}
|
||||||
|
|
||||||
const headers: Record<string, string> = {
|
const headers: Record<string, string> = {
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
...(options.headers as Record<string, string>),
|
...(options.headers as Record<string, string>),
|
||||||
@@ -128,7 +135,8 @@ async function apiFetch<T>(
|
|||||||
headers["Authorization"] = `Bearer ${token}`;
|
headers["Authorization"] = `Bearer ${token}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
const response = await fetch(`${API_BASE_URL}${endpoint}`, {
|
const fullUrl = `${API_BASE_URL}${endpoint}`;
|
||||||
|
const response = await fetch(fullUrl, {
|
||||||
...options,
|
...options,
|
||||||
headers,
|
headers,
|
||||||
});
|
});
|
||||||
|
Reference in New Issue
Block a user