build: package standalone self hosted runtime

This commit is contained in:
poyrazavsever
2026-07-18 20:18:23 +03:00
parent 090d10ae31
commit 100b624061
10 changed files with 48 additions and 12223 deletions
View File
-19
View File
@@ -1,19 +0,0 @@
> mood-tracker-mvp@0.1.0 dev D:\Poyraz\kodlama\Introduction-to-Data-Visualization-Project-Assignment
> next dev "--port" "3010"
▲ Next.js 16.2.6 (Turbopack)
- Local: http://localhost:3010
- Network: http://192.168.0.114:3010
- Environments: .env.local
✓ Ready in 1070ms
Creating turbopack project {
dir: 'D:\\Poyraz\\kodlama\\Introduction-to-Data-Visualization-Project-Assignment',
testMode: true
}
○ Compiling /login ...
GET /login 200 in 8.7s (next.js: 7.6s, proxy.ts: 335ms, application-code: 738ms)
GET /register 200 in 8.4s (next.js: 8.0s, proxy.ts: 10ms, application-code: 395ms)
[?25h
ELIFECYCLE Command failed with exit code 1.
+4
View File
@@ -14,3 +14,7 @@ yarn-error.log*
pnpm-debug.log* pnpm-debug.log*
.pnpm-store/ .pnpm-store/
*.tsbuildinfo *.tsbuildinfo
.DS_Store
.artifacts/
__pycache__/
*.py[cod]
+5 -4
View File
@@ -1,14 +1,16 @@
FROM node:22-bookworm-slim AS deps FROM node:22-bookworm-slim AS deps
WORKDIR /app WORKDIR /app
COPY package.json package-lock.json ./ RUN corepack enable
RUN npm ci COPY package.json pnpm-lock.yaml pnpm-workspace.yaml ./
RUN pnpm install --frozen-lockfile --config.node-linker=hoisted
FROM node:22-bookworm-slim AS builder FROM node:22-bookworm-slim AS builder
WORKDIR /app WORKDIR /app
ENV NEXT_TELEMETRY_DISABLED=1 ENV NEXT_TELEMETRY_DISABLED=1
RUN corepack enable
COPY --from=deps /app/node_modules ./node_modules COPY --from=deps /app/node_modules ./node_modules
COPY . . COPY . .
RUN npm run build RUN pnpm --config.node-linker=hoisted build
FROM node:22-bookworm-slim AS runner FROM node:22-bookworm-slim AS runner
WORKDIR /app WORKDIR /app
@@ -25,7 +27,6 @@ RUN groupadd --system --gid 1001 nodejs \
COPY --from=builder /app/public ./public COPY --from=builder /app/public ./public
COPY --from=builder /app/.next/standalone ./ COPY --from=builder /app/.next/standalone ./
COPY --from=builder /app/.next/static ./.next/static
COPY --from=builder /app/scripts ./scripts COPY --from=builder /app/scripts ./scripts
COPY --from=builder /app/server/db/migrations ./server/db/migrations COPY --from=builder /app/server/db/migrations ./server/db/migrations
COPY --from=builder /app/node_modules/drizzle-orm ./node_modules/drizzle-orm COPY --from=builder /app/node_modules/drizzle-orm ./node_modules/drizzle-orm
+5 -1
View File
@@ -32,7 +32,7 @@ Kalıcı veri ağacı:
## Gereksinimler ## Gereksinimler
- Node.js 22 - Node.js 22
- pnpm 11 (lokal geliştirme için) - pnpm 11.5.1 (lokal geliştirme ve Docker build için; sürüm `packageManager` alanında sabittir)
- Production'da kalıcı disk/volume - Production'da kalıcı disk/volume
- Localhost dışındaki production kurulumunda HTTPS reverse proxy - Localhost dışındaki production kurulumunda HTTPS reverse proxy
@@ -44,6 +44,8 @@ cp .env.example .env.local
openssl rand -base64 32 openssl rand -base64 32
``` ```
`pnpm-lock.yaml` repository'nin tek canonical dependency lockfile'ıdır. Lokal kurulum ve Docker image aynı çözümü kullanır.
Üretilen secret'ı `.env.local` içindeki `BETTER_AUTH_SECRET` alanına koyun, ardından: Üretilen secret'ı `.env.local` içindeki `BETTER_AUTH_SECRET` alanına koyun, ardından:
```bash ```bash
@@ -188,6 +190,8 @@ pnpm build
`phase8:release-boundary`; Supabase, PWA ve browser database bağımlılıklarının runtime'a geri dönmesini engeller. `phase8:release-boundary`; Supabase, PWA ve browser database bağımlılıklarının runtime'a geri dönmesini engeller.
Güncel teknik yayın durumu, doğrulama kanıtları, kalıntı güvenlik riskleri ve gerçek production cutover sınırı: [2026-07-18 release-readiness raporu](docs/self-hosted-redesign/release-readiness-2026-07-18.md).
## Lisans ## Lisans
Bu proje kişisel self-hosting amacıyla geliştirilen proprietary bir projedir. Bu proje kişisel self-hosting amacıyla geliştirilen proprietary bir projedir.
+1 -1
View File
@@ -9,7 +9,7 @@
@layer base { @layer base {
:root { :root {
--poyraz-font-primary: var(--font-geist-sans), ui-sans-serif, system-ui, sans-serif; --poyraz-font-primary: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
} }
* { * {
+1 -3
View File
@@ -2,7 +2,6 @@ import type { Metadata, Viewport } from "next";
import type { CSSProperties } from "react"; import type { CSSProperties } from "react";
import { cookies } from "next/headers"; import { cookies } from "next/headers";
import "./globals.css"; import "./globals.css";
import { Geist } from "next/font/google";
import { cn } from "@/lib/utils"; import { cn } from "@/lib/utils";
import { import {
COLOR_MODE_COOKIE, COLOR_MODE_COOKIE,
@@ -11,7 +10,6 @@ import {
import { Toaster } from "poyraz-ui/molecules"; import { Toaster } from "poyraz-ui/molecules";
import { getPublicBranding } from "@/server/branding/runtime"; import { getPublicBranding } from "@/server/branding/runtime";
const geist = Geist({ subsets: ["latin"], variable: "--font-geist-sans" });
const colorModeScript = `(() => { const colorModeScript = `(() => {
const root = document.documentElement; const root = document.documentElement;
const media = window.matchMedia("(prefers-color-scheme: dark)"); const media = window.matchMedia("(prefers-color-scheme: dark)");
@@ -58,7 +56,7 @@ export default async function RootLayout({
return ( return (
<html <html
lang="tr" lang="tr"
className={cn("font-sans", geist.variable, colorMode === "dark" && "dark")} className={cn("font-sans", colorMode === "dark" && "dark")}
data-color-mode={colorMode} data-color-mode={colorMode}
style={branding.cssVariables as CSSProperties} style={branding.cssVariables as CSSProperties}
suppressHydrationWarning suppressHydrationWarning
-12194
View File
File diff suppressed because it is too large Load Diff
+3 -1
View File
@@ -2,12 +2,14 @@
"name": "neta", "name": "neta",
"version": "0.1.0", "version": "0.1.0",
"private": true, "private": true,
"packageManager": "pnpm@11.5.1",
"scripts": { "scripts": {
"predev": "node scripts/migrate.mjs", "predev": "node scripts/migrate.mjs",
"dev": "next dev", "dev": "next dev",
"build": "next build", "build": "next build",
"postbuild": "node scripts/prepare-standalone.mjs",
"prestart": "node scripts/migrate.mjs", "prestart": "node scripts/migrate.mjs",
"start": "next start", "start": "node .next/standalone/server.js",
"lint": "eslint .", "lint": "eslint .",
"typecheck": "tsc --noEmit", "typecheck": "tsc --noEmit",
"db:generate": "drizzle-kit generate", "db:generate": "drizzle-kit generate",
+29
View File
@@ -0,0 +1,29 @@
import { cp, mkdir, stat } from "node:fs/promises";
import path from "node:path";
const rootDir = process.cwd();
const standaloneDir = path.join(rootDir, ".next", "standalone");
async function requireDirectory(directory, label) {
const info = await stat(directory).catch(() => null);
if (!info?.isDirectory()) {
throw new Error(`${label} bulunamadı: ${directory}`);
}
}
await requireDirectory(standaloneDir, "Next.js standalone çıktısı");
await requireDirectory(path.join(rootDir, ".next", "static"), "Next.js static çıktısı");
await requireDirectory(path.join(rootDir, "public"), "Public dizini");
await mkdir(path.join(standaloneDir, ".next"), { recursive: true });
await cp(path.join(rootDir, ".next", "static"), path.join(standaloneDir, ".next", "static"), {
recursive: true,
force: true,
});
await cp(path.join(rootDir, "public"), path.join(standaloneDir, "public"), {
recursive: true,
force: true,
});
console.log("Standalone runtime assets prepared.");