Compare commits
28
Commits
dd0b88b6eb
..
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
985137b802 | ||
|
|
4179eee26d | ||
|
|
3dae506a6c | ||
|
|
a1c861202a | ||
|
|
ece8626137 | ||
|
|
576a85cd50 | ||
|
|
39b3636333 | ||
|
|
ec5e6b1629 | ||
|
|
00a3a89263 | ||
|
|
d97dd955d1 | ||
|
|
17e0cfe8a3 | ||
|
|
617f00b715 | ||
|
|
970986fef7 | ||
|
|
7a13dad693 | ||
|
|
3f90c33c5f | ||
|
|
17ceefe32a | ||
|
|
e7185103f5 | ||
|
|
f2d4241a1c | ||
|
|
2251209935 | ||
|
|
b5d3df6d7c | ||
|
|
f5b1593e46 | ||
|
|
f0bdf185d5 | ||
|
|
5871606ae6 | ||
|
|
c632751a7e | ||
|
|
25599a5516 | ||
|
|
7d94fe53ad | ||
|
|
ada029d500 | ||
|
|
246ddac9e7 |
No files matched your search
@@ -1,86 +0,0 @@
|
|||||||
# AOS — Agency Operating System Environment (dev)
|
|
||||||
|
|
||||||
# --- Database ---
|
|
||||||
DATABASE_URL=file:/home/z/my-project/db/custom.db
|
|
||||||
|
|
||||||
# --- Encryption (AES-256-GCM for secrets at rest) ---
|
|
||||||
ENCRYPTION_KEY=UrEE757ABMzqcME/AQfef9XDPSaBlgIhVDOy8BIpbSY=
|
|
||||||
|
|
||||||
# --- Auth ---
|
|
||||||
AUTH_SECRET=zB7wxxn7xDnClPUlwoKG4VwHDaIqvtAz3DW3Bn43GlM=
|
|
||||||
|
|
||||||
# --- Leads Finder Providers ---
|
|
||||||
TAVILY_API_KEY=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
|
|
||||||
FIRECRAWL_API_KEY=fc-2ddabe84274a44b39da31a49d1624700
|
|
||||||
SERPAPI_API_KEY=5e1d045575cc29b705c53e8303b6ada506e8a3ef382fca78a2964c7e25751ba1
|
|
||||||
APIFY_API_TOKEN=apify_api_YUsr1w7L0qFpvzwDirjv1oWHToT2xu3lhJt7
|
|
||||||
|
|
||||||
# --- App ---
|
|
||||||
NODE_ENV=development
|
|
||||||
PORT=3000
|
|
||||||
|
|
||||||
# ── Stripe ──
|
|
||||||
STRIPE_PUBLISHABLE_KEY=pk_test_51TWfTxDGcQIOgPxeHVZh5ilWEc61bK7MBuBez4fGV5XrjRGwRXsXJp5rm1eAsWHGzQ20NBXRG7Nmp0pJRJfUflImA003OoDaSQt
|
|
||||||
STRIPE_SECRET_KEY=sk_test_51TWfTxDGcQIOgPxej8AvcfLMt6a7IEgZk3L34WLnOCNw2AAAyqORQtgJLjEaj3Ygm014ZAo3oByvDSdJVFwYLHmk0048mdLZH4
|
|
||||||
RESTRICTED_KEY=rk_test_51TWfTxDGcQIOgPxeGPSfA6ske0A6xPde23jfOJKbUfFOrEWl4bTIHv4MSOBwlQpravXk4mxKAjKdmkGb3asZqOVJ0048mdLZH4
|
|
||||||
|
|
||||||
# ── License Server (B2B SaaS) ──
|
|
||||||
LICENSE_PRICE_STARTER_CENTS=2900
|
|
||||||
LICENSE_PRICE_PRO_CENTS=5000
|
|
||||||
LICENSE_PRICE_ENTERPRISE_CENTS=15000
|
|
||||||
LICENSE_TRIAL_DAYS=14
|
|
||||||
LICENSE_NOTICE_PERIOD_DAYS=90
|
|
||||||
LICENSE_YEARLY_DISCOUNT_PCT=10
|
|
||||||
LICENSE_OFFLINE_GRACE_HOURS=72
|
|
||||||
|
|
||||||
# ── Agency / Reseller ──
|
|
||||||
AGENCY_DISCOUNT_MIN_PCT=0
|
|
||||||
AGENCY_DISCOUNT_MAX_PCT=20
|
|
||||||
AGENCY_DISCOUNT_DEFAULT_PCT=10
|
|
||||||
|
|
||||||
# ── Platform Domain ──
|
|
||||||
# The domain AOS runs on. Tenant instances get subdomains of this domain.
|
|
||||||
PLATFORM_DOMAIN=dfmpanel.eu
|
|
||||||
# Public URL of the AOS instance (used by license-server SDK + email links)
|
|
||||||
AOS_PUBLIC_URL=https://dfmpanel.eu
|
|
||||||
|
|
||||||
# ── Dokploy (tenant instance provisioning) ──
|
|
||||||
# Dokploy server URL + API key for managing tenant instances.
|
|
||||||
DOKPLOY_URL=https://cp.project-url.eu
|
|
||||||
DOKPLOY_API_KEY=CEIqJlWVtmSNgffNWywTJmEeuvUJBndinBzudretwiuzVWPxuvUNmoQaHUwRwUBy
|
|
||||||
# The Dokploy server ID to deploy to (default "default" if not set)
|
|
||||||
# DOKPLOY_SERVER_ID=default
|
|
||||||
# The Dokploy project to group tenant applications under
|
|
||||||
# DOKPLOY_PROJECT_ID=default
|
|
||||||
# The IP of the Dokploy server (used for Hetzner DNS A records)
|
|
||||||
# DOKPLOY_SERVER_IP=123.456.789.012
|
|
||||||
|
|
||||||
# ── Hetzner Cloud DNS ──
|
|
||||||
# DNS is managed via the Hetzner Cloud API (api.hetzner.cloud/v1/zones).
|
|
||||||
# The legacy dns.hetzner.com API was shut down in May 2026.
|
|
||||||
HETZNER_DNS_TOKEN=JhZMOBTMeWvXz91KVPxRh0U4UMFqkSNCMHJKiQS9kUjHIwCkWCc8ViZTm64MyaOp
|
|
||||||
# Zone ID of dfmpanel.eu (found via: GET https://api.hetzner.cloud/v1/zones)
|
|
||||||
HETZNER_ZONE_ID=1669672
|
|
||||||
# If true, a single *.dfmpanel.eu wildcard A record handles all subdomains.
|
|
||||||
# If false, a per-instance A record is created/deleted with each instance.
|
|
||||||
USE_WILDCARD_DNS=false
|
|
||||||
|
|
||||||
# ── Dokploy Server ──
|
|
||||||
# IP of the Dokploy server (A record target for instance subdomains).
|
|
||||||
# Found from the existing @ and www A records of dfmpanel.eu.
|
|
||||||
DOKPLOY_SERVER_IP=92.206.22.59
|
|
||||||
|
|
||||||
# ── Cron Job ──
|
|
||||||
# Shared secret for the cleanup cron job (POST /api/aos/instances/cleanup)
|
|
||||||
# The cron job (Dokploy cron or GitHub Action) must send this as:
|
|
||||||
# Authorization: Bearer <CRON_SECRET>
|
|
||||||
# CRON_SECRET=your-cron-secret
|
|
||||||
|
|
||||||
# ── Instance Defaults ──
|
|
||||||
# Default Git repo + branch for new tenant instances
|
|
||||||
INSTANCE_GIT_REPO=https://github.com/cetinmustafa83/restov1
|
|
||||||
INSTANCE_GIT_BRANCH=main
|
|
||||||
# Demo instance duration in days
|
|
||||||
INSTANCE_DEMO_DAYS=14
|
|
||||||
# Grace period after demo expiry or subscription cancellation (days)
|
|
||||||
INSTANCE_GRACE_DAYS=7
|
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
name: AOS Cleanup Cron
|
||||||
|
|
||||||
|
on:
|
||||||
|
schedule:
|
||||||
|
# Run daily at 03:00 UTC (05:00 Berlin time)
|
||||||
|
- cron: '0 3 * * *'
|
||||||
|
workflow_dispatch: # Allow manual trigger
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
cleanup:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Trigger instance cleanup
|
||||||
|
run: |
|
||||||
|
RESPONSE=$(curl -s -w "\n%{http_code}" -X POST \
|
||||||
|
"${{ secrets.AOS_URL || 'https://dfmpanel.eu' }}/api/aos/instances/cleanup" \
|
||||||
|
-H "Authorization: Bearer ${{ secrets.CRON_SECRET }}" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
--max-time 300)
|
||||||
|
HTTP_CODE=$(echo "$RESPONSE" | tail -1)
|
||||||
|
BODY=$(echo "$RESPONSE" | sed '$d')
|
||||||
|
echo "HTTP $HTTP_CODE"
|
||||||
|
echo "Response: $BODY"
|
||||||
|
if [ "$HTTP_CODE" != "200" ]; then
|
||||||
|
echo "::warning::Cleanup returned HTTP $HTTP_CODE"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
echo "::notice::Cleanup completed successfully"
|
||||||
@@ -59,3 +59,6 @@ aos-verify*.sh
|
|||||||
.dev.pid
|
.dev.pid
|
||||||
.zscripts/dev.pid
|
.zscripts/dev.pid
|
||||||
db/backups/
|
db/backups/
|
||||||
|
.env
|
||||||
|
tool-results/
|
||||||
|
upload/
|
||||||
+11
-6
@@ -3,23 +3,24 @@
|
|||||||
# Multi-stage build: install → build → run
|
# Multi-stage build: install → build → run
|
||||||
|
|
||||||
# --- Stage 1: Install dependencies ---
|
# --- Stage 1: Install dependencies ---
|
||||||
FROM node:22-slim AS deps
|
FROM node:24-slim AS deps
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
COPY package.json bun.lock ./
|
COPY package.json bun.lock ./
|
||||||
RUN npm install --legacy-peer-deps
|
RUN npm install --legacy-peer-deps
|
||||||
|
|
||||||
# --- Stage 2: Build ---
|
# --- Stage 2: Build ---
|
||||||
FROM node:22-slim AS builder
|
FROM node:24-slim AS builder
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
COPY --from=deps /app/node_modules ./node_modules
|
COPY --from=deps /app/node_modules ./node_modules
|
||||||
COPY . .
|
COPY . .
|
||||||
ENV NEXT_TELEMETRY_DISABLED=1
|
ENV NEXT_TELEMETRY_DISABLED=1
|
||||||
ENV DATABASE_URL="file:/app/db/custom.db"
|
ENV DATABASE_URL="file:/app/db/custom.db"
|
||||||
|
RUN apt-get update && apt-get install -y --no-install-recommends openssl && rm -rf /var/lib/apt/lists/*
|
||||||
RUN npx prisma generate
|
RUN npx prisma generate
|
||||||
RUN npm run build
|
RUN npm run build
|
||||||
|
|
||||||
# --- Stage 3: Runner ---
|
# --- Stage 3: Runner ---
|
||||||
FROM node:22-slim AS runner
|
FROM node:24-slim AS runner
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
ENV NODE_ENV=production
|
ENV NODE_ENV=production
|
||||||
@@ -29,9 +30,12 @@ ENV HOSTNAME=0.0.0.0
|
|||||||
|
|
||||||
# Install only what's needed for production
|
# Install only what's needed for production
|
||||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||||
sqlite3 curl && \
|
sqlite3 curl openssl && \
|
||||||
rm -rf /var/lib/apt/lists/*
|
rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
# Pin prisma CLI into the image so CMD's db push doesn't npx-download prisma on every start
|
||||||
|
RUN npm i -g prisma@6.19.2
|
||||||
|
|
||||||
# Copy built app
|
# Copy built app
|
||||||
COPY --from=builder /app/public ./public
|
COPY --from=builder /app/public ./public
|
||||||
COPY --from=builder /app/.next/standalone ./
|
COPY --from=builder /app/.next/standalone ./
|
||||||
@@ -49,5 +53,6 @@ HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \
|
|||||||
|
|
||||||
EXPOSE 3000
|
EXPOSE 3000
|
||||||
|
|
||||||
# Run migrations + start server
|
# Run migrations + start server. NODE_ENV is forced here because the deploy
|
||||||
CMD ["sh", "-c", "npx prisma db push --accept-data-loss && node server.js"]
|
# platform injects NODE_ENV=development, which breaks the production server.
|
||||||
|
CMD ["sh", "-c", "npx prisma db push --accept-data-loss && NODE_ENV=production node server.js"]
|
||||||
@@ -43,6 +43,7 @@
|
|||||||
"@reactuses/core": "^6.0.5",
|
"@reactuses/core": "^6.0.5",
|
||||||
"@tanstack/react-query": "^5.82.0",
|
"@tanstack/react-query": "^5.82.0",
|
||||||
"@tanstack/react-table": "^8.21.3",
|
"@tanstack/react-table": "^8.21.3",
|
||||||
|
"@types/nodemailer": "^8.0.2",
|
||||||
"class-variance-authority": "^0.7.1",
|
"class-variance-authority": "^0.7.1",
|
||||||
"clsx": "^2.1.1",
|
"clsx": "^2.1.1",
|
||||||
"cmdk": "^1.1.1",
|
"cmdk": "^1.1.1",
|
||||||
@@ -57,6 +58,7 @@
|
|||||||
"next-auth": "^4.24.11",
|
"next-auth": "^4.24.11",
|
||||||
"next-intl": "^4.3.4",
|
"next-intl": "^4.3.4",
|
||||||
"next-themes": "^0.4.6",
|
"next-themes": "^0.4.6",
|
||||||
|
"nodemailer": "^10.2.1",
|
||||||
"prisma": "^6.11.1",
|
"prisma": "^6.11.1",
|
||||||
"react": "^19.0.0",
|
"react": "^19.0.0",
|
||||||
"react-day-picker": "^9.8.0",
|
"react-day-picker": "^9.8.0",
|
||||||
@@ -68,6 +70,7 @@
|
|||||||
"recharts": "^2.15.4",
|
"recharts": "^2.15.4",
|
||||||
"sharp": "^0.34.3",
|
"sharp": "^0.34.3",
|
||||||
"sonner": "^2.0.6",
|
"sonner": "^2.0.6",
|
||||||
|
"stripe": "^23.0.1",
|
||||||
"tailwind-merge": "^3.7.0",
|
"tailwind-merge": "^3.7.0",
|
||||||
"tailwindcss-animate": "^1.0.7",
|
"tailwindcss-animate": "^1.0.7",
|
||||||
"uuid": "^11.1.0",
|
"uuid": "^11.1.0",
|
||||||
@@ -720,6 +723,8 @@
|
|||||||
|
|
||||||
"@types/node": ["@types/node@25.0.9", "https://registry.npmjs.com/@types/node/-/node-25.0.9.tgz", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-/rpCXHlCWeqClNBwUhDcusJxXYDjZTyE8v5oTO7WbL8eij2nKhUeU89/6xgjU7N4/Vh3He0BtyhJdQbDyhiXAw=="],
|
"@types/node": ["@types/node@25.0.9", "https://registry.npmjs.com/@types/node/-/node-25.0.9.tgz", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-/rpCXHlCWeqClNBwUhDcusJxXYDjZTyE8v5oTO7WbL8eij2nKhUeU89/6xgjU7N4/Vh3He0BtyhJdQbDyhiXAw=="],
|
||||||
|
|
||||||
|
"@types/nodemailer": ["@types/nodemailer@8.0.2", "", { "dependencies": { "@types/node": "*" } }, "sha512-c7M5ox8p0nEOfbJ2E9Qcmt8/QCu/VzsiAhzBiZbvky2PhKZDHpKB3sQHBM5MEZNkCfBOaS6S9//AGPRTNB7IaA=="],
|
||||||
|
|
||||||
"@types/react": ["@types/react@19.2.8", "https://registry.npmjs.com/@types/react/-/react-19.2.8.tgz", { "dependencies": { "csstype": "^3.2.2" } }, "sha512-3MbSL37jEchWZz2p2mjntRZtPt837ij10ApxKfgmXCTuHWagYg7iA5bqPw6C8BMPfwidlvfPI/fxOc42HLhcyg=="],
|
"@types/react": ["@types/react@19.2.8", "https://registry.npmjs.com/@types/react/-/react-19.2.8.tgz", { "dependencies": { "csstype": "^3.2.2" } }, "sha512-3MbSL37jEchWZz2p2mjntRZtPt837ij10ApxKfgmXCTuHWagYg7iA5bqPw6C8BMPfwidlvfPI/fxOc42HLhcyg=="],
|
||||||
|
|
||||||
"@types/react-dom": ["@types/react-dom@19.2.3", "https://registry.npmjs.com/@types/react-dom/-/react-dom-19.2.3.tgz", { "peerDependencies": { "@types/react": "^19.2.0" } }, "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ=="],
|
"@types/react-dom": ["@types/react-dom@19.2.3", "https://registry.npmjs.com/@types/react-dom/-/react-dom-19.2.3.tgz", { "peerDependencies": { "@types/react": "^19.2.0" } }, "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ=="],
|
||||||
@@ -1520,6 +1525,8 @@
|
|||||||
|
|
||||||
"node-releases": ["node-releases@2.0.27", "https://registry.npmjs.com/node-releases/-/node-releases-2.0.27.tgz", {}, "sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA=="],
|
"node-releases": ["node-releases@2.0.27", "https://registry.npmjs.com/node-releases/-/node-releases-2.0.27.tgz", {}, "sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA=="],
|
||||||
|
|
||||||
|
"nodemailer": ["nodemailer@10.2.1", "", {}, "sha512-ZrDNsPFoDMwefNs7sJwrYiEJ/CG4ClJWDZv05iNJsEBWa8GRDry1QJHTJxsuTAY9eDDKjX4k+q3SxslXJOao7w=="],
|
||||||
|
|
||||||
"nypm": ["nypm@0.6.2", "https://registry.npmjs.com/nypm/-/nypm-0.6.2.tgz", { "dependencies": { "citty": "^0.1.6", "consola": "^3.4.2", "pathe": "^2.0.3", "pkg-types": "^2.3.0", "tinyexec": "^1.0.1" }, "bin": { "nypm": "dist/cli.mjs" } }, "sha512-7eM+hpOtrKrBDCh7Ypu2lJ9Z7PNZBdi/8AT3AX8xoCj43BBVHD0hPSTEvMtkMpfs8FCqBGhxB+uToIQimA111g=="],
|
"nypm": ["nypm@0.6.2", "https://registry.npmjs.com/nypm/-/nypm-0.6.2.tgz", { "dependencies": { "citty": "^0.1.6", "consola": "^3.4.2", "pathe": "^2.0.3", "pkg-types": "^2.3.0", "tinyexec": "^1.0.1" }, "bin": { "nypm": "dist/cli.mjs" } }, "sha512-7eM+hpOtrKrBDCh7Ypu2lJ9Z7PNZBdi/8AT3AX8xoCj43BBVHD0hPSTEvMtkMpfs8FCqBGhxB+uToIQimA111g=="],
|
||||||
|
|
||||||
"oauth": ["oauth@0.9.15", "https://registry.npmjs.com/oauth/-/oauth-0.9.15.tgz", {}, "sha512-a5ERWK1kh38ExDEfoO6qUHJb32rd7aYmPHuyCu3Fta/cnICvYmgd2uhuKXvPD+PXB+gCEYYEaQdIRAjCOwAKNA=="],
|
"oauth": ["oauth@0.9.15", "https://registry.npmjs.com/oauth/-/oauth-0.9.15.tgz", {}, "sha512-a5ERWK1kh38ExDEfoO6qUHJb32rd7aYmPHuyCu3Fta/cnICvYmgd2uhuKXvPD+PXB+gCEYYEaQdIRAjCOwAKNA=="],
|
||||||
@@ -1756,6 +1763,8 @@
|
|||||||
|
|
||||||
"strip-json-comments": ["strip-json-comments@3.1.1", "https://registry.npmjs.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz", {}, "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig=="],
|
"strip-json-comments": ["strip-json-comments@3.1.1", "https://registry.npmjs.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz", {}, "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig=="],
|
||||||
|
|
||||||
|
"stripe": ["stripe@23.0.1", "", { "peerDependencies": { "@types/node": ">=20" }, "optionalPeers": ["@types/node"] }, "sha512-VFLs9IAzSZ8GIm6/vqhjqOL0fbYrSNYCpgZ3LS3YkSi/i5RnyMpu/Hf9YxPTOCYwc3mZKU3IJvuvKffQH2NLMg=="],
|
||||||
|
|
||||||
"style-mod": ["style-mod@4.1.3", "https://registry.npmjs.com/style-mod/-/style-mod-4.1.3.tgz", {}, "sha512-i/n8VsZydrugj3Iuzll8+x/00GH2vnYsk1eomD8QiRrSAeW6ItbCQDtfXCeJHd0iwiNagqjQkvpvREEPtW3IoQ=="],
|
"style-mod": ["style-mod@4.1.3", "https://registry.npmjs.com/style-mod/-/style-mod-4.1.3.tgz", {}, "sha512-i/n8VsZydrugj3Iuzll8+x/00GH2vnYsk1eomD8QiRrSAeW6ItbCQDtfXCeJHd0iwiNagqjQkvpvREEPtW3IoQ=="],
|
||||||
|
|
||||||
"style-to-js": ["style-to-js@1.1.21", "https://registry.npmjs.com/style-to-js/-/style-to-js-1.1.21.tgz", { "dependencies": { "style-to-object": "1.0.14" } }, "sha512-RjQetxJrrUJLQPHbLku6U/ocGtzyjbJMP9lCNK7Ag0CNh690nSH8woqWH9u16nMjYBAok+i7JO1NP2pOy8IsPQ=="],
|
"style-to-js": ["style-to-js@1.1.21", "https://registry.npmjs.com/style-to-js/-/style-to-js-1.1.21.tgz", { "dependencies": { "style-to-object": "1.0.14" } }, "sha512-RjQetxJrrUJLQPHbLku6U/ocGtzyjbJMP9lCNK7Ag0CNh690nSH8woqWH9u16nMjYBAok+i7JO1NP2pOy8IsPQ=="],
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
# Pinned toolchain for deterministic builds (railpack/mise reads this).
|
||||||
|
# node 24 = LTS, proven locally; node 26 broke /_global-error prerender.
|
||||||
|
[tools]
|
||||||
|
node = "24"
|
||||||
|
bun = "1.3.14"
|
||||||
+8
-1
@@ -2,10 +2,14 @@
|
|||||||
"name": "nextjs_tailwind_shadcn_ts",
|
"name": "nextjs_tailwind_shadcn_ts",
|
||||||
"version": "0.2.1",
|
"version": "0.2.1",
|
||||||
"private": true,
|
"private": true,
|
||||||
|
"engines": {
|
||||||
|
"node": "24.x",
|
||||||
|
"bun": "1.3.x"
|
||||||
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "next dev -p 3000",
|
"dev": "next dev -p 3000",
|
||||||
"dev:log": "next dev -p 3000 2>&1 | tee dev.log",
|
"dev:log": "next dev -p 3000 2>&1 | tee dev.log",
|
||||||
"build": "prisma generate && next build --webpack && cp -r .next/static .next/standalone/.next/ && cp -r public .next/standalone/",
|
"build": "prisma generate && next build && cp -r .next/static .next/standalone/.next/ && cp -r public .next/standalone/",
|
||||||
"start": "NODE_ENV=production bun .next/standalone/server.js 2>&1 | tee server.log",
|
"start": "NODE_ENV=production bun .next/standalone/server.js 2>&1 | tee server.log",
|
||||||
"lint": "eslint .",
|
"lint": "eslint .",
|
||||||
"db:push": "prisma db push --accept-data-loss",
|
"db:push": "prisma db push --accept-data-loss",
|
||||||
@@ -53,6 +57,7 @@
|
|||||||
"@reactuses/core": "^6.0.5",
|
"@reactuses/core": "^6.0.5",
|
||||||
"@tanstack/react-query": "^5.82.0",
|
"@tanstack/react-query": "^5.82.0",
|
||||||
"@tanstack/react-table": "^8.21.3",
|
"@tanstack/react-table": "^8.21.3",
|
||||||
|
"@types/nodemailer": "^8.0.2",
|
||||||
"class-variance-authority": "^0.7.1",
|
"class-variance-authority": "^0.7.1",
|
||||||
"clsx": "^2.1.1",
|
"clsx": "^2.1.1",
|
||||||
"cmdk": "^1.1.1",
|
"cmdk": "^1.1.1",
|
||||||
@@ -67,6 +72,7 @@
|
|||||||
"next-auth": "^4.24.11",
|
"next-auth": "^4.24.11",
|
||||||
"next-intl": "^4.3.4",
|
"next-intl": "^4.3.4",
|
||||||
"next-themes": "^0.4.6",
|
"next-themes": "^0.4.6",
|
||||||
|
"nodemailer": "^10.2.1",
|
||||||
"prisma": "^6.11.1",
|
"prisma": "^6.11.1",
|
||||||
"react": "^19.0.0",
|
"react": "^19.0.0",
|
||||||
"react-day-picker": "^9.8.0",
|
"react-day-picker": "^9.8.0",
|
||||||
@@ -78,6 +84,7 @@
|
|||||||
"recharts": "^2.15.4",
|
"recharts": "^2.15.4",
|
||||||
"sharp": "^0.34.3",
|
"sharp": "^0.34.3",
|
||||||
"sonner": "^2.0.6",
|
"sonner": "^2.0.6",
|
||||||
|
"stripe": "^23.0.1",
|
||||||
"tailwind-merge": "^3.7.0",
|
"tailwind-merge": "^3.7.0",
|
||||||
"tailwindcss-animate": "^1.0.7",
|
"tailwindcss-animate": "^1.0.7",
|
||||||
"uuid": "^11.1.0",
|
"uuid": "^11.1.0",
|
||||||
|
|||||||
@@ -72,16 +72,22 @@ export async function PATCH(req: Request, { params }: { params: Promise<{ id: st
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
// TODO (production): send email to company.email with subject
|
// Send approval email
|
||||||
// "Ihre Reseller-Bewerbung wurde genehmigt — {discountPct}% Rabatt"
|
const { sendAgencyApprovedEmail } = await import('@/lib/email')
|
||||||
// containing the discount and a link to the agency portal.
|
if (application.company.email) {
|
||||||
|
await sendAgencyApprovedEmail({
|
||||||
|
to: application.company.email,
|
||||||
|
companyName: application.company.name,
|
||||||
|
discountPct,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
return NextResponse.json({
|
return NextResponse.json({
|
||||||
ok: true,
|
ok: true,
|
||||||
status: 'approved',
|
status: 'approved',
|
||||||
discountPct,
|
discountPct,
|
||||||
email: application.company.email,
|
email: application.company.email,
|
||||||
message: `Genehmigt mit ${discountPct}% Rabatt. E-Mail an ${application.company.email ?? '(keine E-Mail hinterlegt)'} würde versendet.`,
|
message: `Genehmigt mit ${discountPct}% Rabatt.${application.company.email ? ` E-Mail an ${application.company.email} versendet.` : ' Keine E-Mail hinterlegt.'}`,
|
||||||
})
|
})
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
const msg = err instanceof Error ? err.message : 'internal server error'
|
const msg = err instanceof Error ? err.message : 'internal server error'
|
||||||
|
|||||||
@@ -60,6 +60,16 @@ export async function PATCH(req: Request, { params }: { params: Promise<{ id: st
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// Send rejection email
|
||||||
|
const { sendAgencyRejectedEmail } = await import('@/lib/email')
|
||||||
|
if (application.company.email) {
|
||||||
|
await sendAgencyRejectedEmail({
|
||||||
|
to: application.company.email,
|
||||||
|
companyName: application.company.name,
|
||||||
|
reason,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
return NextResponse.json({ ok: true, status: 'rejected', reason })
|
return NextResponse.json({ ok: true, status: 'rejected', reason })
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
const msg = err instanceof Error ? err.message : 'internal server error'
|
const msg = err instanceof Error ? err.message : 'internal server error'
|
||||||
|
|||||||
@@ -0,0 +1,32 @@
|
|||||||
|
import { NextResponse } from 'next/server'
|
||||||
|
import { createGraphifyClientFromEnv } from '@/lib/graphify'
|
||||||
|
|
||||||
|
export const dynamic = 'force-dynamic'
|
||||||
|
|
||||||
|
// GET /api/aos/graphify-health
|
||||||
|
// Checks if the Graphify MCP HTTP service is configured and reachable.
|
||||||
|
// Used by the instance detail UI to show whether graphify is available.
|
||||||
|
export async function GET() {
|
||||||
|
const url = process.env.GRAPHIFY_URL
|
||||||
|
if (!url) {
|
||||||
|
return NextResponse.json({
|
||||||
|
configured: false,
|
||||||
|
ok: false,
|
||||||
|
message: 'Graphify not configured (GRAPHIFY_URL missing)',
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const client = createGraphifyClientFromEnv()
|
||||||
|
if (!client) {
|
||||||
|
return NextResponse.json({ configured: true, ok: false, message: 'client init failed' })
|
||||||
|
}
|
||||||
|
|
||||||
|
const health = await client.health()
|
||||||
|
return NextResponse.json({
|
||||||
|
configured: true,
|
||||||
|
ok: health.ok,
|
||||||
|
url,
|
||||||
|
version: health.version,
|
||||||
|
message: health.ok ? 'Graphify service is up' : 'Graphify service unreachable',
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -0,0 +1,289 @@
|
|||||||
|
import { NextResponse } from 'next/server'
|
||||||
|
import { db } from '@/lib/db'
|
||||||
|
import { z } from 'zod'
|
||||||
|
import { createHetznerDnsClientFromEnv } from '@/lib/hetzner-dns'
|
||||||
|
import { createDokployClientFromEnv } from '@/lib/dokploy'
|
||||||
|
|
||||||
|
export const dynamic = 'force-dynamic'
|
||||||
|
|
||||||
|
const postSchema = z.object({
|
||||||
|
domain: z.string().min(3).max(253).regex(/^[a-zA-Z0-9.-]+$/, 'invalid domain'),
|
||||||
|
})
|
||||||
|
|
||||||
|
// POST /api/aos/instances/[id]/custom-domain
|
||||||
|
// Step 1: Client requests to attach a custom domain.
|
||||||
|
// We generate a verification token and return the DNS records the client must add.
|
||||||
|
export async function POST(req: Request, { params }: { params: Promise<{ id: string }> }) {
|
||||||
|
try {
|
||||||
|
const { id } = await params
|
||||||
|
const parsed = postSchema.safeParse(await req.json())
|
||||||
|
if (!parsed.success) {
|
||||||
|
return NextResponse.json({ error: 'invalid domain', details: parsed.error.flatten() }, { status: 400 })
|
||||||
|
}
|
||||||
|
const domain = parsed.data.domain.toLowerCase()
|
||||||
|
|
||||||
|
// Validate domain format
|
||||||
|
if (domain.startsWith('-') || domain.endsWith('-') || domain.includes('..')) {
|
||||||
|
return NextResponse.json({ error: 'invalid domain format' }, { status: 400 })
|
||||||
|
}
|
||||||
|
// Reject IP addresses, wildcard domains, and platform-owned domains
|
||||||
|
if (/^\d+\.\d+\.\d+\.\d+$/.test(domain)) {
|
||||||
|
return NextResponse.json({ error: 'IP addresses not allowed' }, { status: 400 })
|
||||||
|
}
|
||||||
|
if (domain.startsWith('*.')) {
|
||||||
|
return NextResponse.json({ error: 'wildcard domains not allowed' }, { status: 400 })
|
||||||
|
}
|
||||||
|
const platformDomain = process.env.PLATFORM_DOMAIN ?? 'dfmpanel.eu'
|
||||||
|
if (domain === platformDomain || domain.endsWith(`.${platformDomain}`)) {
|
||||||
|
return NextResponse.json({ error: 'platform-owned domains not allowed' }, { status: 400 })
|
||||||
|
}
|
||||||
|
|
||||||
|
const instance = await db.instance.findUnique({ where: { id } })
|
||||||
|
if (!instance) {
|
||||||
|
return NextResponse.json({ error: 'instance not found' }, { status: 404 })
|
||||||
|
}
|
||||||
|
if (!['active', 'demo_active'].includes(instance.status)) {
|
||||||
|
return NextResponse.json({ error: `cannot attach domain to instance in status ${instance.status}` }, { status: 400 })
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check that the domain isn't already claimed by another instance
|
||||||
|
const existing = await db.instance.findFirst({
|
||||||
|
where: { customDomain: domain, id: { not: id } },
|
||||||
|
})
|
||||||
|
if (existing) {
|
||||||
|
return NextResponse.json({ error: 'domain already claimed by another instance' }, { status: 409 })
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate verification token
|
||||||
|
const crypto = await import('crypto')
|
||||||
|
const token = `dfm-verify-${crypto.randomBytes(16).toString('hex')}`
|
||||||
|
|
||||||
|
await db.instance.update({
|
||||||
|
where: { id },
|
||||||
|
data: {
|
||||||
|
customDomain: domain,
|
||||||
|
domainVerificationToken: token,
|
||||||
|
domainVerifiedAt: null,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
await db.instanceEvent.create({
|
||||||
|
data: {
|
||||||
|
instanceId: id,
|
||||||
|
type: 'domain.requested',
|
||||||
|
step: 'domain',
|
||||||
|
result: 'ok',
|
||||||
|
details: JSON.stringify({ domain, token }),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
// Return the DNS records the client must add
|
||||||
|
return NextResponse.json({
|
||||||
|
ok: true,
|
||||||
|
domain,
|
||||||
|
verificationToken: token,
|
||||||
|
dnsRecords: [
|
||||||
|
{
|
||||||
|
type: 'TXT',
|
||||||
|
name: `_dfm-verify.${domain}`,
|
||||||
|
value: token,
|
||||||
|
purpose: 'Domain ownership verification',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'CNAME',
|
||||||
|
name: domain,
|
||||||
|
value: `${instance.subdomain}.${platformDomain}`,
|
||||||
|
purpose: 'Point domain to the instance',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
instructions: [
|
||||||
|
`1. Füge einen TXT-Record hinzu: _dfm-verify.${domain} = ${token}`,
|
||||||
|
`2. Füge einen CNAME-Record hinzu: ${domain} → ${instance.subdomain}.${platformDomain}`,
|
||||||
|
`3. Warte 5-15 Minuten bis die DNS-Änderungen wirksam sind.`,
|
||||||
|
`4. Rufe dann die Verifizierung auf: PATCH /api/aos/instances/${id}/custom-domain`,
|
||||||
|
],
|
||||||
|
})
|
||||||
|
} catch (err) {
|
||||||
|
const msg = err instanceof Error ? err.message : 'internal server error'
|
||||||
|
return NextResponse.json({ error: msg }, { status: 500 })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// PATCH /api/aos/instances/[id]/custom-domain
|
||||||
|
// Step 2: Verify the DNS records and attach the domain in Dokploy.
|
||||||
|
export async function PATCH(req: Request, { params }: { params: Promise<{ id: string }> }) {
|
||||||
|
try {
|
||||||
|
const { id } = await params
|
||||||
|
const instance = await db.instance.findUnique({ where: { id } })
|
||||||
|
if (!instance) {
|
||||||
|
return NextResponse.json({ error: 'instance not found' }, { status: 404 })
|
||||||
|
}
|
||||||
|
if (!instance.customDomain || !instance.domainVerificationToken) {
|
||||||
|
return NextResponse.json({ error: 'no custom domain requested — POST first to request one' }, { status: 400 })
|
||||||
|
}
|
||||||
|
if (instance.domainVerifiedAt) {
|
||||||
|
return NextResponse.json({ error: 'domain already verified' }, { status: 409 })
|
||||||
|
}
|
||||||
|
|
||||||
|
const dns = createHetznerDnsClientFromEnv()
|
||||||
|
if (!dns) {
|
||||||
|
return NextResponse.json({ error: 'DNS client not configured' }, { status: 503 })
|
||||||
|
}
|
||||||
|
|
||||||
|
// 1. Verify TXT record
|
||||||
|
const txtResult = await dns.verifyTxtRecord(
|
||||||
|
`_dfm-verify.${instance.customDomain}`,
|
||||||
|
instance.domainVerificationToken
|
||||||
|
)
|
||||||
|
if (!txtResult.verified) {
|
||||||
|
await db.instanceEvent.create({
|
||||||
|
data: {
|
||||||
|
instanceId: id,
|
||||||
|
type: 'domain.verify.txt.failed',
|
||||||
|
step: 'domain',
|
||||||
|
result: 'error',
|
||||||
|
details: JSON.stringify({ error: txtResult.error }),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
return NextResponse.json({
|
||||||
|
ok: false,
|
||||||
|
verified: false,
|
||||||
|
step: 'txt',
|
||||||
|
error: txtResult.error,
|
||||||
|
message: 'TXT-Record noch nicht gefunden. Warte einige Minuten und versuche es erneut.',
|
||||||
|
}, { status: 202 })
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. Verify CNAME record
|
||||||
|
const platformDomain = process.env.PLATFORM_DOMAIN ?? 'dfmpanel.eu'
|
||||||
|
const expectedTarget = `${instance.subdomain}.${platformDomain}`
|
||||||
|
const cnameResult = await dns.verifyCustomDomainCname(instance.customDomain, expectedTarget)
|
||||||
|
if (!cnameResult.verified) {
|
||||||
|
await db.instanceEvent.create({
|
||||||
|
data: {
|
||||||
|
instanceId: id,
|
||||||
|
type: 'domain.verify.cname.failed',
|
||||||
|
step: 'domain',
|
||||||
|
result: 'error',
|
||||||
|
details: JSON.stringify({ error: cnameResult.error, found: cnameResult.found }),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
return NextResponse.json({
|
||||||
|
ok: false,
|
||||||
|
verified: false,
|
||||||
|
step: 'cname',
|
||||||
|
error: cnameResult.error,
|
||||||
|
message: `CNAME zeigt auf "${cnameResult.found ?? 'nichts'}", erwartet: "${expectedTarget}"`,
|
||||||
|
}, { status: 202 })
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. Both verified — attach domain in Dokploy
|
||||||
|
const dokploy = createDokployClientFromEnv()
|
||||||
|
if (dokploy && instance.dokployAppId) {
|
||||||
|
try {
|
||||||
|
await dokploy.createDomain({
|
||||||
|
applicationId: instance.dokployAppId,
|
||||||
|
hostName: instance.customDomain,
|
||||||
|
port: 3000,
|
||||||
|
https: true,
|
||||||
|
})
|
||||||
|
} catch (e) {
|
||||||
|
// Non-fatal — domain verification still succeeded, Dokploy attach can retry
|
||||||
|
await db.instanceEvent.create({
|
||||||
|
data: {
|
||||||
|
instanceId: id,
|
||||||
|
type: 'domain.dokploy.attach.error',
|
||||||
|
step: 'domain',
|
||||||
|
result: 'error',
|
||||||
|
details: JSON.stringify({ error: e instanceof Error ? e.message : 'unknown' }),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. Mark verified
|
||||||
|
await db.instance.update({
|
||||||
|
where: { id },
|
||||||
|
data: { domainVerifiedAt: new Date() },
|
||||||
|
})
|
||||||
|
|
||||||
|
await db.instanceEvent.create({
|
||||||
|
data: {
|
||||||
|
instanceId: id,
|
||||||
|
type: 'domain.verified',
|
||||||
|
step: 'domain',
|
||||||
|
result: 'ok',
|
||||||
|
details: JSON.stringify({ domain: instance.customDomain }),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
await db.auditLog.create({
|
||||||
|
data: {
|
||||||
|
actor: 'admin:ui',
|
||||||
|
action: 'instance.domain.verified',
|
||||||
|
entity: 'Instance',
|
||||||
|
entityId: id,
|
||||||
|
after: JSON.stringify({ domain: instance.customDomain }),
|
||||||
|
hash: 'sha256:' + Math.random().toString(36).slice(2),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
return NextResponse.json({
|
||||||
|
ok: true,
|
||||||
|
verified: true,
|
||||||
|
domain: instance.customDomain,
|
||||||
|
message: `Domain ${instance.customDomain} verifiziert und in Dokploy hinterlegt.`,
|
||||||
|
})
|
||||||
|
} catch (err) {
|
||||||
|
const msg = err instanceof Error ? err.message : 'internal server error'
|
||||||
|
return NextResponse.json({ error: msg }, { status: 500 })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// DELETE /api/aos/instances/[id]/custom-domain
|
||||||
|
// Remove the custom domain (keeps the platform subdomain active).
|
||||||
|
export async function DELETE(_req: Request, { params }: { params: Promise<{ id: string }> }) {
|
||||||
|
try {
|
||||||
|
const { id } = await params
|
||||||
|
const instance = await db.instance.findUnique({ where: { id } })
|
||||||
|
if (!instance) {
|
||||||
|
return NextResponse.json({ error: 'instance not found' }, { status: 404 })
|
||||||
|
}
|
||||||
|
if (!instance.customDomain) {
|
||||||
|
return NextResponse.json({ error: 'no custom domain set' }, { status: 400 })
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove from Dokploy (best-effort)
|
||||||
|
const dokploy = createDokployClientFromEnv()
|
||||||
|
if (dokploy && instance.dokployAppId) {
|
||||||
|
try {
|
||||||
|
// We'd need the domain ID from Dokploy — for now, log the removal
|
||||||
|
await db.instanceEvent.create({
|
||||||
|
data: {
|
||||||
|
instanceId: id,
|
||||||
|
type: 'domain.removed',
|
||||||
|
step: 'domain',
|
||||||
|
result: 'ok',
|
||||||
|
details: JSON.stringify({ domain: instance.customDomain }),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
} catch (e) {
|
||||||
|
// Non-fatal
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
await db.instance.update({
|
||||||
|
where: { id },
|
||||||
|
data: {
|
||||||
|
customDomain: null,
|
||||||
|
domainVerificationToken: null,
|
||||||
|
domainVerifiedAt: null,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
return NextResponse.json({ ok: true, message: 'Custom domain removed' })
|
||||||
|
} catch (err) {
|
||||||
|
const msg = err instanceof Error ? err.message : 'internal server error'
|
||||||
|
return NextResponse.json({ error: msg }, { status: 500 })
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,142 @@
|
|||||||
|
import { NextResponse } from 'next/server'
|
||||||
|
import { db } from '@/lib/db'
|
||||||
|
import { buildGraphCommand, graphPathForInstance } from '@/lib/graphify'
|
||||||
|
|
||||||
|
export const dynamic = 'force-dynamic'
|
||||||
|
export const maxDuration = 600 // 10 min — graph build can take a while
|
||||||
|
|
||||||
|
// POST /api/aos/instances/[id]/graph-build
|
||||||
|
// Triggers a Graphify graph build for this instance's codebase.
|
||||||
|
// Can be called by:
|
||||||
|
// 1. The AOS UI (admin "Graph neu erstellen" button)
|
||||||
|
// 2. An external worker (cron job) that polls for queued graphs
|
||||||
|
// 3. The provisioning hook (fire-and-forget)
|
||||||
|
//
|
||||||
|
// The actual build runs via the Graphify CLI in a subprocess. In production,
|
||||||
|
// this should be delegated to a worker container that has Graphify installed.
|
||||||
|
// For dev/demo: we shell out directly (requires graphify installed on host).
|
||||||
|
export async function POST(req: Request, { params }: { params: Promise<{ id: string }> }) {
|
||||||
|
try {
|
||||||
|
const { id } = await params
|
||||||
|
const instance = await db.instance.findUnique({
|
||||||
|
where: { id },
|
||||||
|
include: { license: true },
|
||||||
|
})
|
||||||
|
if (!instance) {
|
||||||
|
return NextResponse.json({ error: 'instance not found' }, { status: 404 })
|
||||||
|
}
|
||||||
|
if (instance.status === 'deleted' || instance.status === 'deleting') {
|
||||||
|
return NextResponse.json({ error: 'cannot build graph for deleted instance' }, { status: 400 })
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse metadata for git repo info
|
||||||
|
const meta = instance.metadata ? JSON.parse(instance.metadata) as { gitRepo?: string; gitBranch?: string } : {}
|
||||||
|
const gitRepo = meta.gitRepo ?? process.env.INSTANCE_GIT_REPO ?? 'https://github.com/cetinmustafa83/restov1'
|
||||||
|
const gitBranch = meta.gitBranch ?? process.env.INSTANCE_GIT_BRANCH ?? 'main'
|
||||||
|
const graphPath = graphPathForInstance(instance.id)
|
||||||
|
|
||||||
|
await db.instanceEvent.create({
|
||||||
|
data: {
|
||||||
|
instanceId: id,
|
||||||
|
type: 'graphify.build.start',
|
||||||
|
step: 'graphify',
|
||||||
|
result: 'pending',
|
||||||
|
details: JSON.stringify({ gitRepo, gitBranch, graphPath }),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
// If Graphify service is not configured, return the command for an
|
||||||
|
// external worker to execute. This allows the build to be picked up
|
||||||
|
// by a separate worker container.
|
||||||
|
if (!process.env.GRAPHIFY_URL) {
|
||||||
|
const cmd = buildGraphCommand({ gitRepo, gitBranch, outputPath: graphPath })
|
||||||
|
return NextResponse.json({
|
||||||
|
ok: true,
|
||||||
|
status: 'queued',
|
||||||
|
message: 'Graphify service not configured — build command generated for external worker.',
|
||||||
|
graphPath,
|
||||||
|
command: cmd,
|
||||||
|
gitRepo,
|
||||||
|
gitBranch,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Graphify is configured — check if the MCP HTTP service is reachable
|
||||||
|
const { createGraphifyClientFromEnv } = await import('@/lib/graphify')
|
||||||
|
const client = createGraphifyClientFromEnv()
|
||||||
|
if (!client) {
|
||||||
|
return NextResponse.json({ error: 'Graphify client init failed' }, { status: 500 })
|
||||||
|
}
|
||||||
|
|
||||||
|
const health = await client.health()
|
||||||
|
if (!health.ok) {
|
||||||
|
await db.instanceEvent.create({
|
||||||
|
data: {
|
||||||
|
instanceId: id,
|
||||||
|
type: 'graphify.build.error',
|
||||||
|
step: 'graphify',
|
||||||
|
result: 'error',
|
||||||
|
details: JSON.stringify({ error: 'Graphify service unreachable' }),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
return NextResponse.json({
|
||||||
|
ok: false,
|
||||||
|
error: 'Graphify service unreachable',
|
||||||
|
command: buildGraphCommand({ gitRepo, gitBranch, outputPath: graphPath }),
|
||||||
|
}, { status: 503 })
|
||||||
|
}
|
||||||
|
|
||||||
|
// The MCP HTTP service is query-only. The actual build must be done
|
||||||
|
// via the CLI in a worker. We return the command so the caller (or a
|
||||||
|
// cron job) can execute it.
|
||||||
|
const cmd = buildGraphCommand({ gitRepo, gitBranch, outputPath: graphPath })
|
||||||
|
return NextResponse.json({
|
||||||
|
ok: true,
|
||||||
|
status: 'command-ready',
|
||||||
|
message: 'Graphify service is up. Execute the build command in a worker.',
|
||||||
|
graphPath,
|
||||||
|
command: cmd,
|
||||||
|
gitRepo,
|
||||||
|
gitBranch,
|
||||||
|
graphifyVersion: health.version,
|
||||||
|
})
|
||||||
|
} catch (err) {
|
||||||
|
const msg = err instanceof Error ? err.message : 'internal server error'
|
||||||
|
return NextResponse.json({ error: msg }, { status: 500 })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GET — returns the current graph build status for this instance
|
||||||
|
export async function GET(req: Request, { params }: { params: Promise<{ id: string }> }) {
|
||||||
|
try {
|
||||||
|
const { id } = await params
|
||||||
|
const events = await db.instanceEvent.findMany({
|
||||||
|
where: { instanceId: id, type: { startsWith: 'graphify.' } },
|
||||||
|
orderBy: { createdAt: 'desc' },
|
||||||
|
take: 10,
|
||||||
|
})
|
||||||
|
|
||||||
|
const buildStarted = events.some((e) => e.type === 'graphify.build.start' || e.type === 'graphify.build.queued')
|
||||||
|
const buildDone = events.some((e) => e.type === 'graphify.build.ok')
|
||||||
|
const buildFailed = events.some((e) => e.type === 'graphify.build.error')
|
||||||
|
|
||||||
|
let status: 'none' | 'queued' | 'building' | 'ready' | 'failed'
|
||||||
|
if (buildDone) status = 'ready'
|
||||||
|
else if (buildFailed) status = 'failed'
|
||||||
|
else if (buildStarted) status = 'building'
|
||||||
|
else status = 'none'
|
||||||
|
|
||||||
|
return NextResponse.json({
|
||||||
|
status,
|
||||||
|
events: events.map((e) => ({
|
||||||
|
type: e.type,
|
||||||
|
result: e.result,
|
||||||
|
details: e.details,
|
||||||
|
createdAt: e.createdAt,
|
||||||
|
})),
|
||||||
|
})
|
||||||
|
} catch (err) {
|
||||||
|
const msg = err instanceof Error ? err.message : 'internal server error'
|
||||||
|
return NextResponse.json({ error: msg }, { status: 500 })
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,75 @@
|
|||||||
|
import { NextResponse } from 'next/server'
|
||||||
|
import { db } from '@/lib/db'
|
||||||
|
|
||||||
|
export const dynamic = 'force-dynamic'
|
||||||
|
|
||||||
|
// POST /api/aos/instances/[id]/graph-status
|
||||||
|
// Called by the graph build worker after it finishes (success or failure).
|
||||||
|
// Body: { status: 'ok' | 'error', stats?: {...}, error?: '...' }
|
||||||
|
//
|
||||||
|
// This is the callback endpoint that completes the graph build lifecycle:
|
||||||
|
// 1. AOS queues build (graphify.build.queued)
|
||||||
|
// 2. Worker picks up, calls POST /graph-build, gets the command
|
||||||
|
// 3. Worker executes graphify CLI
|
||||||
|
// 4. Worker calls this endpoint to report success/failure
|
||||||
|
// 5. AOS records graphify.build.ok / graphify.build.error
|
||||||
|
export async function POST(req: Request, { params }: { params: Promise<{ id: string }> }) {
|
||||||
|
try {
|
||||||
|
const { id } = await params
|
||||||
|
const body = await req.json().catch(() => ({}))
|
||||||
|
const status = body.status === 'ok' ? 'ok' : 'error'
|
||||||
|
|
||||||
|
const instance = await db.instance.findUnique({ where: { id } })
|
||||||
|
if (!instance) {
|
||||||
|
return NextResponse.json({ error: 'instance not found' }, { status: 404 })
|
||||||
|
}
|
||||||
|
|
||||||
|
if (status === 'ok') {
|
||||||
|
await db.instanceEvent.create({
|
||||||
|
data: {
|
||||||
|
instanceId: id,
|
||||||
|
type: 'graphify.build.ok',
|
||||||
|
step: 'graphify',
|
||||||
|
result: 'ok',
|
||||||
|
details: JSON.stringify({
|
||||||
|
stats: body.stats ?? null,
|
||||||
|
graphPath: body.graphPath ?? null,
|
||||||
|
builtAt: new Date().toISOString(),
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
await db.auditLog.create({
|
||||||
|
data: {
|
||||||
|
actor: 'graphify-worker',
|
||||||
|
action: 'graphify.build.ok',
|
||||||
|
entity: 'Instance',
|
||||||
|
entityId: id,
|
||||||
|
after: JSON.stringify({ stats: body.stats }),
|
||||||
|
hash: 'sha256:' + Math.random().toString(36).slice(2),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
return NextResponse.json({ ok: true, status: 'ok' })
|
||||||
|
} else {
|
||||||
|
await db.instanceEvent.create({
|
||||||
|
data: {
|
||||||
|
instanceId: id,
|
||||||
|
type: 'graphify.build.error',
|
||||||
|
step: 'graphify',
|
||||||
|
result: 'error',
|
||||||
|
details: JSON.stringify({ error: body.error ?? 'unknown build error' }),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
await db.instance.update({
|
||||||
|
where: { id },
|
||||||
|
data: {
|
||||||
|
lastError: `graphify build failed: ${body.error ?? 'unknown'}`,
|
||||||
|
lastErrorAt: new Date(),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
return NextResponse.json({ ok: false, status: 'error', error: body.error })
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
const msg = err instanceof Error ? err.message : 'internal server error'
|
||||||
|
return NextResponse.json({ error: msg }, { status: 500 })
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -184,8 +184,7 @@ export async function DELETE(_req: Request, { params }: { params: Promise<{ id:
|
|||||||
try {
|
try {
|
||||||
const result = await dokploy.teardownInstance({
|
const result = await dokploy.teardownInstance({
|
||||||
dokployAppId: instance.dokployAppId ?? undefined,
|
dokployAppId: instance.dokployAppId ?? undefined,
|
||||||
dokployDbId: instance.dokployDbId ?? undefined,
|
dokployDomainId: meta.dokployDomainId,
|
||||||
dnsDomainId: meta.dokployDomainId,
|
|
||||||
})
|
})
|
||||||
steps.push(...result.steps)
|
steps.push(...result.steps)
|
||||||
await db.instanceEvent.create({
|
await db.instanceEvent.create({
|
||||||
|
|||||||
@@ -88,8 +88,7 @@ export async function POST(req: Request) {
|
|||||||
try {
|
try {
|
||||||
const r = await dokploy.teardownInstance({
|
const r = await dokploy.teardownInstance({
|
||||||
dokployAppId: inst.dokployAppId ?? undefined,
|
dokployAppId: inst.dokployAppId ?? undefined,
|
||||||
dokployDbId: inst.dokployDbId ?? undefined,
|
dokployDomainId: meta.dokployDomainId,
|
||||||
dnsDomainId: meta.dokployDomainId,
|
|
||||||
})
|
})
|
||||||
steps.push(...r.steps)
|
steps.push(...r.steps)
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
|||||||
@@ -158,7 +158,7 @@ export async function POST(req: Request) {
|
|||||||
gitRepo,
|
gitRepo,
|
||||||
gitBranch,
|
gitBranch,
|
||||||
envVars: instanceEnv,
|
envVars: instanceEnv,
|
||||||
databaseName: `${product}_${subdomain}`.replace(/-/g, '_').slice(0, 40),
|
gitProvider: gitRepo.includes('github.com') ? 'github' : 'gitea',
|
||||||
cpuLimit: plan === 'enterprise' ? '2' : plan === 'pro' ? '1' : '0.5',
|
cpuLimit: plan === 'enterprise' ? '2' : plan === 'pro' ? '1' : '0.5',
|
||||||
memoryLimit: plan === 'enterprise' ? '2048m' : plan === 'pro' ? '1024m' : '512m',
|
memoryLimit: plan === 'enterprise' ? '2048m' : plan === 'pro' ? '1024m' : '512m',
|
||||||
}
|
}
|
||||||
@@ -183,8 +183,7 @@ export async function POST(req: Request) {
|
|||||||
result: 'ok',
|
result: 'ok',
|
||||||
details: JSON.stringify({
|
details: JSON.stringify({
|
||||||
appId: result.app.applicationId,
|
appId: result.app.applicationId,
|
||||||
dbId: result.database?.databaseId,
|
domainId: result.domain?.domainId,
|
||||||
domainId: result.domain.domainId,
|
|
||||||
url: result.url,
|
url: result.url,
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
@@ -227,15 +226,11 @@ export async function POST(req: Request) {
|
|||||||
data: {
|
data: {
|
||||||
status: isDemo ? 'demo_active' : 'active',
|
status: isDemo ? 'demo_active' : 'active',
|
||||||
dokployAppId: result.app.applicationId,
|
dokployAppId: result.app.applicationId,
|
||||||
dokployDbId: result.database?.databaseId ?? null,
|
|
||||||
dokployDbName: result.database?.database ?? null,
|
|
||||||
dokployDbUser: result.database?.username ?? null,
|
|
||||||
dokployDbPassword: result.database?.password ?? null,
|
|
||||||
dnsRecordId,
|
dnsRecordId,
|
||||||
metadata: JSON.stringify({
|
metadata: JSON.stringify({
|
||||||
gitRepo,
|
gitRepo,
|
||||||
gitBranch,
|
gitBranch,
|
||||||
dokployDomainId: result.domain.domainId,
|
dokployDomainId: result.domain?.domainId ?? null,
|
||||||
url: result.url,
|
url: result.url,
|
||||||
provisionedAt: now.toISOString(),
|
provisionedAt: now.toISOString(),
|
||||||
}),
|
}),
|
||||||
@@ -258,6 +253,45 @@ export async function POST(req: Request) {
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// --- Generate admin login token (one-time, 7-day expiry) ---
|
||||||
|
// This token allows the client to access their instance admin panel
|
||||||
|
// without separate credentials. Sent via email (if SMTP configured).
|
||||||
|
const crypto = await import('crypto')
|
||||||
|
const adminToken = `admin-${crypto.randomBytes(24).toString('hex')}`
|
||||||
|
const adminTokenExpires = new Date(Date.now() + 7 * 86400000)
|
||||||
|
await db.instance.update({
|
||||||
|
where: { id: instance.id },
|
||||||
|
data: {
|
||||||
|
adminLoginToken: adminToken,
|
||||||
|
adminLoginExpiresAt: adminTokenExpires,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
// --- Graphify: trigger background graph build ---
|
||||||
|
// Builds a knowledge graph from the instance's Git repo so the support
|
||||||
|
// ticket AI can query the codebase later. Fire-and-forget: we don't
|
||||||
|
// await this — it runs in the background and takes 30s-5min depending
|
||||||
|
// on repo size. The graph build job is recorded as an instance event.
|
||||||
|
if (process.env.GRAPHIFY_URL) {
|
||||||
|
import('@/lib/graphify').then(({ graphPathForInstance, buildGraphCommand }) => {
|
||||||
|
const graphPath = graphPathForInstance(instance.id)
|
||||||
|
const cmd = buildGraphCommand({ gitRepo, gitBranch, outputPath: graphPath })
|
||||||
|
db.instanceEvent.create({
|
||||||
|
data: {
|
||||||
|
instanceId: instance.id,
|
||||||
|
type: 'graphify.build.queued',
|
||||||
|
step: 'graphify',
|
||||||
|
result: 'pending',
|
||||||
|
details: JSON.stringify({ graphPath, gitRepo, gitBranch }),
|
||||||
|
},
|
||||||
|
}).then(() => {
|
||||||
|
// In production: enqueue to a worker (BullMQ, Dokploy cron, etc.)
|
||||||
|
// For now: log the command that should be executed.
|
||||||
|
console.log(`[graphify] Instance ${instance.id} graph build queued: ${cmd}`)
|
||||||
|
}).catch(() => {})
|
||||||
|
}).catch(() => {})
|
||||||
|
}
|
||||||
|
|
||||||
await db.auditLog.create({
|
await db.auditLog.create({
|
||||||
data: {
|
data: {
|
||||||
actor: 'admin:ui',
|
actor: 'admin:ui',
|
||||||
@@ -275,12 +309,26 @@ export async function POST(req: Request) {
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// Send instance ready email with admin login link
|
||||||
|
const { sendEmail } = await import('@/lib/email')
|
||||||
|
if (company.email) {
|
||||||
|
const adminLoginUrl = `${result.url}/?admin_token=${adminToken}`
|
||||||
|
sendEmail({
|
||||||
|
to: company.email,
|
||||||
|
subject: `Ihre ${product}-Instanz ist bereit — ${result.url}`,
|
||||||
|
text: `Guten Tag,\n\nIhre Instanz wurde erfolgreich bereitgestellt.\n\nURL: ${result.url}\nAdmin-Login: ${adminLoginUrl}\n${isDemo ? `Demo-Laufzeit: 14 Tage (endet am ${new Date(instance.demoExpiresAt!).toLocaleDateString('de-DE')})` : ''}\n\nMit freundlichen Grüßen\nDFM Solutions`,
|
||||||
|
html: `<p>Guten Tag,</p><p>Ihre <strong>${product}</strong>-Instanz wurde erfolgreich bereitgestellt.</p><p><strong>URL:</strong> <a href="${result.url}">${result.url}</a><br><strong>Admin-Login:</strong> <a href="${adminLoginUrl}">${adminLoginUrl}</a></p>${isDemo ? `<p><strong>Demo-Laufzeit:</strong> 14 Tage (endet am ${new Date(instance.demoExpiresAt!).toLocaleDateString('de-DE')})</p>` : ''}<p>Mit freundlichen Grüßen<br>DFM Solutions</p>`,
|
||||||
|
}).catch(() => {})
|
||||||
|
}
|
||||||
|
|
||||||
return NextResponse.json({
|
return NextResponse.json({
|
||||||
instanceId: instance.id,
|
instanceId: instance.id,
|
||||||
subdomain,
|
subdomain,
|
||||||
url: result.url,
|
url: result.url,
|
||||||
status: isDemo ? 'demo_active' : 'active',
|
status: isDemo ? 'demo_active' : 'active',
|
||||||
demoExpiresAt: instance.demoExpiresAt,
|
demoExpiresAt: instance.demoExpiresAt,
|
||||||
|
adminLoginToken: adminToken,
|
||||||
|
adminLoginUrl: `${result.url}/?admin_token=${adminToken}`,
|
||||||
}, { status: 201 })
|
}, { status: 201 })
|
||||||
} catch (provErr) {
|
} catch (provErr) {
|
||||||
// Provisioning failed — mark as failed, keep the record for retry
|
// Provisioning failed — mark as failed, keep the record for retry
|
||||||
|
|||||||
@@ -304,6 +304,18 @@ export async function POST(req: Request) {
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// Send license key email to the customer
|
||||||
|
const { sendLicenseKeyEmail } = await import('@/lib/email')
|
||||||
|
if (company.email && !parentId) {
|
||||||
|
// Only send for core licenses (not modules)
|
||||||
|
sendLicenseKeyEmail({
|
||||||
|
to: company.email,
|
||||||
|
licenseKey: key,
|
||||||
|
product,
|
||||||
|
plan,
|
||||||
|
}).catch(() => {}) // fire-and-forget, don't block response
|
||||||
|
}
|
||||||
|
|
||||||
return NextResponse.json({ license, pricing: pricing.breakdown }, { status: 201 })
|
return NextResponse.json({ license, pricing: pricing.breakdown }, { status: 201 })
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
const msg = err instanceof Error ? err.message : 'internal server error'
|
const msg = err instanceof Error ? err.message : 'internal server error'
|
||||||
|
|||||||
@@ -0,0 +1,244 @@
|
|||||||
|
import { NextResponse } from 'next/server'
|
||||||
|
import { db } from '@/lib/db'
|
||||||
|
|
||||||
|
export const dynamic = 'force-dynamic'
|
||||||
|
export const maxDuration = 120
|
||||||
|
|
||||||
|
// POST /api/aos/seed-prod
|
||||||
|
// Production-safe seed: requires SEED_ADMIN_KEY header, runs the seed
|
||||||
|
// directly via Prisma (no child_process, no bun dependency).
|
||||||
|
//
|
||||||
|
// This populates the database with demo data + activates all modules so
|
||||||
|
// the AOS UI is fully functional after first deploy.
|
||||||
|
//
|
||||||
|
// Usage:
|
||||||
|
// curl -X POST https://dfmpanel.eu/api/aos/seed-prod \
|
||||||
|
// -H "X-Seed-Key: $SEED_ADMIN_KEY"
|
||||||
|
export async function POST(req: Request) {
|
||||||
|
// Auth: if SEED_ADMIN_KEY is set, require it. If NOT set, allow seeding
|
||||||
|
// only when the database is empty (first-time bootstrap — no auth needed
|
||||||
|
// because there's nothing to protect yet).
|
||||||
|
const seedKey = process.env.SEED_ADMIN_KEY
|
||||||
|
const providedKey = req.headers.get('x-seed-key') ?? new URL(req.url).searchParams.get('key')
|
||||||
|
|
||||||
|
if (seedKey) {
|
||||||
|
// Auth mode: key must match
|
||||||
|
if (providedKey !== seedKey) {
|
||||||
|
return NextResponse.json({ error: 'unauthorized' }, { status: 401 })
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Bootstrap mode: only allowed when DB is empty (companyCount === 0)
|
||||||
|
const { db } = await import('@/lib/db')
|
||||||
|
const companyCount = await db.company.count()
|
||||||
|
if (companyCount > 0) {
|
||||||
|
return NextResponse.json({
|
||||||
|
error: 'SEED_ADMIN_KEY not configured and DB is not empty. Set SEED_ADMIN_KEY env to seed a non-empty database.',
|
||||||
|
companyCount,
|
||||||
|
}, { status: 403 })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const stats: Record<string, number> = {}
|
||||||
|
|
||||||
|
// --- 1. Modules — activate all core modules ---
|
||||||
|
const moduleDefs = [
|
||||||
|
{ id: 'crm', version: '1.0.0', enabled: true, installed: true },
|
||||||
|
{ id: 'leads', version: '1.0.0', enabled: true, installed: true },
|
||||||
|
{ id: 'projects', version: '1.0.0', enabled: true, installed: true },
|
||||||
|
{ id: 'licenses', version: '1.0.0', enabled: true, installed: true },
|
||||||
|
{ id: 'contracts', version: '1.0.0', enabled: true, installed: true },
|
||||||
|
{ id: 'expenses', version: '1.0.0', enabled: true, installed: true },
|
||||||
|
{ id: 'estimates', version: '1.0.0', enabled: true, installed: true },
|
||||||
|
{ id: 'support', version: '1.0.0', enabled: true, installed: true },
|
||||||
|
{ id: 'accounting', version: '1.0.0', enabled: true, installed: true },
|
||||||
|
{ id: 'sales-docs', version: '1.0.0', enabled: true, installed: true },
|
||||||
|
{ id: 'finance', version: '1.0.0', enabled: true, installed: true },
|
||||||
|
{ id: 'reporting', version: '1.0.0', enabled: true, installed: true },
|
||||||
|
]
|
||||||
|
for (const m of moduleDefs) {
|
||||||
|
await db.module.upsert({
|
||||||
|
where: { id: m.id },
|
||||||
|
create: m,
|
||||||
|
update: { enabled: true, installed: true },
|
||||||
|
})
|
||||||
|
}
|
||||||
|
stats.modules = moduleDefs.length
|
||||||
|
|
||||||
|
// --- 2. Settings ---
|
||||||
|
const settings: Record<string, string> = {
|
||||||
|
'company.name': 'DFM Solutions',
|
||||||
|
'company.legalForm': 'GmbH',
|
||||||
|
'company.vatId': 'DE123456789',
|
||||||
|
'company.registerCourt': 'Amtsgericht Hamburg',
|
||||||
|
'company.registerNumber': 'HRB 123456',
|
||||||
|
'company.city': 'Hamburg',
|
||||||
|
'invoice.numberPrefix': 'RE-2026-',
|
||||||
|
'tax.standardBp': '1900',
|
||||||
|
'leadFinder.radiusKm': '50',
|
||||||
|
}
|
||||||
|
for (const [key, value] of Object.entries(settings)) {
|
||||||
|
await db.setting.upsert({ where: { key }, create: { key, value }, update: { value } })
|
||||||
|
}
|
||||||
|
stats.settings = Object.keys(settings).length
|
||||||
|
|
||||||
|
// --- 3. Admin user ---
|
||||||
|
const existingUser = await db.user.findUnique({ where: { email: 'admin@dfmpanel.eu' } })
|
||||||
|
if (!existingUser) {
|
||||||
|
await db.user.create({
|
||||||
|
data: { email: 'admin@dfmpanel.eu', name: 'Max Brandt', role: 'owner' },
|
||||||
|
})
|
||||||
|
stats.users = 1
|
||||||
|
} else {
|
||||||
|
stats.users = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- 4. Companies ---
|
||||||
|
const companies = [
|
||||||
|
{ name: 'Pizzeria RESTO GmbH', legalForm: 'GmbH', vatId: 'DE298765432', website: 'pizzeria-resto.de', email: 'bestellung@pizzeria-resto.de', phone: '+49 40 2280 15', city: 'Hamburg', zip: '22765', street: 'Ottenser Hauptstraße 42', source: 'referral', tags: 'food,restov1,online-bestellung' },
|
||||||
|
{ name: 'Nordwind Logistik GmbH', legalForm: 'GmbH', vatId: 'DE440281115', website: 'nordwind-logistik.de', email: 'info@nordwind-logistik.de', phone: '+49 421 500 88', city: 'Bremen', zip: '28195', street: 'Am Markt 12', source: 'referral', tags: 'logistik,maintenance' },
|
||||||
|
{ name: 'HanseMöbel Manufaktur GmbH', legalForm: 'GmbH', vatId: 'DE118823440', website: 'hansemoebel.de', email: 'verkauf@hansemoebel.de', city: 'Hamburg', zip: '21107', street: 'Stuhlrother Str. 5', source: 'lead-finder', tags: 'shop,woocommerce' },
|
||||||
|
{ name: 'TechStart UG (haftungsbeschränkt)', legalForm: 'UG', vatId: 'DE312045519', website: 'techstart.berlin', email: 'hello@techstart.berlin', city: 'Berlin', zip: '10115', street: 'Torstraße 100', source: 'lead-finder', tags: 'startup,saas' },
|
||||||
|
{ name: 'Atelier Wendland GbR', legalForm: 'GbR', website: 'atelier-wendland.de', email: 'studio@atelier-wendland.de', city: 'Lüneburg', zip: '21335', street: 'Am Sande 4', source: 'manual', tags: 'design,redesign' },
|
||||||
|
]
|
||||||
|
const companyMap: Record<string, string> = {}
|
||||||
|
for (const c of companies) {
|
||||||
|
const existing = await db.company.findFirst({ where: { name: c.name } })
|
||||||
|
if (existing) {
|
||||||
|
companyMap[c.name] = existing.id
|
||||||
|
} else {
|
||||||
|
const created = await db.company.create({ data: c })
|
||||||
|
companyMap[c.name] = created.id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
stats.companies = Object.keys(companyMap).length
|
||||||
|
|
||||||
|
// --- 5. Licenses (restov1 core + modules + demo) ---
|
||||||
|
const crypto = await import('crypto')
|
||||||
|
const sig = () => 'sig_' + crypto.randomBytes(32).toString('hex')
|
||||||
|
|
||||||
|
const existingLicenses = await db.license.count()
|
||||||
|
if (existingLicenses === 0) {
|
||||||
|
// restov1 core (production, pro, 365 days)
|
||||||
|
const core = await db.license.create({
|
||||||
|
data: {
|
||||||
|
key: 'AOS-PRO-RESTO-001-CORE',
|
||||||
|
companyId: companyMap['Pizzeria RESTO GmbH'],
|
||||||
|
product: 'restov1',
|
||||||
|
plan: 'pro',
|
||||||
|
status: 'active',
|
||||||
|
environment: 'production',
|
||||||
|
maxActivations: 2,
|
||||||
|
validUntil: new Date(Date.now() + 365 * 86400000),
|
||||||
|
token: sig(),
|
||||||
|
billingCycle: 'monthly',
|
||||||
|
priceCents: 5000,
|
||||||
|
discountPct: 0,
|
||||||
|
netPriceCents: 5000,
|
||||||
|
noticePeriodDays: 90,
|
||||||
|
trialEndsAt: new Date(Date.now() + 14 * 86400000),
|
||||||
|
subscriptionStartsAt: new Date(Date.now() + 15 * 86400000),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
await db.licenseActivation.create({
|
||||||
|
data: { licenseId: core.id, domain: 'pizzeria-resto.de', environment: 'production', version: '1.0.0' },
|
||||||
|
})
|
||||||
|
|
||||||
|
// restov1 modules
|
||||||
|
const moduleKeys = [
|
||||||
|
{ key: 'AOS-PRO-RESTO-002-MOD-ONLINE', module: 'online-order' },
|
||||||
|
{ key: 'AOS-PRO-RESTO-003-MOD-PAYMENT', module: 'payment' },
|
||||||
|
{ key: 'AOS-PRO-RESTO-004-MOD-RESERV', module: 'reservation' },
|
||||||
|
{ key: 'AOS-PRO-RESTO-005-MOD-DELIVER', module: 'delivery' },
|
||||||
|
]
|
||||||
|
for (const m of moduleKeys) {
|
||||||
|
await db.license.create({
|
||||||
|
data: {
|
||||||
|
key: m.key,
|
||||||
|
companyId: companyMap['Pizzeria RESTO GmbH'],
|
||||||
|
product: 'restov1',
|
||||||
|
plan: 'pro',
|
||||||
|
status: 'active',
|
||||||
|
environment: 'production',
|
||||||
|
module: m.module,
|
||||||
|
parentId: core.id,
|
||||||
|
maxActivations: 2,
|
||||||
|
validUntil: new Date(Date.now() + 365 * 86400000),
|
||||||
|
token: sig(),
|
||||||
|
billingCycle: 'monthly',
|
||||||
|
priceCents: 0,
|
||||||
|
discountPct: 0,
|
||||||
|
netPriceCents: 0,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Demo license
|
||||||
|
const demo = await db.license.create({
|
||||||
|
data: {
|
||||||
|
key: 'AOS-PRO-RESTO-DEMO-001',
|
||||||
|
companyId: companyMap['Atelier Wendland GbR'],
|
||||||
|
product: 'restov1',
|
||||||
|
plan: 'pro',
|
||||||
|
status: 'active',
|
||||||
|
environment: 'demo',
|
||||||
|
maxActivations: 1,
|
||||||
|
validUntil: new Date(Date.now() + 14 * 86400000),
|
||||||
|
token: sig(),
|
||||||
|
billingCycle: 'monthly',
|
||||||
|
priceCents: 5000,
|
||||||
|
discountPct: 0,
|
||||||
|
netPriceCents: 5000,
|
||||||
|
noticePeriodDays: 90,
|
||||||
|
trialEndsAt: new Date(Date.now() + 14 * 86400000),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
await db.licenseActivation.create({
|
||||||
|
data: { licenseId: demo.id, domain: 'demo.pizzeria-resto.de', environment: 'demo', version: '1.0.0-beta' },
|
||||||
|
})
|
||||||
|
|
||||||
|
stats.licenses = 1 + moduleKeys.length + 1
|
||||||
|
} else {
|
||||||
|
stats.licenses = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- 6. API Token (for MCP access) ---
|
||||||
|
const existingTokens = await db.apiToken.count()
|
||||||
|
if (existingTokens === 0) {
|
||||||
|
const adminScopes = ['mcp:read', 'mcp:write', 'crm.company:read', 'crm.deal:read', 'finance.invoice:read', 'leads:read', 'leads:write', 'support:read', 'support:write', 'licenses.license:read', 'licenses.license:write']
|
||||||
|
// Use MCP_API_TOKEN env var if set, otherwise generate a random one
|
||||||
|
const tokenValue = process.env.MCP_API_TOKEN || ('aos_' + crypto.randomUUID())
|
||||||
|
const hash = crypto.createHash('sha256').update(tokenValue).digest('hex')
|
||||||
|
await db.apiToken.create({
|
||||||
|
data: {
|
||||||
|
name: 'MCP Admin Token (seeded)',
|
||||||
|
tokenHash: hash,
|
||||||
|
tokenPrefix: tokenValue.slice(0, 12) + '…',
|
||||||
|
scopes: adminScopes.join(','),
|
||||||
|
expiresAt: null,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
stats.apiTokens = 1
|
||||||
|
stats.mcpToken = tokenValue === process.env.MCP_API_TOKEN ? '(from env)' : tokenValue
|
||||||
|
} else {
|
||||||
|
stats.apiTokens = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- 7. Audit log ---
|
||||||
|
await db.auditLog.create({
|
||||||
|
data: {
|
||||||
|
actor: 'system:seed-prod',
|
||||||
|
action: 'seed-prod.complete',
|
||||||
|
entity: 'System',
|
||||||
|
entityId: 'seed',
|
||||||
|
after: JSON.stringify(stats),
|
||||||
|
hash: 'sha256:' + Math.random().toString(36).slice(2),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
return NextResponse.json({ ok: true, stats, message: 'Production seed complete — all modules activated, demo licenses + companies created.' })
|
||||||
|
} catch (err) {
|
||||||
|
const msg = err instanceof Error ? err.message : 'seed failed'
|
||||||
|
return NextResponse.json({ error: msg, stack: err instanceof Error ? err.stack : undefined }, { status: 500 })
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,62 @@
|
|||||||
|
import { NextResponse } from 'next/server'
|
||||||
|
import { db } from '@/lib/db'
|
||||||
|
import { createCheckoutSession } from '@/lib/stripe'
|
||||||
|
|
||||||
|
export const dynamic = 'force-dynamic'
|
||||||
|
|
||||||
|
// POST /api/aos/stripe/checkout
|
||||||
|
// Creates a Stripe Checkout session for a license subscription.
|
||||||
|
// Body: { licenseId: string }
|
||||||
|
export async function POST(req: Request) {
|
||||||
|
try {
|
||||||
|
const { licenseId } = await req.json()
|
||||||
|
if (!licenseId) {
|
||||||
|
return NextResponse.json({ error: 'licenseId required' }, { status: 400 })
|
||||||
|
}
|
||||||
|
|
||||||
|
const license = await db.license.findUnique({
|
||||||
|
where: { id: licenseId },
|
||||||
|
include: { company: true },
|
||||||
|
})
|
||||||
|
if (!license) {
|
||||||
|
return NextResponse.json({ error: 'license not found' }, { status: 404 })
|
||||||
|
}
|
||||||
|
if (license.parentId) {
|
||||||
|
return NextResponse.json({ error: 'checkout for module licenses not supported — pay for the core license' }, { status: 400 })
|
||||||
|
}
|
||||||
|
if (license.netPriceCents <= 0) {
|
||||||
|
return NextResponse.json({ error: 'this license has no price (free)' }, { status: 400 })
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = await createCheckoutSession({
|
||||||
|
licenseId: license.id,
|
||||||
|
licenseKey: license.key,
|
||||||
|
product: license.product,
|
||||||
|
plan: license.plan,
|
||||||
|
billingCycle: license.billingCycle as 'monthly' | 'yearly',
|
||||||
|
netPriceCents: license.netPriceCents,
|
||||||
|
customerEmail: license.company.email ?? undefined,
|
||||||
|
})
|
||||||
|
|
||||||
|
if ('error' in result) {
|
||||||
|
return NextResponse.json({ error: result.error }, { status: 502 })
|
||||||
|
}
|
||||||
|
|
||||||
|
// Audit
|
||||||
|
await db.auditLog.create({
|
||||||
|
data: {
|
||||||
|
actor: 'client:checkout',
|
||||||
|
action: 'stripe.checkout.created',
|
||||||
|
entity: 'License',
|
||||||
|
entityId: license.id,
|
||||||
|
after: JSON.stringify({ plan: license.plan, cycle: license.billingCycle, netPriceCents: license.netPriceCents }),
|
||||||
|
hash: 'sha256:' + Math.random().toString(36).slice(2),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
return NextResponse.json({ url: result.url })
|
||||||
|
} catch (err) {
|
||||||
|
const msg = err instanceof Error ? err.message : 'internal server error'
|
||||||
|
return NextResponse.json({ error: msg }, { status: 500 })
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,178 @@
|
|||||||
|
import { NextResponse } from 'next/server'
|
||||||
|
import { db } from '@/lib/db'
|
||||||
|
import { constructWebhookEvent } from '@/lib/stripe'
|
||||||
|
import type Stripe from 'stripe'
|
||||||
|
|
||||||
|
export const dynamic = 'force-dynamic'
|
||||||
|
export const maxDuration = 30
|
||||||
|
|
||||||
|
// POST /api/aos/stripe/webhook
|
||||||
|
// Handles Stripe webhook events:
|
||||||
|
// - checkout.session.completed → link Stripe customer + subscription to license
|
||||||
|
// - invoice.paid → activate license (remove trial, set to active)
|
||||||
|
// - customer.subscription.deleted → cancel license (grace → delete)
|
||||||
|
// - invoice.payment_failed → suspend license after dunning
|
||||||
|
export async function POST(req: Request) {
|
||||||
|
const body = await req.text()
|
||||||
|
const signature = req.headers.get('stripe-signature') ?? ''
|
||||||
|
|
||||||
|
const event = constructWebhookEvent(body, signature)
|
||||||
|
if (!event) {
|
||||||
|
return NextResponse.json({ error: 'invalid signature' }, { status: 400 })
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
switch (event.type) {
|
||||||
|
case 'checkout.session.completed': {
|
||||||
|
const session = event.data.object as Stripe.Checkout.Session
|
||||||
|
const licenseId = session.metadata?.licenseId
|
||||||
|
if (!licenseId) break
|
||||||
|
|
||||||
|
// Link Stripe customer + subscription to the license
|
||||||
|
await db.license.update({
|
||||||
|
where: { id: licenseId },
|
||||||
|
data: {
|
||||||
|
stripeCustomerId: session.customer as string,
|
||||||
|
stripeSubscriptionId: session.subscription as string,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
await db.auditLog.create({
|
||||||
|
data: {
|
||||||
|
actor: 'stripe:webhook',
|
||||||
|
action: 'stripe.checkout.completed',
|
||||||
|
entity: 'License',
|
||||||
|
entityId: licenseId,
|
||||||
|
after: JSON.stringify({ customerId: session.customer, subscriptionId: session.subscription }),
|
||||||
|
hash: 'sha256:' + Math.random().toString(36).slice(2),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
case 'invoice.paid': {
|
||||||
|
const invoice = event.data.object as Stripe.Invoice
|
||||||
|
const subscriptionId = (invoice as Stripe.Invoice & { subscription?: string }).subscription
|
||||||
|
if (!subscriptionId) break
|
||||||
|
|
||||||
|
// Find license by Stripe subscription ID and activate it
|
||||||
|
const license = await db.license.findFirst({
|
||||||
|
where: { stripeSubscriptionId: subscriptionId },
|
||||||
|
})
|
||||||
|
if (!license) break
|
||||||
|
|
||||||
|
// If license was in trial, move to active (paid subscription started)
|
||||||
|
if (license.trialEndsAt && new Date(license.trialEndsAt) > new Date()) {
|
||||||
|
await db.license.update({
|
||||||
|
where: { id: license.id },
|
||||||
|
data: {
|
||||||
|
status: 'active',
|
||||||
|
trialEndsAt: null,
|
||||||
|
subscriptionStartsAt: new Date(),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
await db.auditLog.create({
|
||||||
|
data: {
|
||||||
|
actor: 'stripe:webhook',
|
||||||
|
action: 'stripe.invoice.paid',
|
||||||
|
entity: 'License',
|
||||||
|
entityId: license.id,
|
||||||
|
after: JSON.stringify({ invoiceId: invoice.id, amount: invoice.amount_paid }),
|
||||||
|
hash: 'sha256:' + Math.random().toString(36).slice(2),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
case 'customer.subscription.deleted': {
|
||||||
|
const subscription = event.data.object as Stripe.Subscription
|
||||||
|
const license = await db.license.findFirst({
|
||||||
|
where: { stripeSubscriptionId: subscription.id },
|
||||||
|
})
|
||||||
|
if (!license) break
|
||||||
|
|
||||||
|
// Subscription cancelled → license goes to grace, then deletion
|
||||||
|
// (handled by the cleanup cron job)
|
||||||
|
const now = new Date()
|
||||||
|
await db.license.update({
|
||||||
|
where: { id: license.id },
|
||||||
|
data: {
|
||||||
|
status: 'cancelled',
|
||||||
|
cancelledAt: now,
|
||||||
|
cancellationEffectiveAt: new Date(now.getTime() + 7 * 86400000), // 7-day grace
|
||||||
|
cancellationReason: 'Stripe subscription deleted',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
// If there's a linked instance, schedule it for deletion too
|
||||||
|
const instance = await db.instance.findFirst({
|
||||||
|
where: { licenseId: license.id, status: { notIn: ['deleted', 'deleting'] } },
|
||||||
|
})
|
||||||
|
if (instance) {
|
||||||
|
await db.instance.update({
|
||||||
|
where: { id: instance.id },
|
||||||
|
data: {
|
||||||
|
status: 'grace',
|
||||||
|
graceEndsAt: new Date(now.getTime() + 7 * 86400000),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
await db.auditLog.create({
|
||||||
|
data: {
|
||||||
|
actor: 'stripe:webhook',
|
||||||
|
action: 'stripe.subscription.deleted',
|
||||||
|
entity: 'License',
|
||||||
|
entityId: license.id,
|
||||||
|
after: JSON.stringify({ subscriptionId: subscription.id, graceEndsAt: now.getTime() + 7 * 86400000 }),
|
||||||
|
hash: 'sha256:' + Math.random().toString(36).slice(2),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
case 'invoice.payment_failed': {
|
||||||
|
const invoice = event.data.object as Stripe.Invoice
|
||||||
|
const subscriptionId = (invoice as Stripe.Invoice & { subscription?: string }).subscription
|
||||||
|
if (!subscriptionId) break
|
||||||
|
|
||||||
|
const license = await db.license.findFirst({
|
||||||
|
where: { stripeSubscriptionId: subscriptionId },
|
||||||
|
})
|
||||||
|
if (!license) break
|
||||||
|
|
||||||
|
// Payment failed → suspend license (dunning)
|
||||||
|
await db.license.update({
|
||||||
|
where: { id: license.id },
|
||||||
|
data: {
|
||||||
|
status: 'suspended',
|
||||||
|
suspendReason: 'Stripe payment failed',
|
||||||
|
suspendedAt: new Date(),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
await db.auditLog.create({
|
||||||
|
data: {
|
||||||
|
actor: 'stripe:webhook',
|
||||||
|
action: 'stripe.payment.failed',
|
||||||
|
entity: 'License',
|
||||||
|
entityId: license.id,
|
||||||
|
after: JSON.stringify({ invoiceId: invoice.id, attempt: invoice.attempt_count }),
|
||||||
|
hash: 'sha256:' + Math.random().toString(36).slice(2),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
// Unhandled event type — log but don't fail
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
return NextResponse.json({ received: true })
|
||||||
|
} catch (err) {
|
||||||
|
const msg = err instanceof Error ? err.message : 'webhook handler failed'
|
||||||
|
return NextResponse.json({ error: msg }, { status: 500 })
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -23,18 +23,52 @@ export async function POST(
|
|||||||
.map((m) => `[${m.fromType.toUpperCase()}] ${m.fromName} (${new Date(m.createdAt).toLocaleString('de-DE')}):\n${m.body}`)
|
.map((m) => `[${m.fromType.toUpperCase()}] ${m.fromName} (${new Date(m.createdAt).toLocaleString('de-DE')}):\n${m.body}`)
|
||||||
.join('\n\n---\n\n')
|
.join('\n\n---\n\n')
|
||||||
|
|
||||||
|
// --- Graphify codebase context ---
|
||||||
|
// If the ticket belongs to a company that has an instance with a built
|
||||||
|
// graph, query the codebase for relevant code before generating the summary.
|
||||||
|
// This gives the AI context about WHERE the issue is in the code.
|
||||||
|
let codebaseContext = ''
|
||||||
|
if (process.env.GRAPHIFY_URL) {
|
||||||
|
try {
|
||||||
|
const { createGraphifyClientFromEnv, graphPathForInstance } = await import('@/lib/graphify')
|
||||||
|
const graphify = createGraphifyClientFromEnv()
|
||||||
|
if (graphify) {
|
||||||
|
// Find the instance linked to this ticket's company
|
||||||
|
const instance = await db.instance.findFirst({
|
||||||
|
where: { companyId: ticket.companyId, status: { notIn: ['deleted', 'deleting'] } },
|
||||||
|
orderBy: { createdAt: 'desc' },
|
||||||
|
})
|
||||||
|
if (instance) {
|
||||||
|
const graphPath = graphPathForInstance(instance.id)
|
||||||
|
// Query the graph with the ticket subject — "Where is X implemented?"
|
||||||
|
const graphResult = await graphify.queryGraph(ticket.subject, graphPath)
|
||||||
|
if (graphResult.nodes && graphResult.nodes.length > 0) {
|
||||||
|
codebaseContext = `\n\n--- Codebase-Kontext (Graphify) ---\n`
|
||||||
|
+ `Relevante Code-Stellen (Confidence: ${graphResult.confidence}):\n`
|
||||||
|
+ graphResult.nodes.slice(0, 5).map((n) =>
|
||||||
|
`- ${n.label} (${n.type})${n.file ? ` in ${n.file}:${n.line ?? '?'}` : ''}`
|
||||||
|
).join('\n')
|
||||||
|
+ `\n\nAntwort: ${graphResult.answer}`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
// Graphify is optional — if it fails, continue without codebase context
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const systemPrompt = `Du bist ein Support-Assistent für eine deutsche Software-Agentur. Fasse ein Support-Ticket prägnant zusammen (max. 4 Sätze):
|
const systemPrompt = `Du bist ein Support-Assistent für eine deutsche Software-Agentur. Fasse ein Support-Ticket prägnant zusammen (max. 4 Sätze):
|
||||||
1. Was ist das Kernproblem / die Anfrage?
|
1. Was ist das Kernproblem / die Anfrage?
|
||||||
2. Was wurde bisher unternommen?
|
2. Was wurde bisher unternommen?
|
||||||
3. Was ist der aktuelle Status / nächste Schritt?
|
3. Was ist der aktuelle Status / nächste Schritt?
|
||||||
Schreibe auf Deutsch, sachlich, keine Einleitungssätze.`
|
Schreibe auf Deutsch, sachlich, keine Einleitungssätze.${codebaseContext ? '\n\nWenn Codebase-Kontext vorhanden ist, erwähne die relevanten Dateien.' : ''}`
|
||||||
|
|
||||||
const userPrompt = `Ticket: ${ticket.number} — ${ticket.subject}
|
const userPrompt = `Ticket: ${ticket.number} — ${ticket.subject}
|
||||||
Kunde: ${ticket.companyId}
|
Kunde: ${ticket.companyId}
|
||||||
Priorität: ${ticket.priority}
|
Priorität: ${ticket.priority}
|
||||||
|
|
||||||
Verlauf:
|
Verlauf:
|
||||||
${conversation}`
|
${conversation}${codebaseContext}`
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const zai = await ZAI.create()
|
const zai = await ZAI.create()
|
||||||
|
|||||||
@@ -0,0 +1,64 @@
|
|||||||
|
import { NextResponse } from 'next/server'
|
||||||
|
import { z } from 'zod'
|
||||||
|
|
||||||
|
export const dynamic = 'force-dynamic'
|
||||||
|
|
||||||
|
const schema = z.object({
|
||||||
|
password: z.string().min(1),
|
||||||
|
redirect: z.string().optional(),
|
||||||
|
})
|
||||||
|
|
||||||
|
// POST /api/auth/login
|
||||||
|
// Simple password-based auth. Password is set via ADMIN_PASSWORD env var.
|
||||||
|
// Returns a session cookie (HMAC-signed, 7-day expiry).
|
||||||
|
export async function POST(req: Request) {
|
||||||
|
try {
|
||||||
|
const parsed = schema.safeParse(await req.json())
|
||||||
|
if (!parsed.success) {
|
||||||
|
return NextResponse.json({ error: 'invalid request' }, { status: 400 })
|
||||||
|
}
|
||||||
|
const { password, redirect } = parsed.data
|
||||||
|
|
||||||
|
const adminPassword = process.env.ADMIN_PASSWORD
|
||||||
|
if (!adminPassword) {
|
||||||
|
return NextResponse.json(
|
||||||
|
{ error: 'ADMIN_PASSWORD env not configured. Set it in Dokploy environment variables.' },
|
||||||
|
{ status: 503 }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (password !== adminPassword) {
|
||||||
|
return NextResponse.json({ error: 'Falsches Passwort' }, { status: 401 })
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create session token: base64(payload).hmac
|
||||||
|
const crypto = await import('crypto')
|
||||||
|
const payload = {
|
||||||
|
sub: 'admin',
|
||||||
|
iat: Date.now(),
|
||||||
|
exp: Date.now() + 7 * 24 * 3600 * 1000, // 7 days
|
||||||
|
}
|
||||||
|
const payloadB64 = Buffer.from(JSON.stringify(payload)).toString('base64url')
|
||||||
|
const key = process.env.AUTH_SECRET || adminPassword
|
||||||
|
const signature = crypto
|
||||||
|
.createHmac('sha256', key)
|
||||||
|
.update(payloadB64)
|
||||||
|
.digest('base64url')
|
||||||
|
const token = `${payloadB64}.${signature}`
|
||||||
|
|
||||||
|
const res = NextResponse.json({
|
||||||
|
ok: true,
|
||||||
|
redirect: redirect || '/',
|
||||||
|
})
|
||||||
|
res.cookies.set('aos-session', token, {
|
||||||
|
httpOnly: true,
|
||||||
|
secure: process.env.NODE_ENV === 'production',
|
||||||
|
sameSite: 'lax',
|
||||||
|
path: '/',
|
||||||
|
maxAge: 7 * 24 * 3600, // 7 days
|
||||||
|
})
|
||||||
|
return res
|
||||||
|
} catch {
|
||||||
|
return NextResponse.json({ error: 'login failed' }, { status: 500 })
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
import { NextResponse } from 'next/server'
|
||||||
|
|
||||||
|
export const dynamic = 'force-dynamic'
|
||||||
|
|
||||||
|
// POST /api/auth/logout
|
||||||
|
export async function POST() {
|
||||||
|
const res = NextResponse.json({ ok: true })
|
||||||
|
res.cookies.delete('aos-session')
|
||||||
|
return res
|
||||||
|
}
|
||||||
@@ -901,6 +901,107 @@ const TOOLS: McpTool[] = [
|
|||||||
return { number, type: args.type, amountCents: signedAmount, balanceCents: newBalance }
|
return { number, type: args.type, amountCents: signedAmount, balanceCents: newBalance }
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
// --- Graphify tools (tenant codebase intelligence) ---
|
||||||
|
// These tools query the Graphify MCP HTTP service to answer questions about
|
||||||
|
// a tenant instance's codebase. Used by the support ticket AI to find where
|
||||||
|
// a feature is implemented before generating a response.
|
||||||
|
{
|
||||||
|
name: 'query_tenant_codebase',
|
||||||
|
description: 'Query a tenant instance\'s codebase knowledge graph. Use this to find where a feature, function, or module is implemented before answering a support ticket. Returns nodes with file paths and confidence (EXTRACTED = from AST, INFERRED = guessed by LLM).',
|
||||||
|
inputSchema: {
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
instanceId: { type: 'string', description: 'The tenant instance ID (links to a graph.json)' },
|
||||||
|
question: { type: 'string', description: 'Natural language question about the codebase, e.g. "Where is the payment checkout implemented?"' },
|
||||||
|
},
|
||||||
|
required: ['instanceId', 'question'],
|
||||||
|
},
|
||||||
|
requiredScopes: ['support:read', 'mcp:read'],
|
||||||
|
handler: async (args) => {
|
||||||
|
const { createGraphifyClientFromEnv, graphPathForInstance } = await import('@/lib/graphify')
|
||||||
|
const client = createGraphifyClientFromEnv()
|
||||||
|
if (!client) return { error: 'Graphify service not configured (GRAPHIFY_URL missing)' }
|
||||||
|
const graphPath = graphPathForInstance(String(args.instanceId))
|
||||||
|
try {
|
||||||
|
const result = await client.queryGraph(String(args.question), graphPath)
|
||||||
|
return result
|
||||||
|
} catch (e) {
|
||||||
|
return { error: e instanceof Error ? e.message : 'graphify query failed' }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'get_tenant_god_nodes',
|
||||||
|
description: 'Get the "god nodes" (highly-connected hubs) in a tenant\'s codebase. These are functions/modules with many dependencies — likely technical debt or critical architecture points. Useful for code review and refactoring priorities.',
|
||||||
|
inputSchema: {
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
instanceId: { type: 'string', description: 'The tenant instance ID' },
|
||||||
|
},
|
||||||
|
required: ['instanceId'],
|
||||||
|
},
|
||||||
|
requiredScopes: ['support:read', 'mcp:read'],
|
||||||
|
handler: async (args) => {
|
||||||
|
const { createGraphifyClientFromEnv, graphPathForInstance } = await import('@/lib/graphify')
|
||||||
|
const client = createGraphifyClientFromEnv()
|
||||||
|
if (!client) return { error: 'Graphify service not configured' }
|
||||||
|
const graphPath = graphPathForInstance(String(args.instanceId))
|
||||||
|
try {
|
||||||
|
const gods = await client.getGodNodes(graphPath)
|
||||||
|
return { god_nodes: gods, count: gods.length }
|
||||||
|
} catch (e) {
|
||||||
|
return { error: e instanceof Error ? e.message : 'failed' }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'get_tenant_graph_stats',
|
||||||
|
description: 'Get statistics about a tenant\'s codebase knowledge graph: node count, edge count, community count, god node count, and edge confidence breakdown (EXTRACTED vs INFERRED).',
|
||||||
|
inputSchema: {
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
instanceId: { type: 'string', description: 'The tenant instance ID' },
|
||||||
|
},
|
||||||
|
required: ['instanceId'],
|
||||||
|
},
|
||||||
|
requiredScopes: ['support:read', 'mcp:read'],
|
||||||
|
handler: async (args) => {
|
||||||
|
const { createGraphifyClientFromEnv, graphPathForInstance } = await import('@/lib/graphify')
|
||||||
|
const client = createGraphifyClientFromEnv()
|
||||||
|
if (!client) return { error: 'Graphify service not configured' }
|
||||||
|
const graphPath = graphPathForInstance(String(args.instanceId))
|
||||||
|
try {
|
||||||
|
return await client.getGraphStats(graphPath)
|
||||||
|
} catch (e) {
|
||||||
|
return { error: e instanceof Error ? e.message : 'failed' }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'find_code_path',
|
||||||
|
description: 'Find the shortest call path between two functions/modules in a tenant\'s codebase. Useful for understanding how data flows through the application.',
|
||||||
|
inputSchema: {
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
instanceId: { type: 'string', description: 'The tenant instance ID' },
|
||||||
|
source: { type: 'string', description: 'Source node ID or label' },
|
||||||
|
target: { type: 'string', description: 'Target node ID or label' },
|
||||||
|
},
|
||||||
|
required: ['instanceId', 'source', 'target'],
|
||||||
|
},
|
||||||
|
requiredScopes: ['support:read', 'mcp:read'],
|
||||||
|
handler: async (args) => {
|
||||||
|
const { createGraphifyClientFromEnv, graphPathForInstance } = await import('@/lib/graphify')
|
||||||
|
const client = createGraphifyClientFromEnv()
|
||||||
|
if (!client) return { error: 'Graphify service not configured' }
|
||||||
|
const graphPath = graphPathForInstance(String(args.instanceId))
|
||||||
|
try {
|
||||||
|
return await client.shortestPath(String(args.source), String(args.target), graphPath)
|
||||||
|
} catch (e) {
|
||||||
|
return { error: e instanceof Error ? e.message : 'failed' }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
// JSON-RPC handler
|
// JSON-RPC handler
|
||||||
|
|||||||
@@ -0,0 +1,92 @@
|
|||||||
|
'use client'
|
||||||
|
|
||||||
|
import { Suspense, useState } from 'react'
|
||||||
|
import { useRouter, useSearchParams } from 'next/navigation'
|
||||||
|
import { Button } from '@/components/ui/button'
|
||||||
|
import { Input } from '@/components/ui/input'
|
||||||
|
import { Label } from '@/components/ui/label'
|
||||||
|
import { Loader2, Lock } from 'lucide-react'
|
||||||
|
|
||||||
|
function LoginForm() {
|
||||||
|
const router = useRouter()
|
||||||
|
const searchParams = useSearchParams()
|
||||||
|
const redirect = searchParams.get('redirect') || '/'
|
||||||
|
const [password, setPassword] = useState('')
|
||||||
|
const [loading, setLoading] = useState(false)
|
||||||
|
const [error, setError] = useState('')
|
||||||
|
|
||||||
|
const handleSubmit = async (e: React.FormEvent) => {
|
||||||
|
e.preventDefault()
|
||||||
|
if (!password) return
|
||||||
|
setLoading(true)
|
||||||
|
setError('')
|
||||||
|
try {
|
||||||
|
const res = await fetch('/api/auth/login', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: { 'content-type': 'application/json' },
|
||||||
|
body: JSON.stringify({ password, redirect }),
|
||||||
|
})
|
||||||
|
const data = await res.json()
|
||||||
|
if (!res.ok) {
|
||||||
|
setError(data.error || 'Login fehlgeschlagen')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
router.push(data.redirect || '/')
|
||||||
|
router.refresh()
|
||||||
|
} catch {
|
||||||
|
setError('Netzwerkfehler')
|
||||||
|
} finally {
|
||||||
|
setLoading(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<form onSubmit={handleSubmit} className="space-y-4">
|
||||||
|
<div className="space-y-2">
|
||||||
|
<Label htmlFor="password">Passwort</Label>
|
||||||
|
<Input
|
||||||
|
id="password"
|
||||||
|
type="password"
|
||||||
|
value={password}
|
||||||
|
onChange={(e) => setPassword(e.target.value)}
|
||||||
|
placeholder="Admin-Passwort eingeben"
|
||||||
|
autoFocus
|
||||||
|
autoComplete="current-password"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
{error && (
|
||||||
|
<p className="text-sm text-red-600 dark:text-red-400">{error}</p>
|
||||||
|
)}
|
||||||
|
<Button type="submit" className="w-full gap-2" disabled={loading || !password}>
|
||||||
|
{loading && <Loader2 className="size-4 animate-spin" />}
|
||||||
|
Anmelden
|
||||||
|
</Button>
|
||||||
|
</form>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function LoginPage() {
|
||||||
|
return (
|
||||||
|
<div className="flex min-h-screen items-center justify-center bg-background p-4">
|
||||||
|
<div className="w-full max-w-sm space-y-6">
|
||||||
|
<div className="text-center space-y-2">
|
||||||
|
<div className="mx-auto flex size-14 items-center justify-center rounded-xl bg-foreground text-background">
|
||||||
|
<Lock className="size-7" />
|
||||||
|
</div>
|
||||||
|
<h1 className="text-2xl font-semibold tracking-tight">AOS Login</h1>
|
||||||
|
<p className="text-sm text-muted-foreground">
|
||||||
|
Agency Operating System — dfmpanel.eu
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Suspense fallback={<div className="text-center text-sm text-muted-foreground">Laden…</div>}>
|
||||||
|
<LoginForm />
|
||||||
|
</Suspense>
|
||||||
|
|
||||||
|
<p className="text-center text-xs text-muted-foreground">
|
||||||
|
Geschützter Bereich — nur für autorisierte Benutzer.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -19,6 +19,7 @@ import { TimesheetView } from './views/timesheet'
|
|||||||
import { SupportView } from './views/support'
|
import { SupportView } from './views/support'
|
||||||
import { LicensesView } from './views/licenses'
|
import { LicensesView } from './views/licenses'
|
||||||
import { AgencyView } from './views/agency'
|
import { AgencyView } from './views/agency'
|
||||||
|
import { ResellerPortalView } from './views/reseller-portal'
|
||||||
import { InstancesView } from './views/instances'
|
import { InstancesView } from './views/instances'
|
||||||
import { ContractsView } from './views/contracts'
|
import { ContractsView } from './views/contracts'
|
||||||
import { ExpensesView } from './views/expenses'
|
import { ExpensesView } from './views/expenses'
|
||||||
@@ -97,6 +98,7 @@ export function AppShell() {
|
|||||||
{view === 'support' && <SupportView />}
|
{view === 'support' && <SupportView />}
|
||||||
{view === 'licenses' && <LicensesView />}
|
{view === 'licenses' && <LicensesView />}
|
||||||
{view === 'agency' && <AgencyView />}
|
{view === 'agency' && <AgencyView />}
|
||||||
|
{view === 'reseller_portal' && <ResellerPortalView />}
|
||||||
{view === 'instances' && <InstancesView />}
|
{view === 'instances' && <InstancesView />}
|
||||||
{view === 'contracts' && <ContractsView />}
|
{view === 'contracts' && <ContractsView />}
|
||||||
{view === 'expenses' && <ExpensesView />}
|
{view === 'expenses' && <ExpensesView />}
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ import {
|
|||||||
CalendarDays,
|
CalendarDays,
|
||||||
Database,
|
Database,
|
||||||
Server,
|
Server,
|
||||||
|
Store,
|
||||||
} from 'lucide-react'
|
} from 'lucide-react'
|
||||||
import { useAos, type ViewId } from '@/store/aos'
|
import { useAos, type ViewId } from '@/store/aos'
|
||||||
import {
|
import {
|
||||||
@@ -51,6 +52,7 @@ const VIEWS: { id: ViewId; label: string; icon: typeof LayoutDashboard; hint: st
|
|||||||
{ id: 'support', label: 'Support', icon: LifeBuoy, hint: 'Tickets & SLA' },
|
{ id: 'support', label: 'Support', icon: LifeBuoy, hint: 'Tickets & SLA' },
|
||||||
{ id: 'licenses', label: 'Lizenzen', icon: KeyRound, hint: 'Ausgestellt & Erneuerungen' },
|
{ id: 'licenses', label: 'Lizenzen', icon: KeyRound, hint: 'Ausgestellt & Erneuerungen' },
|
||||||
{ id: 'agency', label: 'Reseller', icon: Users, hint: 'Reseller-Bewerbungen & Rabatte' },
|
{ id: 'agency', label: 'Reseller', icon: Users, hint: 'Reseller-Bewerbungen & Rabatte' },
|
||||||
|
{ id: 'reseller_portal', label: 'Reseller-Portal', icon: Store, hint: 'Selbstbedienung: Kunden, Lizenzen, Tickets' },
|
||||||
{ id: 'instances', label: 'Instanzen', icon: Server, hint: 'Tenant-Instanzen & Provisioning' },
|
{ id: 'instances', label: 'Instanzen', icon: Server, hint: 'Tenant-Instanzen & Provisioning' },
|
||||||
{ id: 'contracts', label: 'Verträge', icon: FileSignature, hint: 'Werkvertrag, AVV, NDA' },
|
{ id: 'contracts', label: 'Verträge', icon: FileSignature, hint: 'Werkvertrag, AVV, NDA' },
|
||||||
{ id: 'expenses', label: 'Ausgaben', icon: Wallet, hint: 'Belastbar & DATEV' },
|
{ id: 'expenses', label: 'Ausgaben', icon: Wallet, hint: 'Belastbar & DATEV' },
|
||||||
|
|||||||
@@ -37,10 +37,20 @@ import {
|
|||||||
AlertTriangle,
|
AlertTriangle,
|
||||||
Bell,
|
Bell,
|
||||||
Info,
|
Info,
|
||||||
|
CreditCard,
|
||||||
|
Plus,
|
||||||
|
Ban,
|
||||||
} from 'lucide-react'
|
} from 'lucide-react'
|
||||||
|
import { toast } from 'sonner'
|
||||||
|
import {
|
||||||
|
Select,
|
||||||
|
SelectContent,
|
||||||
|
SelectItem,
|
||||||
|
SelectTrigger,
|
||||||
|
SelectValue,
|
||||||
|
} from '@/components/ui/select'
|
||||||
import { formatEuro, formatDate, formatRelative, daysUntil } from '@/lib/format'
|
import { formatEuro, formatDate, formatRelative, daysUntil } from '@/lib/format'
|
||||||
import { cn } from '@/lib/utils'
|
import { cn } from '@/lib/utils'
|
||||||
import { toast } from 'sonner'
|
|
||||||
import {
|
import {
|
||||||
Popover,
|
Popover,
|
||||||
PopoverContent,
|
PopoverContent,
|
||||||
@@ -94,6 +104,8 @@ interface PortalData {
|
|||||||
licenses: {
|
licenses: {
|
||||||
id: string; key: string; product: string; plan: string; status: string
|
id: string; key: string; product: string; plan: string; status: string
|
||||||
validUntil: string | null; activations: { domain: string; environment: string }[]
|
validUntil: string | null; activations: { domain: string; environment: string }[]
|
||||||
|
netPriceCents: number; billingCycle: string; parentId: string | null
|
||||||
|
trialEndsAt: string | null; noticePeriodDays: number; cancelledAt: string | null
|
||||||
}[]
|
}[]
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -503,6 +515,32 @@ function PortalApprovals({ data, refetch }: { data: PortalData; refetch: () => v
|
|||||||
}
|
}
|
||||||
|
|
||||||
function PortalInvoices({ data }: { data: PortalData }) {
|
function PortalInvoices({ data }: { data: PortalData }) {
|
||||||
|
const [paying, setPaying] = useState<string | null>(null)
|
||||||
|
const companyId = data.company.id
|
||||||
|
|
||||||
|
const pay = async (licenseId: string) => {
|
||||||
|
setPaying(licenseId)
|
||||||
|
const t = toast.loading('Stripe Checkout wird vorbereitet…')
|
||||||
|
try {
|
||||||
|
const r = await fetch('/api/aos/stripe/checkout', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: { 'content-type': 'application/json' },
|
||||||
|
body: JSON.stringify({ licenseId }),
|
||||||
|
})
|
||||||
|
const res = await r.json()
|
||||||
|
if (!r.ok) throw new Error(res.error || 'checkout failed')
|
||||||
|
toast.success('Weiterleitung zu Stripe…', { id: t })
|
||||||
|
window.location.href = res.url
|
||||||
|
} catch (err) {
|
||||||
|
toast.error(err instanceof Error ? err.message : 'Checkout fehlgeschlagen', { id: t })
|
||||||
|
} finally {
|
||||||
|
setPaying(null)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find licenses with a price > 0 that could be paid
|
||||||
|
const payableLicenses = data.licenses.filter((l) => l.netPriceCents > 0 && l.status === 'active' && !l.parentId)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="space-y-4">
|
<div className="space-y-4">
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
@@ -512,6 +550,46 @@ function PortalInvoices({ data }: { data: PortalData }) {
|
|||||||
<p className="text-xs text-muted-foreground">Deine Rechnungen — Ansicht nur für dein Unternehmen.</p>
|
<p className="text-xs text-muted-foreground">Deine Rechnungen — Ansicht nur für dein Unternehmen.</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* Pay subscription */}
|
||||||
|
{payableLicenses.length > 0 && (
|
||||||
|
<Card className="border-foreground/30 bg-foreground/5">
|
||||||
|
<CardContent className="p-4">
|
||||||
|
<div className="flex items-start justify-between gap-3">
|
||||||
|
<div className="flex items-start gap-2">
|
||||||
|
<CreditCard className="mt-0.5 size-4 text-foreground" />
|
||||||
|
<div>
|
||||||
|
<p className="text-sm font-medium">Abonnement bezahlen</p>
|
||||||
|
<p className="text-xs text-muted-foreground">
|
||||||
|
{payableLicenses.length} Lizenz(en) mit offener Zahlung. Klicke auf „Jetzt zahlen", um zur Stripe-Checkout-Seite zu gelangen.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="mt-3 space-y-2">
|
||||||
|
{payableLicenses.map((l) => (
|
||||||
|
<div key={l.id} className="flex items-center justify-between rounded-md border border-border p-2">
|
||||||
|
<div>
|
||||||
|
<p className="text-xs font-medium">{l.product} — {l.plan}</p>
|
||||||
|
<p className="text-[10px] text-muted-foreground">{formatEuro(l.netPriceCents)} / {l.billingCycle === 'yearly' ? 'Jahr' : 'Monat'}</p>
|
||||||
|
</div>
|
||||||
|
<Button
|
||||||
|
size="sm"
|
||||||
|
className="gap-1.5"
|
||||||
|
disabled={paying === l.id}
|
||||||
|
onClick={() => pay(l.id)}
|
||||||
|
>
|
||||||
|
{paying === l.id && <Loader2 className="size-3.5 animate-spin" />}
|
||||||
|
<CreditCard className="size-3.5" />
|
||||||
|
Jetzt zahlen
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
)}
|
||||||
|
|
||||||
<Card>
|
<Card>
|
||||||
<CardContent className="p-0">
|
<CardContent className="p-0">
|
||||||
<div className="overflow-x-auto">
|
<div className="overflow-x-auto">
|
||||||
@@ -557,6 +635,47 @@ function PortalInvoices({ data }: { data: PortalData }) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function PortalTickets({ data }: { data: PortalData }) {
|
function PortalTickets({ data }: { data: PortalData }) {
|
||||||
|
const companyId = data.company.id
|
||||||
|
const [showCreate, setShowCreate] = useState(false)
|
||||||
|
const [subject, setSubject] = useState('')
|
||||||
|
const [category, setCategory] = useState('anfrage')
|
||||||
|
const [priority, setPriority] = useState<'low' | 'normal' | 'high' | 'urgent'>('normal')
|
||||||
|
const [message, setMessage] = useState('')
|
||||||
|
const [creating, setCreating] = useState(false)
|
||||||
|
|
||||||
|
const createTicket = async () => {
|
||||||
|
if (!subject.trim() || !message.trim()) return
|
||||||
|
setCreating(true)
|
||||||
|
const t = toast.loading('Ticket wird erstellt…')
|
||||||
|
try {
|
||||||
|
const r = await fetch('/api/aos/tickets', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: { 'content-type': 'application/json' },
|
||||||
|
body: JSON.stringify({
|
||||||
|
companyId,
|
||||||
|
subject: subject.trim(),
|
||||||
|
categoryId: category,
|
||||||
|
priority,
|
||||||
|
message: message.trim(),
|
||||||
|
fromName: data.company.name,
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
const res = await r.json()
|
||||||
|
if (!r.ok) throw new Error(res.error || 'create failed')
|
||||||
|
toast.success(`Ticket ${res.ticket?.number ?? ''} erstellt`, { id: t })
|
||||||
|
setShowCreate(false)
|
||||||
|
setSubject('')
|
||||||
|
setCategory('anfrage')
|
||||||
|
setPriority('normal')
|
||||||
|
setMessage('')
|
||||||
|
window.location.reload()
|
||||||
|
} catch (err) {
|
||||||
|
toast.error(err instanceof Error ? err.message : 'Erstellung fehlgeschlagen', { id: t })
|
||||||
|
} finally {
|
||||||
|
setCreating(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="space-y-4">
|
<div className="space-y-4">
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
@@ -567,7 +686,9 @@ function PortalTickets({ data }: { data: PortalData }) {
|
|||||||
<p className="text-xs text-muted-foreground">Support-Anfragen und Konversationen.</p>
|
<p className="text-xs text-muted-foreground">Support-Anfragen und Konversationen.</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<Button size="sm"><LifeBuoy className="size-4" />Neues Ticket</Button>
|
<Button size="sm" onClick={() => setShowCreate(true)}>
|
||||||
|
<Plus className="size-4" />Neues Ticket
|
||||||
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
{data.tickets.map((t) => (
|
{data.tickets.map((t) => (
|
||||||
@@ -587,11 +708,94 @@ function PortalTickets({ data }: { data: PortalData }) {
|
|||||||
))}
|
))}
|
||||||
{data.tickets.length === 0 && <p className="py-8 text-center text-xs text-muted-foreground">Keine Tickets.</p>}
|
{data.tickets.length === 0 && <p className="py-8 text-center text-xs text-muted-foreground">Keine Tickets.</p>}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* Create Ticket Dialog */}
|
||||||
|
<Dialog open={showCreate} onOpenChange={setShowCreate}>
|
||||||
|
<DialogContent className="sm:max-w-md">
|
||||||
|
<DialogHeader>
|
||||||
|
<DialogTitle>Neues Ticket</DialogTitle>
|
||||||
|
<DialogDescription>
|
||||||
|
Support-Anfrage erstellen. Dein Ticket wird an den zuständigen Reseller oder DFM Solutions weitergeleitet.
|
||||||
|
</DialogDescription>
|
||||||
|
</DialogHeader>
|
||||||
|
<div className="space-y-4">
|
||||||
|
<div className="space-y-1.5">
|
||||||
|
<Label className="text-xs">Betreff</Label>
|
||||||
|
<Input value={subject} onChange={(e) => setSubject(e.target.value)} placeholder="Kurze Beschreibung des Problems" />
|
||||||
|
</div>
|
||||||
|
<div className="grid grid-cols-2 gap-3">
|
||||||
|
<div className="space-y-1.5">
|
||||||
|
<Label className="text-xs">Kategorie</Label>
|
||||||
|
<Select value={category} onValueChange={setCategory}>
|
||||||
|
<SelectTrigger className="w-full"><SelectValue /></SelectTrigger>
|
||||||
|
<SelectContent>
|
||||||
|
<SelectItem value="anfrage">Anfrage</SelectItem>
|
||||||
|
<SelectItem value="bug">Fehler</SelectItem>
|
||||||
|
<SelectItem value="aenderung">Änderung</SelectItem>
|
||||||
|
<SelectItem value="rechnung">Rechnung</SelectItem>
|
||||||
|
<SelectItem value="konto">Konto</SelectItem>
|
||||||
|
<SelectItem value="hosting">Hosting</SelectItem>
|
||||||
|
</SelectContent>
|
||||||
|
</Select>
|
||||||
|
</div>
|
||||||
|
<div className="space-y-1.5">
|
||||||
|
<Label className="text-xs">Priorität</Label>
|
||||||
|
<Select value={priority} onValueChange={(v) => setPriority(v as 'low' | 'normal' | 'high' | 'urgent')}>
|
||||||
|
<SelectTrigger className="w-full"><SelectValue /></SelectTrigger>
|
||||||
|
<SelectContent>
|
||||||
|
<SelectItem value="low">Niedrig</SelectItem>
|
||||||
|
<SelectItem value="normal">Normal</SelectItem>
|
||||||
|
<SelectItem value="high">Hoch</SelectItem>
|
||||||
|
<SelectItem value="urgent">Dringend</SelectItem>
|
||||||
|
</SelectContent>
|
||||||
|
</Select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="space-y-1.5">
|
||||||
|
<Label className="text-xs">Nachricht</Label>
|
||||||
|
<Textarea value={message} onChange={(e) => setMessage(e.target.value)} placeholder="Beschreibe dein Anliegen…" rows={4} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<DialogFooter>
|
||||||
|
<Button variant="outline" onClick={() => setShowCreate(false)}>Abbrechen</Button>
|
||||||
|
<Button onClick={createTicket} disabled={creating || !subject.trim() || !message.trim()} className="gap-1.5">
|
||||||
|
{creating && <Loader2 className="size-3.5 animate-spin" />}
|
||||||
|
Erstellen
|
||||||
|
</Button>
|
||||||
|
</DialogFooter>
|
||||||
|
</DialogContent>
|
||||||
|
</Dialog>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
function PortalLicenses({ data }: { data: PortalData }) {
|
function PortalLicenses({ data }: { data: PortalData }) {
|
||||||
|
const [cancelling, setCancelling] = useState<string | null>(null)
|
||||||
|
const [showCancel, setShowCancel] = useState<string | null>(null)
|
||||||
|
const [cancelReason, setCancelReason] = useState('')
|
||||||
|
|
||||||
|
const cancelLicense = async (licenseId: string) => {
|
||||||
|
setCancelling(licenseId)
|
||||||
|
const t = toast.loading('Kündigung wird verarbeitet…')
|
||||||
|
try {
|
||||||
|
const r = await fetch(`/api/aos/licenses/${licenseId}/cancel`, {
|
||||||
|
method: 'PATCH',
|
||||||
|
headers: { 'content-type': 'application/json' },
|
||||||
|
body: JSON.stringify({ reason: cancelReason || undefined }),
|
||||||
|
})
|
||||||
|
const res = await r.json()
|
||||||
|
if (!r.ok) throw new Error(res.error || 'cancel failed')
|
||||||
|
toast.success(res.message || 'Lizenz gekündigt', { id: t, duration: 6000 })
|
||||||
|
setShowCancel(null)
|
||||||
|
setCancelReason('')
|
||||||
|
window.location.reload()
|
||||||
|
} catch (err) {
|
||||||
|
toast.error(err instanceof Error ? err.message : 'Kündigung fehlgeschlagen', { id: t })
|
||||||
|
} finally {
|
||||||
|
setCancelling(null)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="space-y-4">
|
<div className="space-y-4">
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
@@ -616,8 +820,52 @@ function PortalLicenses({ data }: { data: PortalData }) {
|
|||||||
{l.validUntil && <p>Gültig bis: {formatDate(l.validUntil)}</p>}
|
{l.validUntil && <p>Gültig bis: {formatDate(l.validUntil)}</p>}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<Badge variant="outline" className="text-[10px] capitalize">{l.status}</Badge>
|
<div className="flex flex-col items-end gap-2">
|
||||||
|
<Badge variant="outline" className="text-[10px] capitalize">{l.status}</Badge>
|
||||||
|
{l.status === 'active' && !l.parentId && !l.cancelledAt && (
|
||||||
|
<Button
|
||||||
|
size="sm"
|
||||||
|
variant="ghost"
|
||||||
|
className="h-7 gap-1 text-[10px] text-muted-foreground hover:text-foreground"
|
||||||
|
onClick={() => setShowCancel(l.id)}
|
||||||
|
>
|
||||||
|
<Ban className="size-3" />
|
||||||
|
Kündigen
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* Cancel dialog */}
|
||||||
|
{showCancel === l.id && (
|
||||||
|
<div className="mt-3 rounded-md border border-foreground/30 bg-foreground/5 p-3">
|
||||||
|
<p className="text-xs font-medium">Lizenz kündigen</p>
|
||||||
|
<p className="mt-1 text-[11px] text-muted-foreground">
|
||||||
|
{l.trialEndsAt && new Date(l.trialEndsAt) > new Date()
|
||||||
|
? 'Du befindest dich in der 14-Tage-Testphase — Kündigung wird sofort wirksam, keine Abbuchung.'
|
||||||
|
: `Kündigungsfrist: ${l.noticePeriodDays ?? 90} Tage. Wirksam zum ${new Date(Date.now() + (l.noticePeriodDays ?? 90) * 86400000).toLocaleDateString('de-DE')}.`}
|
||||||
|
</p>
|
||||||
|
<Input
|
||||||
|
className="mt-2"
|
||||||
|
value={cancelReason}
|
||||||
|
onChange={(e) => setCancelReason(e.target.value)}
|
||||||
|
placeholder="Grund (optional)"
|
||||||
|
/>
|
||||||
|
<div className="mt-2 flex gap-2">
|
||||||
|
<Button size="sm" variant="ghost" onClick={() => { setShowCancel(null); setCancelReason('') }}>Abbrechen</Button>
|
||||||
|
<Button
|
||||||
|
size="sm"
|
||||||
|
variant="destructive"
|
||||||
|
disabled={cancelling === l.id}
|
||||||
|
onClick={() => cancelLicense(l.id)}
|
||||||
|
className="gap-1.5"
|
||||||
|
>
|
||||||
|
{cancelling === l.id && <Loader2 className="size-3.5 animate-spin" />}
|
||||||
|
Kündigung bestätigen
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</Card>
|
</Card>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ import {
|
|||||||
RefreshCw,
|
RefreshCw,
|
||||||
Landmark,
|
Landmark,
|
||||||
Server,
|
Server,
|
||||||
|
Store,
|
||||||
} from 'lucide-react'
|
} from 'lucide-react'
|
||||||
import { useAos, type ViewId } from '@/store/aos'
|
import { useAos, type ViewId } from '@/store/aos'
|
||||||
import { translate } from '@/lib/i18n'
|
import { translate } from '@/lib/i18n'
|
||||||
@@ -69,6 +70,7 @@ const NAV: {
|
|||||||
items: [
|
items: [
|
||||||
{ id: 'licenses', label: 'Lizenzen', icon: KeyRound, permission: 'licenses:read' },
|
{ id: 'licenses', label: 'Lizenzen', icon: KeyRound, permission: 'licenses:read' },
|
||||||
{ id: 'agency', label: 'Reseller', icon: Users, permission: 'admin' },
|
{ id: 'agency', label: 'Reseller', icon: Users, permission: 'admin' },
|
||||||
|
{ id: 'reseller_portal', label: 'Reseller-Portal', icon: Store, permission: 'admin' },
|
||||||
{ id: 'instances', label: 'Instanzen', icon: Server, permission: 'admin' },
|
{ id: 'instances', label: 'Instanzen', icon: Server, permission: 'admin' },
|
||||||
{ id: 'contracts', label: 'Verträge', icon: FileSignature, permission: 'contracts:read' },
|
{ id: 'contracts', label: 'Verträge', icon: FileSignature, permission: 'contracts:read' },
|
||||||
{ id: 'expenses', label: 'Ausgaben', icon: Wallet, permission: 'expenses:read' },
|
{ id: 'expenses', label: 'Ausgaben', icon: Wallet, permission: 'expenses:read' },
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ const TITLES: Record<ViewId, { title: string; crumb: string }> = {
|
|||||||
support: { title: 'Support', crumb: 'Lieferung / Tickets' },
|
support: { title: 'Support', crumb: 'Lieferung / Tickets' },
|
||||||
licenses: { title: 'Lizenzen', crumb: 'Betrieb / Lizenzen' },
|
licenses: { title: 'Lizenzen', crumb: 'Betrieb / Lizenzen' },
|
||||||
agency: { title: 'Reseller', crumb: 'Betrieb / Reseller' },
|
agency: { title: 'Reseller', crumb: 'Betrieb / Reseller' },
|
||||||
|
reseller_portal: { title: 'Reseller-Portal', crumb: 'Betrieb / Reseller-Portal' },
|
||||||
instances: { title: 'Instanzen', crumb: 'Betrieb / Instanzen' },
|
instances: { title: 'Instanzen', crumb: 'Betrieb / Instanzen' },
|
||||||
contracts: { title: 'Verträge', crumb: 'Betrieb / Verträge' },
|
contracts: { title: 'Verträge', crumb: 'Betrieb / Verträge' },
|
||||||
expenses: { title: 'Ausgaben', crumb: 'Betrieb / Ausgaben' },
|
expenses: { title: 'Ausgaben', crumb: 'Betrieb / Ausgaben' },
|
||||||
@@ -110,7 +111,16 @@ export function TopBar() {
|
|||||||
<DropdownMenuItem>Profil</DropdownMenuItem>
|
<DropdownMenuItem>Profil</DropdownMenuItem>
|
||||||
<DropdownMenuItem>Sitzungen</DropdownMenuItem>
|
<DropdownMenuItem>Sitzungen</DropdownMenuItem>
|
||||||
<DropdownMenuSeparator />
|
<DropdownMenuSeparator />
|
||||||
<DropdownMenuItem className="text-muted-foreground">Abmelden</DropdownMenuItem>
|
<DropdownMenuItem
|
||||||
|
className="text-muted-foreground"
|
||||||
|
onSelect={async (e) => {
|
||||||
|
e.preventDefault()
|
||||||
|
await fetch('/api/auth/logout', { method: 'POST' })
|
||||||
|
window.location.href = '/login'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Abmelden
|
||||||
|
</DropdownMenuItem>
|
||||||
</DropdownMenuContent>
|
</DropdownMenuContent>
|
||||||
</DropdownMenu>
|
</DropdownMenu>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ import {
|
|||||||
CheckCircle2,
|
CheckCircle2,
|
||||||
XCircle,
|
XCircle,
|
||||||
CircleDashed,
|
CircleDashed,
|
||||||
|
Network,
|
||||||
} from 'lucide-react'
|
} from 'lucide-react'
|
||||||
import { useFetch } from '@/hooks/use-fetch'
|
import { useFetch } from '@/hooks/use-fetch'
|
||||||
import { Card } from '@/components/ui/card'
|
import { Card } from '@/components/ui/card'
|
||||||
@@ -797,6 +798,63 @@ function InstanceDetailSheet({
|
|||||||
</dl>
|
</dl>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
{/* Codebase Graph (Graphify) */}
|
||||||
|
<section className="space-y-2">
|
||||||
|
<h3 className="text-xs font-semibold uppercase tracking-wider text-muted-foreground">
|
||||||
|
Codebase-Graph (Graphify)
|
||||||
|
</h3>
|
||||||
|
<div className="rounded-md border border-border bg-muted/20 p-3 text-xs">
|
||||||
|
{(() => {
|
||||||
|
const graphEvents = instance.events.filter(
|
||||||
|
(e) => e.type.startsWith('graphify.')
|
||||||
|
)
|
||||||
|
const buildQueued = graphEvents.some(
|
||||||
|
(e) => e.type === 'graphify.build.queued'
|
||||||
|
)
|
||||||
|
const buildDone = graphEvents.some(
|
||||||
|
(e) => e.type === 'graphify.build.ok'
|
||||||
|
)
|
||||||
|
const buildFailed = graphEvents.some(
|
||||||
|
(e) => e.type === 'graphify.build.error'
|
||||||
|
)
|
||||||
|
if (buildDone) {
|
||||||
|
return (
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<CheckCircle2 className="size-3.5 text-foreground" />
|
||||||
|
<span>Graph erstellt — Support-AI kann Codebasis analysieren.</span>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
if (buildFailed) {
|
||||||
|
return (
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<AlertTriangle className="size-3.5 text-muted-foreground" />
|
||||||
|
<span>Graph-Erstellung fehlgeschlagen. Siehe Ereignisverlauf.</span>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
if (buildQueued) {
|
||||||
|
return (
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<Loader2 className="size-3.5 animate-spin text-muted-foreground" />
|
||||||
|
<span>Graph wird im Hintergrund erstellt…</span>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<CircleDashed className="size-3.5 text-muted-foreground" />
|
||||||
|
<span>Kein Graphify-Graph vorhanden.</span>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
})()}
|
||||||
|
<p className="mt-2 text-[10px] text-muted-foreground">
|
||||||
|
Der Codebase-Graph ermöglicht der Support-AI, relevante
|
||||||
|
Code-Stellen zu finden, wenn ein Ticket erstellt wird.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
{/* Status timeline (events) */}
|
{/* Status timeline (events) */}
|
||||||
<section className="space-y-2">
|
<section className="space-y-2">
|
||||||
<h3 className="text-xs font-semibold uppercase tracking-wider text-muted-foreground">
|
<h3 className="text-xs font-semibold uppercase tracking-wider text-muted-foreground">
|
||||||
@@ -841,15 +899,57 @@ function InstanceDetailSheet({
|
|||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<ActionsRow
|
<>
|
||||||
status={status}
|
<ActionsRow
|
||||||
busyAction={busyAction}
|
status={status}
|
||||||
onSuspend={() => handleAction('suspend', 'Suspendieren')}
|
busyAction={busyAction}
|
||||||
onReactivate={() => handleAction('reactivate', 'Reaktivieren')}
|
onSuspend={() => handleAction('suspend', 'Suspendieren')}
|
||||||
onExtend={() => handleAction('extend', 'Demo verlängern', 7)}
|
onReactivate={() => handleAction('reactivate', 'Reaktivieren')}
|
||||||
onRetry={() => handleAction('retry', 'Provisioning wiederholen')}
|
onExtend={() => handleAction('extend', 'Demo verlängern', 7)}
|
||||||
onDelete={() => setConfirmingDelete(true)}
|
onRetry={() => handleAction('retry', 'Provisioning wiederholen')}
|
||||||
/>
|
onDelete={() => setConfirmingDelete(true)}
|
||||||
|
/>
|
||||||
|
{['demo_active', 'active'].includes(status) && (
|
||||||
|
<Button
|
||||||
|
variant="outline"
|
||||||
|
size="sm"
|
||||||
|
className="w-full gap-1.5"
|
||||||
|
disabled={busyAction !== null}
|
||||||
|
onClick={async () => {
|
||||||
|
setBusyAction('graph-build')
|
||||||
|
const t = toast.loading('Graphify-Graph wird erstellt…')
|
||||||
|
try {
|
||||||
|
const r = await fetch(`/api/aos/instances/${instance.id}/graph-build`, { method: 'POST' })
|
||||||
|
const res = await r.json()
|
||||||
|
if (!r.ok) throw new Error(res.error || 'build failed')
|
||||||
|
if (res.status === 'queued') {
|
||||||
|
toast.info('Graphify nicht konfiguriert — Build-Kommando generiert.', {
|
||||||
|
id: t,
|
||||||
|
description: 'Worker muss den Build ausführen.',
|
||||||
|
duration: 6000,
|
||||||
|
})
|
||||||
|
} else if (res.status === 'command-ready') {
|
||||||
|
toast.success('Graphify-Service erreichbar. Build-Kommando bereit.', {
|
||||||
|
id: t,
|
||||||
|
description: 'Worker führt den Build aus.',
|
||||||
|
duration: 6000,
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
toast.success('Graph-Build gestartet', { id: t })
|
||||||
|
}
|
||||||
|
refetch()
|
||||||
|
} catch (err) {
|
||||||
|
toast.error(err instanceof Error ? err.message : 'Build fehlgeschlagen', { id: t })
|
||||||
|
} finally {
|
||||||
|
setBusyAction(null)
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Network className="size-3.5" />
|
||||||
|
Graph neu erstellen
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
)}
|
)}
|
||||||
</section>
|
</section>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
File diff suppressed because it is too large.
Load diff
+204
-183
@@ -1,102 +1,90 @@
|
|||||||
/**
|
/**
|
||||||
* Dokploy API Client
|
* Dokploy API Client (v2 — correct tRPC-based API)
|
||||||
* -------------------
|
* -----------------------------------------------
|
||||||
* Manages tenant instances on the Dokploy server: create applications from
|
* Manages tenant instances on the Dokploy server.
|
||||||
* a Git repo, deploy, attach domains, create databases, suspend/delete.
|
*
|
||||||
|
* API format (verified from @dokploy/mcp source):
|
||||||
|
* - Base URL: {DOKPLOY_URL}/api
|
||||||
|
* - Auth: x-api-key header (NOT Authorization: Bearer)
|
||||||
|
* - Endpoints: /application.create, /application.deploy, /application.delete, etc.
|
||||||
|
* - Application creation is multi-step:
|
||||||
|
* 1. POST /application.create { name, environmentId, sourceType: 'gitea' }
|
||||||
|
* 2. POST /application.saveGiteaProvider { applicationId, giteaOwner, giteaRepository, giteaBranch, giteaBuildPath }
|
||||||
|
* (or saveGitProvider for generic git, saveGithubProvider for github)
|
||||||
|
* 3. POST /application.saveEnvironment { applicationId, env: [...] }
|
||||||
|
* 4. POST /application.deploy { applicationId }
|
||||||
*
|
*
|
||||||
* Config (env):
|
* Config (env):
|
||||||
* DOKPLOY_URL - e.g. https://cp.project-url.eu
|
* DOKPLOY_URL - e.g. https://cp.project-url.eu
|
||||||
* DOKPLOY_API_KEY - bearer token
|
* DOKPLOY_API_KEY - x-api-key value
|
||||||
* DOKPLOY_SERVER_ID - the Dokploy server ID to deploy to (default "default")
|
* DOKPLOY_ENVIRONMENT_ID - the Dokploy environment ID to create apps under
|
||||||
* DOKPLOY_PROJECT_ID - the Dokploy project to put tenant apps under
|
* DOKPLOY_SERVER_ID - (optional) specific server, null = default
|
||||||
*
|
|
||||||
* NOTE: Dokploy API endpoints should be verified against the current API docs
|
|
||||||
* at implementation time. The endpoints below are based on the Dokploy REST API.
|
|
||||||
* See: https://docs.dokploy.com/docs/api
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export interface DokployConfig {
|
export interface DokployConfig {
|
||||||
url: string
|
url: string
|
||||||
apiKey: string
|
apiKey: string
|
||||||
serverId?: string
|
environmentId?: string
|
||||||
projectId?: string
|
serverId?: string | null
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface DokployApp {
|
export interface DokployApp {
|
||||||
applicationId: string
|
applicationId: string
|
||||||
name: string
|
name: string
|
||||||
|
appName?: string
|
||||||
status?: string
|
status?: string
|
||||||
url?: string
|
previewDomain?: string
|
||||||
createdAt?: string
|
createdAt?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface DokployDatabase {
|
|
||||||
databaseId: string
|
|
||||||
name: string
|
|
||||||
type: string // postgres|mysql|redis|...
|
|
||||||
host: string
|
|
||||||
port: number
|
|
||||||
database: string
|
|
||||||
username: string
|
|
||||||
password: string
|
|
||||||
externalUrl?: string
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface DokployDomain {
|
export interface DokployDomain {
|
||||||
domainId: string
|
domainId: string
|
||||||
hostName: string
|
hostName: string
|
||||||
applicationId: string
|
applicationId: string
|
||||||
https: boolean
|
https: boolean
|
||||||
certificateStatus?: string
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ProvisionInstanceInput {
|
export interface ProvisionInstanceInput {
|
||||||
name: string
|
name: string
|
||||||
subdomain: string
|
subdomain: string
|
||||||
gitRepo: string // e.g. https://github.com/cetinmustafa83/restov1
|
gitRepo: string
|
||||||
gitBranch: string // e.g. main
|
gitBranch: string
|
||||||
buildPath?: string // e.g. / (repo root, default)
|
buildPath?: string
|
||||||
envVars: Record<string, string>
|
envVars: Record<string, string>
|
||||||
// Resource limits (Dokploy applies these as container constraints)
|
gitProvider?: 'gitea' | 'github' | 'git' // default: gitea
|
||||||
cpuLimit?: string // e.g. "0.5" = 50% of one core
|
// Resource limits (applied via application.update after creation)
|
||||||
memoryLimit?: string // e.g. "512m"
|
cpuLimit?: string
|
||||||
// Database
|
memoryLimit?: string
|
||||||
databaseName?: string // if set, a Postgres DB is created for this instance
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ProvisionInstanceResult {
|
export interface ProvisionInstanceResult {
|
||||||
app: DokployApp
|
app: DokployApp
|
||||||
database?: DokployDatabase
|
domain?: DokployDomain
|
||||||
domain: DokployDomain
|
|
||||||
url: string
|
url: string
|
||||||
}
|
}
|
||||||
|
|
||||||
class DokployError extends Error {
|
class DokployError extends Error {
|
||||||
constructor(
|
constructor(message: string, public status: number, public endpoint: string, public body?: unknown) {
|
||||||
message: string,
|
|
||||||
public status: number,
|
|
||||||
public endpoint: string,
|
|
||||||
public body?: unknown
|
|
||||||
) {
|
|
||||||
super(message)
|
super(message)
|
||||||
this.name = 'DokployError'
|
this.name = 'DokployError'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function createDokployClient(config: DokployConfig) {
|
export function createDokployClient(config: DokployConfig) {
|
||||||
const baseUrl = config.url.replace(/\/$/, '')
|
const baseUrl = config.url.replace(/\/+$/, '') + '/api'
|
||||||
const serverId = config.serverId ?? 'default'
|
|
||||||
const headers: Record<string, string> = {
|
const headers: Record<string, string> = {
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
Authorization: `Bearer ${config.apiKey}`,
|
Accept: 'application/json',
|
||||||
|
'x-api-key': config.apiKey,
|
||||||
}
|
}
|
||||||
|
|
||||||
async function call<T = unknown>(endpoint: string, body?: Record<string, unknown>, method = 'POST'): Promise<T> {
|
async function call<T = unknown>(path: string, body?: Record<string, unknown>, method = 'POST'): Promise<T> {
|
||||||
const url = `${baseUrl}${endpoint}`
|
const url = `${baseUrl}${path}`
|
||||||
|
const isGet = method === 'GET'
|
||||||
const res = await fetch(url, {
|
const res = await fetch(url, {
|
||||||
method,
|
method,
|
||||||
headers,
|
headers,
|
||||||
body: body ? JSON.stringify(body) : undefined,
|
body: !isGet && body ? JSON.stringify(body) : undefined,
|
||||||
})
|
})
|
||||||
const text = await res.text()
|
const text = await res.text()
|
||||||
let json: unknown
|
let json: unknown
|
||||||
@@ -107,9 +95,9 @@ export function createDokployClient(config: DokployConfig) {
|
|||||||
}
|
}
|
||||||
if (!res.ok) {
|
if (!res.ok) {
|
||||||
throw new DokployError(
|
throw new DokployError(
|
||||||
`Dokploy API ${endpoint} failed: HTTP ${res.status}`,
|
`Dokploy API ${path} failed: HTTP ${res.status}`,
|
||||||
res.status,
|
res.status,
|
||||||
endpoint,
|
path,
|
||||||
json
|
json
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -120,111 +108,130 @@ export function createDokployClient(config: DokployConfig) {
|
|||||||
|
|
||||||
async function createApplication(input: {
|
async function createApplication(input: {
|
||||||
name: string
|
name: string
|
||||||
|
environmentId: string
|
||||||
|
sourceType?: string
|
||||||
|
serverId?: string | null
|
||||||
description?: string
|
description?: string
|
||||||
gitRepo: string
|
|
||||||
gitBranch: string
|
|
||||||
buildPath?: string
|
|
||||||
envVars?: Record<string, string>
|
|
||||||
cpuLimit?: string
|
|
||||||
memoryLimit?: string
|
|
||||||
}): Promise<DokployApp> {
|
}): Promise<DokployApp> {
|
||||||
const body: Record<string, unknown> = {
|
const body: Record<string, unknown> = {
|
||||||
name: input.name,
|
name: input.name,
|
||||||
description: input.description ?? `Tenant instance: ${input.name}`,
|
environmentId: input.environmentId,
|
||||||
serverId,
|
sourceType: input.sourceType ?? 'gitea',
|
||||||
projectName: config.projectId ?? 'default',
|
|
||||||
sourceType: 'git',
|
|
||||||
gitRepository: input.gitRepo,
|
|
||||||
gitBranch: input.gitBranch,
|
|
||||||
buildPath: input.buildPath ?? '/',
|
|
||||||
// Dokploy expects env vars as a JSON string
|
|
||||||
env: JSON.stringify(input.envVars ?? {}),
|
|
||||||
cpuLimit: input.cpuLimit ?? '0.5',
|
|
||||||
memoryLimit: input.memoryLimit ?? '512m',
|
|
||||||
}
|
}
|
||||||
const res = await call<{ applicationId?: string; app?: { applicationId: string }; [k: string]: unknown }>('/api/application.create', body)
|
if (input.serverId) body.serverId = input.serverId
|
||||||
const applicationId = res.applicationId ?? (res.app as { applicationId: string } | undefined)?.applicationId
|
if (input.description) body.description = input.description
|
||||||
|
|
||||||
|
const res = await call<{ applicationId?: string; app?: DokployApp; [k: string]: unknown }>(
|
||||||
|
'/application.create',
|
||||||
|
body
|
||||||
|
)
|
||||||
|
const applicationId = res.applicationId ?? (res.app as DokployApp | undefined)?.applicationId
|
||||||
if (!applicationId) {
|
if (!applicationId) {
|
||||||
throw new DokployError('Dokploy createApplication returned no applicationId', 200, '/api/application.create', res)
|
throw new DokployError('createApplication returned no applicationId', 200, '/application.create', res)
|
||||||
}
|
}
|
||||||
return { applicationId, name: input.name, status: 'created' }
|
return { applicationId, name: input.name, status: 'created' }
|
||||||
}
|
}
|
||||||
|
|
||||||
async function deployApplication(applicationId: string): Promise<{ deployId: string; status: string }> {
|
async function saveGiteaProvider(input: {
|
||||||
const res = await call<{ deployId?: string; jobId?: string; status?: string }>('/api/application.deploy', { applicationId })
|
applicationId: string
|
||||||
return { deployId: res.deployId ?? res.jobId ?? '', status: res.status ?? 'deploying' }
|
giteaOwner: string
|
||||||
|
giteaRepository: string
|
||||||
|
giteaBranch: string
|
||||||
|
giteaBuildPath?: string | null
|
||||||
|
giteaId?: string | null
|
||||||
|
}): Promise<void> {
|
||||||
|
await call('/application.saveGiteaProvider', {
|
||||||
|
applicationId: input.applicationId,
|
||||||
|
giteaOwner: input.giteaOwner,
|
||||||
|
giteaRepository: input.giteaRepository,
|
||||||
|
giteaBranch: input.giteaBranch,
|
||||||
|
giteaBuildPath: input.giteaBuildPath ?? '/',
|
||||||
|
giteaId: input.giteaId ?? null,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getApplication(applicationId: string): Promise<DokployApp & { status?: string; url?: string }> {
|
async function saveGitProvider(input: {
|
||||||
|
applicationId: string
|
||||||
|
gitProviderOwner?: string | null
|
||||||
|
gitProviderRepository?: string | null
|
||||||
|
gitProviderBranch?: string
|
||||||
|
gitProviderBuildPath?: string | null
|
||||||
|
gitProviderId?: string | null
|
||||||
|
}): Promise<void> {
|
||||||
|
await call('/application.saveGitProvider', {
|
||||||
|
applicationId: input.applicationId,
|
||||||
|
gitProviderOwner: input.gitProviderOwner ?? null,
|
||||||
|
gitProviderRepository: input.gitProviderRepository ?? null,
|
||||||
|
gitProviderBranch: input.gitProviderBranch ?? 'main',
|
||||||
|
gitProviderBuildPath: input.gitProviderBuildPath ?? '/',
|
||||||
|
gitProviderId: input.gitProviderId ?? null,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async function saveGithubProvider(input: {
|
||||||
|
applicationId: string
|
||||||
|
githubOwner: string
|
||||||
|
githubRepository: string
|
||||||
|
githubBranch: string
|
||||||
|
githubBuildPath?: string | null
|
||||||
|
githubId?: string | null
|
||||||
|
}): Promise<void> {
|
||||||
|
await call('/application.saveGithubProvider', {
|
||||||
|
applicationId: input.applicationId,
|
||||||
|
githubOwner: input.githubOwner,
|
||||||
|
githubRepository: input.githubRepository,
|
||||||
|
githubBranch: input.githubBranch,
|
||||||
|
githubBuildPath: input.githubBuildPath ?? '/',
|
||||||
|
githubId: input.githubId ?? null,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async function saveEnvironment(applicationId: string, envVars: Record<string, string>): Promise<void> {
|
||||||
|
// Dokploy expects env as array of { key, value } objects OR a JSON string
|
||||||
|
const envArray = Object.entries(envVars).map(([key, value]) => ({ key, value }))
|
||||||
|
await call('/application.saveEnvironment', {
|
||||||
|
applicationId,
|
||||||
|
env: JSON.stringify(envArray),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async function deployApplication(applicationId: string): Promise<{ jobId?: string; status: string }> {
|
||||||
|
const res = await call<{ jobId?: string; deployId?: string; status?: string }>('/application.deploy', {
|
||||||
|
applicationId,
|
||||||
|
})
|
||||||
|
return { jobId: res.jobId ?? res.deployId, status: res.status ?? 'deploying' }
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getApplication(applicationId: string): Promise<DokployApp> {
|
||||||
const res = await call<DokployApp & { applicationStatus?: string; previewDomain?: string }>(
|
const res = await call<DokployApp & { applicationStatus?: string; previewDomain?: string }>(
|
||||||
`/api/application.one`,
|
'/application.one',
|
||||||
{ applicationId },
|
{ applicationId },
|
||||||
|
'GET'
|
||||||
)
|
)
|
||||||
return {
|
return {
|
||||||
applicationId: res.applicationId,
|
applicationId: res.applicationId,
|
||||||
name: res.name,
|
name: res.name,
|
||||||
|
appName: res.appName,
|
||||||
status: res.applicationStatus ?? res.status,
|
status: res.applicationStatus ?? res.status,
|
||||||
url: res.previewDomain ?? res.url,
|
previewDomain: res.previewDomain,
|
||||||
createdAt: res.createdAt,
|
createdAt: res.createdAt,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function deleteApplication(applicationId: string): Promise<void> {
|
async function deleteApplication(applicationId: string): Promise<void> {
|
||||||
await call('/api/application.delete', { applicationId, deleteVolumes: true })
|
await call('/application.delete', { applicationId })
|
||||||
}
|
}
|
||||||
|
|
||||||
async function stopApplication(applicationId: string): Promise<void> {
|
async function stopApplication(applicationId: string): Promise<void> {
|
||||||
await call('/api/application.stop', { applicationId })
|
await call('/application.stop', { applicationId })
|
||||||
}
|
}
|
||||||
|
|
||||||
async function startApplication(applicationId: string): Promise<void> {
|
async function startApplication(applicationId: string): Promise<void> {
|
||||||
await call('/api/application.start', { applicationId })
|
await call('/application.start', { applicationId })
|
||||||
}
|
}
|
||||||
|
|
||||||
async function updateEnv(applicationId: string, envVars: Record<string, string>): Promise<void> {
|
async function redeployApplication(applicationId: string): Promise<void> {
|
||||||
await call('/api/application.update', {
|
await call('/application.redeploy', { applicationId })
|
||||||
applicationId,
|
|
||||||
env: JSON.stringify(envVars),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// --- Databases (Postgres) ---
|
|
||||||
|
|
||||||
async function createPostgresDatabase(input: {
|
|
||||||
name: string
|
|
||||||
appName: string // the application this DB belongs to
|
|
||||||
description?: string
|
|
||||||
externalUrl?: boolean
|
|
||||||
}): Promise<DokployDatabase> {
|
|
||||||
const body: Record<string, unknown> = {
|
|
||||||
name: input.name,
|
|
||||||
appName: input.appName,
|
|
||||||
description: input.description ?? `DB for ${input.appName}`,
|
|
||||||
serverId,
|
|
||||||
projectName: config.projectId ?? 'default',
|
|
||||||
externalUrl: input.externalUrl ?? false,
|
|
||||||
}
|
|
||||||
const res = await call<Record<string, unknown>>('/api/database.postgres.create', body)
|
|
||||||
// The response shape varies between Dokploy versions; handle both.
|
|
||||||
const db = (res.database as Record<string, unknown> | undefined) ?? res
|
|
||||||
const databaseId = (db.databaseId as string | undefined) ?? (res.databaseId as string | undefined)
|
|
||||||
if (!databaseId) {
|
|
||||||
throw new DokployError('Dokploy createDatabase returned no databaseId', 200, '/api/database.postgres.create', res)
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
databaseId,
|
|
||||||
name: (db.name as string | undefined) ?? input.name,
|
|
||||||
type: 'postgres',
|
|
||||||
host: (db.host as string | undefined) ?? 'postgres',
|
|
||||||
port: (db.port as number | undefined) ?? 5432,
|
|
||||||
database: (db.database as string | undefined) ?? input.name,
|
|
||||||
username: (db.username as string | undefined) ?? 'postgres',
|
|
||||||
password: (db.password as string | undefined) ?? '',
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async function deleteDatabase(databaseId: string): Promise<void> {
|
|
||||||
await call('/api/database.postgres.delete', { databaseId })
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- Domains ---
|
// --- Domains ---
|
||||||
@@ -235,20 +242,17 @@ export function createDokployClient(config: DokployConfig) {
|
|||||||
path?: string
|
path?: string
|
||||||
port?: number
|
port?: number
|
||||||
https?: boolean
|
https?: boolean
|
||||||
certificateType?: 'letsencrypt' | 'none'
|
|
||||||
}): Promise<DokployDomain> {
|
}): Promise<DokployDomain> {
|
||||||
const body: Record<string, unknown> = {
|
const res = await call<{ domainId?: string; id?: string }>('/domain.create', {
|
||||||
applicationId: input.applicationId,
|
applicationId: input.applicationId,
|
||||||
hostName: input.hostName,
|
hostName: input.hostName,
|
||||||
path: input.path ?? '/',
|
path: input.path ?? '/',
|
||||||
port: input.port ?? 3000,
|
port: input.port ?? 3000,
|
||||||
https: input.https ?? true,
|
https: input.https ?? true,
|
||||||
certificateType: input.certificateType ?? 'letsencrypt',
|
})
|
||||||
}
|
|
||||||
const res = await call<{ domainId?: string; id?: string; hostName?: string; https?: boolean }>('/api/domain.create', body)
|
|
||||||
const domainId = res.domainId ?? res.id
|
const domainId = res.domainId ?? res.id
|
||||||
if (!domainId) {
|
if (!domainId) {
|
||||||
throw new DokployError('Dokploy createDomain returned no domainId', 200, '/api/domain.create', res)
|
throw new DokployError('createDomain returned no domainId', 200, '/domain.create', res)
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
domainId,
|
domainId,
|
||||||
@@ -259,55 +263,84 @@ export function createDokployClient(config: DokployConfig) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function deleteDomain(domainId: string): Promise<void> {
|
async function deleteDomain(domainId: string): Promise<void> {
|
||||||
await call('/api/domain.delete', { domainId })
|
await call('/domain.delete', { domainId })
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- High-level: provision a full instance ---
|
// --- High-level: provision a full instance ---
|
||||||
|
|
||||||
async function provisionInstance(input: ProvisionInstanceInput): Promise<ProvisionInstanceResult> {
|
async function provisionInstance(input: ProvisionInstanceInput): Promise<ProvisionInstanceResult> {
|
||||||
// 1. Create application from Git repo
|
const environmentId = config.environmentId ?? ''
|
||||||
|
if (!environmentId) {
|
||||||
|
throw new DokployError('DOKPLOY_ENVIRONMENT_ID not configured', 500, 'config')
|
||||||
|
}
|
||||||
|
|
||||||
|
// 1. Create application
|
||||||
const app = await createApplication({
|
const app = await createApplication({
|
||||||
name: input.name,
|
name: input.name,
|
||||||
gitRepo: input.gitRepo,
|
environmentId,
|
||||||
gitBranch: input.gitBranch,
|
sourceType: input.gitProvider ?? 'gitea',
|
||||||
buildPath: '/',
|
serverId: config.serverId,
|
||||||
envVars: input.envVars,
|
description: `Tenant instance: ${input.subdomain}`,
|
||||||
cpuLimit: input.cpuLimit,
|
|
||||||
memoryLimit: input.memoryLimit,
|
|
||||||
})
|
})
|
||||||
|
|
||||||
// 2. (Optional) Create Postgres database
|
// 2. Save Git provider (repo connection)
|
||||||
let database: DokployDatabase | undefined
|
// Parse git repo URL: https://git.dfmpanel.eu/dfmsolutions/AOS.git
|
||||||
if (input.databaseName) {
|
// → owner: dfmsolutions, repo: AOS
|
||||||
database = await createPostgresDatabase({
|
const gitMatch = input.gitRepo.match(/\/([^/]+)\/([^/]+?)(?:\.git)?$/)
|
||||||
name: input.databaseName,
|
const owner = gitMatch?.[1] ?? ''
|
||||||
appName: input.name,
|
const repo = gitMatch?.[2] ?? ''
|
||||||
|
|
||||||
|
if (input.gitProvider === 'github' || input.gitRepo.includes('github.com')) {
|
||||||
|
await saveGithubProvider({
|
||||||
|
applicationId: app.applicationId,
|
||||||
|
githubOwner: owner,
|
||||||
|
githubRepository: repo,
|
||||||
|
githubBranch: input.gitBranch,
|
||||||
|
githubBuildPath: input.buildPath ?? '/',
|
||||||
})
|
})
|
||||||
// Inject DATABASE_URL into the app's env
|
} else if (input.gitProvider === 'gitea' || input.gitRepo.includes('git.dfmpanel.eu')) {
|
||||||
const dbUrl = `postgresql://${database.username}:${database.password}@${database.host}:${database.port}/${database.database}`
|
await saveGiteaProvider({
|
||||||
await updateEnv(app.applicationId, {
|
applicationId: app.applicationId,
|
||||||
...input.envVars,
|
giteaOwner: owner,
|
||||||
DATABASE_URL: dbUrl,
|
giteaRepository: repo,
|
||||||
|
giteaBranch: input.gitBranch,
|
||||||
|
giteaBuildPath: input.buildPath ?? '/',
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
// Generic git
|
||||||
|
await saveGitProvider({
|
||||||
|
applicationId: app.applicationId,
|
||||||
|
gitProviderOwner: owner,
|
||||||
|
gitProviderRepository: repo,
|
||||||
|
gitProviderBranch: input.gitBranch,
|
||||||
|
gitProviderBuildPath: input.buildPath ?? '/',
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3. Attach domain (subdomain.platform-domain)
|
// 3. Save environment variables
|
||||||
const hostName = input.subdomain
|
await saveEnvironment(app.applicationId, input.envVars)
|
||||||
const domain = await createDomain({
|
|
||||||
applicationId: app.applicationId,
|
|
||||||
hostName,
|
|
||||||
port: 3000,
|
|
||||||
https: true,
|
|
||||||
})
|
|
||||||
|
|
||||||
// 4. Trigger deploy
|
// 4. Deploy
|
||||||
await deployApplication(app.applicationId)
|
await deployApplication(app.applicationId)
|
||||||
|
|
||||||
|
// 5. Attach domain (optional — can be done later)
|
||||||
|
let domain: DokployDomain | undefined
|
||||||
|
try {
|
||||||
|
domain = await createDomain({
|
||||||
|
applicationId: app.applicationId,
|
||||||
|
hostName: input.subdomain,
|
||||||
|
port: 3000,
|
||||||
|
https: true,
|
||||||
|
})
|
||||||
|
} catch (e) {
|
||||||
|
// Domain creation is non-fatal — app is already deployed
|
||||||
|
console.warn('[dokploy] Domain creation failed (non-fatal):', e instanceof Error ? e.message : e)
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
app,
|
app,
|
||||||
database,
|
|
||||||
domain,
|
domain,
|
||||||
url: `https://${hostName}`,
|
url: `https://${input.subdomain}`,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -315,14 +348,13 @@ export function createDokployClient(config: DokployConfig) {
|
|||||||
|
|
||||||
async function teardownInstance(input: {
|
async function teardownInstance(input: {
|
||||||
dokployAppId?: string
|
dokployAppId?: string
|
||||||
dokployDbId?: string
|
dokployDomainId?: string
|
||||||
dnsDomainId?: string // Dokploy domain ID
|
|
||||||
}): Promise<{ steps: string[] }> {
|
}): Promise<{ steps: string[] }> {
|
||||||
const steps: string[] = []
|
const steps: string[] = []
|
||||||
// Remove domain first (stop traffic)
|
// Remove domain first (stop traffic)
|
||||||
if (input.dnsDomainId) {
|
if (input.dokployDomainId) {
|
||||||
try {
|
try {
|
||||||
await deleteDomain(input.dnsDomainId)
|
await deleteDomain(input.dokployDomainId)
|
||||||
steps.push('domain.removed')
|
steps.push('domain.removed')
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (e instanceof DokployError && e.status !== 404) {
|
if (e instanceof DokployError && e.status !== 404) {
|
||||||
@@ -330,17 +362,6 @@ export function createDokployClient(config: DokployConfig) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Delete database
|
|
||||||
if (input.dokployDbId) {
|
|
||||||
try {
|
|
||||||
await deleteDatabase(input.dokployDbId)
|
|
||||||
steps.push('database.removed')
|
|
||||||
} catch (e) {
|
|
||||||
if (e instanceof DokployError && e.status !== 404) {
|
|
||||||
steps.push(`database.error: ${e.message}`)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Delete application (+ volumes)
|
// Delete application (+ volumes)
|
||||||
if (input.dokployAppId) {
|
if (input.dokployAppId) {
|
||||||
try {
|
try {
|
||||||
@@ -358,14 +379,16 @@ export function createDokployClient(config: DokployConfig) {
|
|||||||
return {
|
return {
|
||||||
// Low-level
|
// Low-level
|
||||||
createApplication,
|
createApplication,
|
||||||
|
saveGiteaProvider,
|
||||||
|
saveGitProvider,
|
||||||
|
saveGithubProvider,
|
||||||
|
saveEnvironment,
|
||||||
deployApplication,
|
deployApplication,
|
||||||
getApplication,
|
getApplication,
|
||||||
deleteApplication,
|
deleteApplication,
|
||||||
stopApplication,
|
stopApplication,
|
||||||
startApplication,
|
startApplication,
|
||||||
updateEnv,
|
redeployApplication,
|
||||||
createPostgresDatabase,
|
|
||||||
deleteDatabase,
|
|
||||||
createDomain,
|
createDomain,
|
||||||
deleteDomain,
|
deleteDomain,
|
||||||
call,
|
call,
|
||||||
@@ -377,8 +400,6 @@ export function createDokployClient(config: DokployConfig) {
|
|||||||
|
|
||||||
export type DokployClient = ReturnType<typeof createDokployClient>
|
export type DokployClient = ReturnType<typeof createDokployClient>
|
||||||
|
|
||||||
// --- Factory: create from env ---
|
|
||||||
|
|
||||||
export function createDokployClientFromEnv(): DokployClient | null {
|
export function createDokployClientFromEnv(): DokployClient | null {
|
||||||
const url = process.env.DOKPLOY_URL
|
const url = process.env.DOKPLOY_URL
|
||||||
const apiKey = process.env.DOKPLOY_API_KEY
|
const apiKey = process.env.DOKPLOY_API_KEY
|
||||||
@@ -386,7 +407,7 @@ export function createDokployClientFromEnv(): DokployClient | null {
|
|||||||
return createDokployClient({
|
return createDokployClient({
|
||||||
url,
|
url,
|
||||||
apiKey,
|
apiKey,
|
||||||
serverId: process.env.DOKPLOY_SERVER_ID,
|
environmentId: process.env.DOKPLOY_ENVIRONMENT_ID,
|
||||||
projectId: process.env.DOKPLOY_PROJECT_ID,
|
serverId: process.env.DOKPLOY_SERVER_ID ?? null,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,118 @@
|
|||||||
|
import type { Transporter } from 'nodemailer'
|
||||||
|
import nodemailer from 'nodemailer'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Email Client
|
||||||
|
* ------------
|
||||||
|
* Sends transactional emails (agency approval, license key delivery, ticket
|
||||||
|
* notifications, invoice sent).
|
||||||
|
*
|
||||||
|
* Config (env):
|
||||||
|
* MAIL_SMTP_HOST - e.g. smtp.your-server.de
|
||||||
|
* MAIL_SMTP_PORT - 587 (STARTTLS) or 465 (SSL)
|
||||||
|
* MAIL_USER - SMTP username
|
||||||
|
* MAIL_PASSWORD - SMTP password
|
||||||
|
* MAIL_FROM - sender email (e.g. "AOS <noreply@dfmpanel.eu>")
|
||||||
|
*/
|
||||||
|
|
||||||
|
let transporter: Transporter | null = null
|
||||||
|
|
||||||
|
function getTransporter(): Transporter | null {
|
||||||
|
const host = process.env.MAIL_SMTP_HOST
|
||||||
|
const port = process.env.MAIL_SMTP_PORT
|
||||||
|
const user = process.env.MAIL_USER
|
||||||
|
const pass = process.env.MAIL_PASSWORD
|
||||||
|
if (!host || !user || !pass) return null
|
||||||
|
if (!transporter) {
|
||||||
|
transporter = nodemailer.createTransport({
|
||||||
|
host,
|
||||||
|
port: port ? parseInt(port, 10) : 587,
|
||||||
|
secure: parseInt(port ?? '587', 10) === 465,
|
||||||
|
auth: { user, pass },
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return transporter
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface EmailInput {
|
||||||
|
to: string
|
||||||
|
subject: string
|
||||||
|
text?: string
|
||||||
|
html?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function sendEmail(input: EmailInput): Promise<{ ok: boolean; error?: string }> {
|
||||||
|
const t = getTransporter()
|
||||||
|
if (!t) {
|
||||||
|
console.warn('[mail] SMTP not configured — email would have been sent to:', input.to, '| subject:', input.subject)
|
||||||
|
return { ok: false, error: 'SMTP not configured' }
|
||||||
|
}
|
||||||
|
const from = process.env.MAIL_FROM || 'AOS <noreply@dfmpanel.eu>'
|
||||||
|
try {
|
||||||
|
await t.sendMail({
|
||||||
|
from,
|
||||||
|
to: input.to,
|
||||||
|
subject: input.subject,
|
||||||
|
text: input.text || input.html?.replace(/<[^>]*>/g, ''),
|
||||||
|
html: input.html || input.text,
|
||||||
|
})
|
||||||
|
return { ok: true }
|
||||||
|
} catch (err) {
|
||||||
|
return { ok: false, error: err instanceof Error ? err.message : 'send failed' }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- Pre-built email templates ---
|
||||||
|
|
||||||
|
export async function sendAgencyApprovedEmail(input: {
|
||||||
|
to: string
|
||||||
|
companyName: string
|
||||||
|
discountPct: number
|
||||||
|
}): Promise<void> {
|
||||||
|
await sendEmail({
|
||||||
|
to: input.to,
|
||||||
|
subject: `Ihre Reseller-Bewerbung wurde genehmigt — ${input.discountPct}% Rabatt`,
|
||||||
|
text: `Guten Tag,\n\nIhre Bewerbung als Reseller wurde genehmigt.\n\nUnternehmen: ${input.companyName}\nIhr Rabatt: ${input.discountPct}% auf alle Lizenzen\n\nSie können jetzt eigene Kunden anlegen und lizenzieren.\n\nBesuchen Sie: https://dfmpanel.eu\n\nMit freundlichen Grüßen\nDFM Solutions`,
|
||||||
|
html: `<p>Guten Tag,</p><p>Ihre Bewerbung als Reseller wurde <strong>genehmigt</strong>.</p><p><strong>Unternehmen:</strong> ${input.companyName}<br><strong>Ihr Rabatt:</strong> ${input.discountPct}% auf alle Lizenzen</p><p>Sie können jetzt eigene Kunden anlegen und lizenzieren.</p><p><a href="https://dfmpanel.eu">Zum Portal →</a></p><p>Mit freundlichen Grüßen<br>DFM Solutions</p>`,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function sendAgencyRejectedEmail(input: {
|
||||||
|
to: string
|
||||||
|
companyName: string
|
||||||
|
reason: string
|
||||||
|
}): Promise<void> {
|
||||||
|
await sendEmail({
|
||||||
|
to: input.to,
|
||||||
|
subject: 'Ihre Reseller-Bewerbung',
|
||||||
|
text: `Guten Tag,\n\nIhre Bewerbung als Reseller wurde leider abgelehnt.\n\nUnternehmen: ${input.companyName}\nGrund: ${input.reason}\n\nBei Fragen kontaktieren Sie uns unter support@dfmpanel.eu\n\nMit freundlichen Grüßen\nDFM Solutions`,
|
||||||
|
html: `<p>Guten Tag,</p><p>Ihre Bewerbung als Reseller wurde leider <strong>abgelehnt</strong>.</p><p><strong>Unternehmen:</strong> ${input.companyName}<br><strong>Grund:</strong> ${input.reason}</p><p>Bei Fragen kontaktieren Sie uns unter support@dfmpanel.eu</p><p>Mit freundlichen Grüßen<br>DFM Solutions</p>`,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function sendLicenseKeyEmail(input: {
|
||||||
|
to: string
|
||||||
|
licenseKey: string
|
||||||
|
product: string
|
||||||
|
plan: string
|
||||||
|
}): Promise<void> {
|
||||||
|
await sendEmail({
|
||||||
|
to: input.to,
|
||||||
|
subject: `Ihre Lizenz für ${input.product} (${input.plan.toUpperCase()})`,
|
||||||
|
text: `Guten Tag,\n\nIhre Lizenz wurde erstellt.\n\nProdukt: ${input.product}\nPlan: ${input.plan}\nLizenzschlüssel: ${input.licenseKey}\n\nSpeichern Sie den Schlüssel sicher. Sie benötigen ihn zur Aktivierung Ihrer Software.\n\nMit freundlichen Grüßen\nDFM Solutions`,
|
||||||
|
html: `<p>Guten Tag,</p><p>Ihre Lizenz wurde erstellt.</p><p><strong>Produkt:</strong> ${input.product}<br><strong>Plan:</strong> ${input.plan}<br><strong>Lizenzschlüssel:</strong> <code style="font-size: 16px; background: #f0f0f0; padding: 8px; border-radius: 4px;">${input.licenseKey}</code></p><p>Speichern Sie den Schlüssel sicher. Sie benötigen ihn zur Aktivierung Ihrer Software.</p><p>Mit freundlichen Grüßen<br>DFM Solutions</p>`,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function sendTicketCreatedEmail(input: {
|
||||||
|
to: string
|
||||||
|
ticketNumber: string
|
||||||
|
subject: string
|
||||||
|
}): Promise<void> {
|
||||||
|
await sendEmail({
|
||||||
|
to: input.to,
|
||||||
|
subject: `Ticket ${input.ticketNumber} wurde erstellt`,
|
||||||
|
text: `Ihr Support-Ticket wurde erstellt.\n\nTicket: ${input.ticketNumber}\nBetreff: ${input.subject}\n\nWir werden uns so schnell wie möglich um Ihr Anliegen kümmern.\n\nMit freundlichen Grüßen\nDFM Solutions`,
|
||||||
|
html: `<p>Ihr Support-Ticket wurde erstellt.</p><p><strong>Ticket:</strong> ${input.ticketNumber}<br><strong>Betreff:</strong> ${input.subject}</p><p>Wir werden uns so schnell wie möglich um Ihr Anliegen kümmern.</p>`,
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -0,0 +1,233 @@
|
|||||||
|
/**
|
||||||
|
* Graphify Client
|
||||||
|
* ----------------
|
||||||
|
* Talks to the Graphify MCP HTTP service (Docker container) to:
|
||||||
|
* 1. Build/refresh a knowledge graph from a Git repo (per tenant instance)
|
||||||
|
* 2. Query the graph (codebase search, god nodes, shortest path, etc.)
|
||||||
|
*
|
||||||
|
* Graphify is a local-first knowledge-graph builder for code. It parses
|
||||||
|
* 40+ languages with tree-sitter (deterministic, no LLM) and produces a
|
||||||
|
* traversable graph.json. The MCP HTTP service exposes 7 query tools.
|
||||||
|
*
|
||||||
|
* Config (env):
|
||||||
|
* GRAPHIFY_URL - e.g. http://localhost:8080 (Docker container)
|
||||||
|
* GRAPHIFY_API_KEY - shared secret (--api-key on the Graphify server)
|
||||||
|
*
|
||||||
|
* Per-tenant graphs are stored at: /data/graphify/{instanceId}/graph.json
|
||||||
|
*/
|
||||||
|
|
||||||
|
export interface GraphifyConfig {
|
||||||
|
url: string
|
||||||
|
apiKey?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface GraphStats {
|
||||||
|
node_count: number
|
||||||
|
edge_count: number
|
||||||
|
community_count: number
|
||||||
|
god_nodes: number
|
||||||
|
extracted_edges: number
|
||||||
|
inferred_edges: number
|
||||||
|
ambiguous_edges: number
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface GraphNode {
|
||||||
|
id: string
|
||||||
|
label: string
|
||||||
|
type: string
|
||||||
|
file?: string
|
||||||
|
line?: number
|
||||||
|
community?: number
|
||||||
|
is_god_node?: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface GraphQueryResult {
|
||||||
|
answer: string
|
||||||
|
nodes: GraphNode[]
|
||||||
|
confidence: 'EXTRACTED' | 'INFERRED' | 'AMBIGUOUS' | 'NONE'
|
||||||
|
path?: string[]
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface GodNode {
|
||||||
|
id: string
|
||||||
|
label: string
|
||||||
|
type: string
|
||||||
|
in_degree: number
|
||||||
|
out_degree: number
|
||||||
|
file?: string
|
||||||
|
community?: number
|
||||||
|
}
|
||||||
|
|
||||||
|
class GraphifyError extends Error {
|
||||||
|
constructor(message: string, public status: number, public body?: unknown) {
|
||||||
|
super(message)
|
||||||
|
this.name = 'GraphifyError'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function createGraphifyClient(config: GraphifyConfig) {
|
||||||
|
const baseUrl = config.url.replace(/\/$/, '')
|
||||||
|
const headers: Record<string, string> = {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
}
|
||||||
|
if (config.apiKey) {
|
||||||
|
headers['Authorization'] = `Bearer ${config.apiKey}`
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- MCP JSON-RPC call ---
|
||||||
|
async function mcpCall<T = unknown>(tool: string, args: Record<string, unknown> = {}): Promise<T> {
|
||||||
|
const res = await fetch(`${baseUrl}/mcp`, {
|
||||||
|
method: 'POST',
|
||||||
|
headers,
|
||||||
|
body: JSON.stringify({
|
||||||
|
jsonrpc: '2.0',
|
||||||
|
method: 'tools/call',
|
||||||
|
params: { name: tool, arguments: args },
|
||||||
|
id: Date.now(),
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
const text = await res.text()
|
||||||
|
let json: unknown
|
||||||
|
try {
|
||||||
|
json = text ? JSON.parse(text) : null
|
||||||
|
} catch {
|
||||||
|
json = text
|
||||||
|
}
|
||||||
|
if (!res.ok) {
|
||||||
|
throw new GraphifyError(
|
||||||
|
`Graphify MCP ${tool} failed: HTTP ${res.status}`,
|
||||||
|
res.status,
|
||||||
|
json
|
||||||
|
)
|
||||||
|
}
|
||||||
|
// MCP response: { result: { content: [{ type: 'text', text: '...' }] } }
|
||||||
|
const result = (json as { result?: { content?: { type: string; text: string }[] } })?.result
|
||||||
|
if (!result) return json as T
|
||||||
|
const textContent = result.content?.find((c) => c.type === 'text')?.text
|
||||||
|
if (!textContent) return json as T
|
||||||
|
try {
|
||||||
|
return JSON.parse(textContent) as T
|
||||||
|
} catch {
|
||||||
|
return textContent as unknown as T
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- Graph build (CLI invocation via HTTP trigger if supported) ---
|
||||||
|
// Note: Graphify's MCP server is read-only (query tools). To BUILD a graph,
|
||||||
|
// we either:
|
||||||
|
// a) Shell out to `graphify extract` + `graphify build` in a worker process
|
||||||
|
// b) Call a custom build endpoint (if the Docker image exposes one)
|
||||||
|
// Here we provide a high-level function that the provisioning hook calls.
|
||||||
|
// The actual build is done via a sidecar job (see instance provisioning route).
|
||||||
|
|
||||||
|
// --- Query tools (read-only, exposed by Graphify MCP) ---
|
||||||
|
|
||||||
|
async function queryGraph(question: string, graphPath?: string): Promise<GraphQueryResult> {
|
||||||
|
const args: Record<string, unknown> = { question }
|
||||||
|
if (graphPath) args.graph_path = graphPath
|
||||||
|
return mcpCall<GraphQueryResult>('query_graph', args)
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getNode(nodeId: string, graphPath?: string): Promise<GraphNode> {
|
||||||
|
const args: Record<string, unknown> = { node_id: nodeId }
|
||||||
|
if (graphPath) args.graph_path = graphPath
|
||||||
|
return mcpCall<GraphNode>('get_node', args)
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getNeighbors(nodeId: string, graphPath?: string): Promise<GraphNode[]> {
|
||||||
|
const args: Record<string, unknown> = { node_id: nodeId }
|
||||||
|
if (graphPath) args.graph_path = graphPath
|
||||||
|
return mcpCall<GraphNode[]>('get_neighbors', args)
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getCommunity(communityId: number, graphPath?: string): Promise<{
|
||||||
|
id: number
|
||||||
|
label: string
|
||||||
|
nodes: GraphNode[]
|
||||||
|
}> {
|
||||||
|
const args: Record<string, unknown> = { community_id: communityId }
|
||||||
|
if (graphPath) args.graph_path = graphPath
|
||||||
|
return mcpCall('get_community', args)
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getGodNodes(graphPath?: string): Promise<GodNode[]> {
|
||||||
|
const args: Record<string, unknown> = {}
|
||||||
|
if (graphPath) args.graph_path = graphPath
|
||||||
|
return mcpCall<GodNode[]>('god_nodes', args)
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getGraphStats(graphPath?: string): Promise<GraphStats> {
|
||||||
|
const args: Record<string, unknown> = {}
|
||||||
|
if (graphPath) args.graph_path = graphPath
|
||||||
|
return mcpCall<GraphStats>('graph_stats', args)
|
||||||
|
}
|
||||||
|
|
||||||
|
async function shortestPath(sourceId: string, targetId: string, graphPath?: string): Promise<{
|
||||||
|
path: string[]
|
||||||
|
length: number
|
||||||
|
found: boolean
|
||||||
|
}> {
|
||||||
|
const args: Record<string, unknown> = { source: sourceId, target: targetId }
|
||||||
|
if (graphPath) args.graph_path = graphPath
|
||||||
|
return mcpCall('shortest_path', args)
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- Health check ---
|
||||||
|
async function health(): Promise<{ ok: boolean; version?: string }> {
|
||||||
|
try {
|
||||||
|
const res = await fetch(`${baseUrl}/health`, { headers, signal: AbortSignal.timeout(5000) })
|
||||||
|
if (!res.ok) return { ok: false }
|
||||||
|
const data = await res.json().catch(() => ({ ok: true }))
|
||||||
|
return { ok: true, version: (data as { version?: string }).version }
|
||||||
|
} catch {
|
||||||
|
return { ok: false }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
mcpCall,
|
||||||
|
queryGraph,
|
||||||
|
getNode,
|
||||||
|
getNeighbors,
|
||||||
|
getCommunity,
|
||||||
|
getGodNodes,
|
||||||
|
getGraphStats,
|
||||||
|
shortestPath,
|
||||||
|
health,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export type GraphifyClient = ReturnType<typeof createGraphifyClient>
|
||||||
|
|
||||||
|
export function createGraphifyClientFromEnv(): GraphifyClient | null {
|
||||||
|
const url = process.env.GRAPHIFY_URL
|
||||||
|
if (!url) return null
|
||||||
|
return createGraphifyClient({
|
||||||
|
url,
|
||||||
|
apiKey: process.env.GRAPHIFY_API_KEY,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- Helper: graph path per instance ---
|
||||||
|
// Each tenant's graph is stored at /data/graphify/{instanceId}/graph.json
|
||||||
|
export function graphPathForInstance(instanceId: string): string {
|
||||||
|
return `/data/graphify/${instanceId}/graph.json`
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- Helper: build graph from a Git repo ---
|
||||||
|
// This is a high-level function that triggers a graph build via the Graphify
|
||||||
|
// CLI. In production, this would be a background job (e.g. via a queue or
|
||||||
|
// Dokploy cron). Here we provide the command that should be executed.
|
||||||
|
export function buildGraphCommand(input: {
|
||||||
|
gitRepo: string
|
||||||
|
gitBranch: string
|
||||||
|
outputPath: string // /data/graphify/{instanceId}/graph.json
|
||||||
|
}): string {
|
||||||
|
return [
|
||||||
|
`git clone --depth 1 -b ${input.gitBranch} ${input.gitRepo} /tmp/repo`,
|
||||||
|
`&& graphify extract /tmp/repo --output ${input.outputPath}`,
|
||||||
|
`&& graphify build ${input.outputPath} --update`,
|
||||||
|
`&& graphify cluster ${input.outputPath}`,
|
||||||
|
`&& rm -rf /tmp/repo`,
|
||||||
|
].join(' ')
|
||||||
|
}
|
||||||
@@ -29,6 +29,7 @@ const de: Dict = {
|
|||||||
'nav.support': 'Support',
|
'nav.support': 'Support',
|
||||||
'nav.licenses': 'Lizenzen',
|
'nav.licenses': 'Lizenzen',
|
||||||
'nav.agency': 'Reseller',
|
'nav.agency': 'Reseller',
|
||||||
|
'nav.reseller_portal': 'Reseller-Portal',
|
||||||
'nav.instances': 'Instanzen',
|
'nav.instances': 'Instanzen',
|
||||||
'nav.contracts': 'Verträge',
|
'nav.contracts': 'Verträge',
|
||||||
'nav.expenses': 'Ausgaben',
|
'nav.expenses': 'Ausgaben',
|
||||||
@@ -87,6 +88,7 @@ const en: Dict = {
|
|||||||
'nav.support': 'Support',
|
'nav.support': 'Support',
|
||||||
'nav.licenses': 'Licenses',
|
'nav.licenses': 'Licenses',
|
||||||
'nav.agency': 'Reseller',
|
'nav.agency': 'Reseller',
|
||||||
|
'nav.reseller_portal': 'Reseller Portal',
|
||||||
'nav.instances': 'Instances',
|
'nav.instances': 'Instances',
|
||||||
'nav.contracts': 'Contracts',
|
'nav.contracts': 'Contracts',
|
||||||
'nav.expenses': 'Expenses',
|
'nav.expenses': 'Expenses',
|
||||||
@@ -141,6 +143,7 @@ const tr: Dict = {
|
|||||||
'nav.support': 'Destek',
|
'nav.support': 'Destek',
|
||||||
'nav.licenses': 'Lisanslar',
|
'nav.licenses': 'Lisanslar',
|
||||||
'nav.agency': 'Bayi',
|
'nav.agency': 'Bayi',
|
||||||
|
'nav.reseller_portal': 'Bayi Portal',
|
||||||
'nav.instances': 'Sunucular',
|
'nav.instances': 'Sunucular',
|
||||||
'nav.contracts': 'Sözleşmeler',
|
'nav.contracts': 'Sözleşmeler',
|
||||||
'nav.expenses': 'Giderler',
|
'nav.expenses': 'Giderler',
|
||||||
|
|||||||
@@ -0,0 +1,119 @@
|
|||||||
|
import Stripe from 'stripe'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stripe Client
|
||||||
|
* --------------
|
||||||
|
* Creates Stripe checkout sessions for license subscriptions and handles
|
||||||
|
* webhook events (invoice.paid, subscription lifecycle).
|
||||||
|
*
|
||||||
|
* Config (env):
|
||||||
|
* STRIPE_SECRET_KEY - sk_test_... or sk_live_...
|
||||||
|
* STRIPE_WEBHOOK_SECRET - whsec_... (for webhook verification)
|
||||||
|
* STRIPE_PUBLISHABLE_KEY - pk_test_... or pk_live_... (client-side)
|
||||||
|
* AOS_PUBLIC_URL - base URL for success/cancel redirects
|
||||||
|
*/
|
||||||
|
|
||||||
|
let stripeInstance: Stripe | null = null
|
||||||
|
|
||||||
|
export function getStripe(): Stripe | null {
|
||||||
|
const key = process.env.STRIPE_SECRET_KEY
|
||||||
|
if (!key) return null
|
||||||
|
if (!stripeInstance) {
|
||||||
|
stripeInstance = new Stripe(key, {
|
||||||
|
apiVersion: '2025-10-28.acacia' as Stripe.LatestApiVersion,
|
||||||
|
typescript: true,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return stripeInstance
|
||||||
|
}
|
||||||
|
|
||||||
|
// Plan → Stripe Price mapping (create these prices in Stripe dashboard)
|
||||||
|
// If STRIPE_PRICE_STARTER, STRIPE_PRICE_PRO, STRIPE_PRICE_ENTERPRISE env
|
||||||
|
// vars are set, they override these defaults.
|
||||||
|
const PLAN_PRICES: Record<string, string> = {
|
||||||
|
starter: process.env.STRIPE_PRICE_STARTER ?? '',
|
||||||
|
pro: process.env.STRIPE_PRICE_PRO ?? '',
|
||||||
|
enterprise: process.env.STRIPE_PRICE_ENTERPRISE ?? '',
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getStripePriceId(plan: string, cycle: 'monthly' | 'yearly'): string | null {
|
||||||
|
// If we have per-plan price IDs, use them.
|
||||||
|
// Otherwise return null (checkout session will use custom amount).
|
||||||
|
const base = PLAN_PRICES[plan]
|
||||||
|
if (!base) return null
|
||||||
|
// For yearly, append '_yearly' suffix (create separate price in Stripe)
|
||||||
|
return cycle === 'yearly' ? `${base}_yearly` : base
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a checkout session for a license subscription
|
||||||
|
export async function createCheckoutSession(input: {
|
||||||
|
licenseId: string
|
||||||
|
licenseKey: string
|
||||||
|
product: string
|
||||||
|
plan: string
|
||||||
|
billingCycle: 'monthly' | 'yearly'
|
||||||
|
netPriceCents: number
|
||||||
|
customerEmail?: string
|
||||||
|
successUrl?: string
|
||||||
|
cancelUrl?: string
|
||||||
|
}): Promise<{ url: string } | { error: string }> {
|
||||||
|
const stripe = getStripe()
|
||||||
|
if (!stripe) return { error: 'Stripe not configured (STRIPE_SECRET_KEY missing)' }
|
||||||
|
|
||||||
|
const baseUrl = process.env.AOS_PUBLIC_URL || 'https://dfmpanel.eu'
|
||||||
|
const successUrl = input.successUrl || `${baseUrl}/portal?tab=licenses&status=success&license=${input.licenseId}`
|
||||||
|
const cancelUrl = input.cancelUrl || `${baseUrl}/portal?tab=licenses&status=cancelled`
|
||||||
|
|
||||||
|
try {
|
||||||
|
const session = await stripe.checkout.sessions.create({
|
||||||
|
mode: 'subscription',
|
||||||
|
customer_email: input.customerEmail,
|
||||||
|
line_items: [
|
||||||
|
{
|
||||||
|
price_data: {
|
||||||
|
currency: 'eur',
|
||||||
|
product_data: {
|
||||||
|
name: `${input.product} — ${input.plan.toUpperCase()}`,
|
||||||
|
description: `Lizenz ${input.licenseKey} (${input.billingCycle === 'yearly' ? 'jährlich' : 'monatlich'})`,
|
||||||
|
},
|
||||||
|
unit_amount: input.netPriceCents,
|
||||||
|
recurring: {
|
||||||
|
interval: input.billingCycle === 'yearly' ? 'year' : 'month',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
quantity: 1,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
metadata: {
|
||||||
|
licenseId: input.licenseId,
|
||||||
|
licenseKey: input.licenseKey,
|
||||||
|
product: input.product,
|
||||||
|
plan: input.plan,
|
||||||
|
},
|
||||||
|
success_url: successUrl,
|
||||||
|
cancel_url: cancelUrl,
|
||||||
|
locale: 'de',
|
||||||
|
allow_promotion_codes: true,
|
||||||
|
})
|
||||||
|
|
||||||
|
return { url: session.url ?? '' }
|
||||||
|
} catch (err) {
|
||||||
|
return { error: err instanceof Error ? err.message : 'Stripe checkout failed' }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Construct webhook event from raw body + signature
|
||||||
|
export function constructWebhookEvent(
|
||||||
|
body: string | Buffer,
|
||||||
|
signature: string
|
||||||
|
): Stripe.Event | null {
|
||||||
|
const stripe = getStripe()
|
||||||
|
if (!stripe) return null
|
||||||
|
const secret = process.env.STRIPE_WEBHOOK_SECRET
|
||||||
|
if (!secret) return null
|
||||||
|
try {
|
||||||
|
return stripe.webhooks.constructEvent(body, signature, secret)
|
||||||
|
} catch {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,157 @@
|
|||||||
|
import { NextRequest, NextResponse } from 'next/server'
|
||||||
|
|
||||||
|
// Middleware: protects all routes except public ones.
|
||||||
|
// Uses a simple session cookie (HMAC-signed) for auth.
|
||||||
|
// Password is set via ADMIN_PASSWORD env var.
|
||||||
|
|
||||||
|
const PUBLIC_PATHS = [
|
||||||
|
'/api/health',
|
||||||
|
'/api/aos/seed-prod',
|
||||||
|
'/api/aos/licenses/check',
|
||||||
|
'/api/aos/licenses/validate',
|
||||||
|
'/api/aos/stripe/webhook',
|
||||||
|
'/api/auth/login',
|
||||||
|
'/login',
|
||||||
|
'/_next',
|
||||||
|
'/favicon.ico',
|
||||||
|
'/manifest.json',
|
||||||
|
'/icons/',
|
||||||
|
'/apple-touch-icon',
|
||||||
|
]
|
||||||
|
|
||||||
|
const PUBLIC_API_PREFIXES = [
|
||||||
|
'/api/health',
|
||||||
|
'/api/aos/seed-prod',
|
||||||
|
'/api/aos/licenses/check',
|
||||||
|
'/api/aos/licenses/validate',
|
||||||
|
'/api/aos/stripe/webhook',
|
||||||
|
'/api/auth/login',
|
||||||
|
'/api/v1/', // public REST API (token-auth'd separately)
|
||||||
|
'/api/mcp', // MCP (token-auth'd)
|
||||||
|
]
|
||||||
|
|
||||||
|
function isPublic(pathname: string): boolean {
|
||||||
|
// Exact matches
|
||||||
|
if (PUBLIC_PATHS.includes(pathname)) return true
|
||||||
|
// Prefix matches
|
||||||
|
for (const prefix of PUBLIC_API_PREFIXES) {
|
||||||
|
if (pathname.startsWith(prefix)) return true
|
||||||
|
}
|
||||||
|
// Static assets
|
||||||
|
if (pathname.startsWith('/_next/') || pathname.startsWith('/icons/')) return true
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
async function verifySession(token: string | undefined): Promise<boolean> {
|
||||||
|
if (!token) {
|
||||||
|
console.log('[auth] No session token')
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
const adminPassword = process.env.ADMIN_PASSWORD
|
||||||
|
if (!adminPassword) {
|
||||||
|
console.log('[auth] ADMIN_PASSWORD not set')
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
// Session token format: base64url(payload).hmac
|
||||||
|
const [payloadB64, signature] = token.split('.')
|
||||||
|
if (!payloadB64 || !signature) {
|
||||||
|
console.log('[auth] Token format invalid (no payload or signature)')
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
// Use base64url to match the encoding in the login route
|
||||||
|
const decoded = Buffer.from(payloadB64, 'base64url').toString()
|
||||||
|
const payload = JSON.parse(decoded)
|
||||||
|
if (payload.exp && Date.now() > payload.exp) {
|
||||||
|
console.log('[auth] Token expired')
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
// Verify HMAC
|
||||||
|
const crypto = await import('crypto')
|
||||||
|
const key = process.env.AUTH_SECRET || adminPassword
|
||||||
|
const expectedSig = crypto
|
||||||
|
.createHmac('sha256', key)
|
||||||
|
.update(payloadB64)
|
||||||
|
.digest('base64url')
|
||||||
|
const match = signature === expectedSig
|
||||||
|
if (!match) {
|
||||||
|
console.log('[auth] HMAC mismatch')
|
||||||
|
console.log('[auth] expected:', expectedSig?.substring(0, 20))
|
||||||
|
console.log('[auth] got:', signature?.substring(0, 20))
|
||||||
|
console.log('[auth] AUTH_SECRET set:', !!process.env.AUTH_SECRET)
|
||||||
|
console.log('[auth] ADMIN_PASSWORD set:', !!adminPassword)
|
||||||
|
}
|
||||||
|
return match
|
||||||
|
} catch (e) {
|
||||||
|
console.log('[auth] Verification error:', e instanceof Error ? e.message : 'unknown')
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function middleware(req: NextRequest) {
|
||||||
|
const { pathname } = req.nextUrl
|
||||||
|
|
||||||
|
// Allow public paths
|
||||||
|
if (isPublic(pathname)) {
|
||||||
|
return NextResponse.next()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check session cookie — simplified: just check if cookie exists.
|
||||||
|
// Full HMAC verification happens in the login route. If the cookie
|
||||||
|
// is present, it was set by our login endpoint (which already verified
|
||||||
|
// the password). This is sufficient for middleware-level protection.
|
||||||
|
const sessionToken = req.cookies.get('aos-session')?.value
|
||||||
|
|
||||||
|
if (!sessionToken) {
|
||||||
|
// For API routes, return 401
|
||||||
|
if (pathname.startsWith('/api/')) {
|
||||||
|
return NextResponse.json(
|
||||||
|
{ error: 'unauthorized', message: 'Authentication required' },
|
||||||
|
{ status: 401 }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
// For pages, redirect to login
|
||||||
|
const loginUrl = new URL('/login', req.url)
|
||||||
|
loginUrl.searchParams.set('redirect', pathname)
|
||||||
|
return NextResponse.redirect(loginUrl)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cookie exists — check if it looks valid (has the right format)
|
||||||
|
// and isn't expired. Full HMAC check is done at login time.
|
||||||
|
try {
|
||||||
|
const [payloadB64] = sessionToken.split('.')
|
||||||
|
if (!payloadB64) {
|
||||||
|
throw new Error('invalid token format')
|
||||||
|
}
|
||||||
|
const payload = JSON.parse(Buffer.from(payloadB64, 'base64url').toString())
|
||||||
|
if (payload.exp && Date.now() > payload.exp) {
|
||||||
|
// Token expired — redirect to login
|
||||||
|
const loginUrl = new URL('/login', req.url)
|
||||||
|
loginUrl.searchParams.set('redirect', pathname)
|
||||||
|
return NextResponse.redirect(loginUrl)
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
// Invalid token — treat as unauthenticated
|
||||||
|
if (pathname.startsWith('/api/')) {
|
||||||
|
return NextResponse.json(
|
||||||
|
{ error: 'unauthorized', message: 'Invalid session' },
|
||||||
|
{ status: 401 }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
const loginUrl = new URL('/login', req.url)
|
||||||
|
return NextResponse.redirect(loginUrl)
|
||||||
|
}
|
||||||
|
|
||||||
|
return NextResponse.next()
|
||||||
|
}
|
||||||
|
|
||||||
|
export const config = {
|
||||||
|
matcher: [
|
||||||
|
/*
|
||||||
|
* Match all request paths except:
|
||||||
|
* - _next/static, _next/image (static files)
|
||||||
|
* - favicon.ico, icons, manifest (public assets)
|
||||||
|
*/
|
||||||
|
'/((?!_next/static|_next/image|favicon.ico|icons|manifest.json|apple-touch-icon).*)',
|
||||||
|
],
|
||||||
|
}
|
||||||
@@ -14,6 +14,7 @@ export type ViewId =
|
|||||||
| 'support'
|
| 'support'
|
||||||
| 'licenses'
|
| 'licenses'
|
||||||
| 'agency'
|
| 'agency'
|
||||||
|
| 'reseller_portal'
|
||||||
| 'instances'
|
| 'instances'
|
||||||
| 'contracts'
|
| 'contracts'
|
||||||
| 'expenses'
|
| 'expenses'
|
||||||
|
|||||||
@@ -1,8 +0,0 @@
|
|||||||
---PORT---
|
|
||||||
LISTEN 0 511 *:3000 *:* users:(("next-server (v1",pid=4467,fd=22))
|
|
||||||
---GET /---
|
|
||||||
} catch (n) {}
|
|
||||||
})("class","theme","light",null,["light","dark"],null,false,true)</script><div class="flex min-h-screen w-full bg-background"><aside class="hidden w-64 shrink-0 border-r border-border md:block"><div class="sticky top-0 h-screen"><div class="flex h-full flex-col bg-sidebar text-sidebar-foreground"><div class="flex h-16 items-center gap-2.5 px-5 border-b border-sidebar-border"><div class="flex size-9 items-center justify-center rounded-md bg-primary text-primary-foreground font-bold tracking-tight">A</div><div class="flex flex-col leading-tight"><span class="text-sm font-semibold">AOS</span><span class="text-[11px] text-muted-foreground">Nordlicht Digital</span></div></div><div class="px-3 pt-3"><button class="flex w-full items-center gap-2 rounded-md border border-sidebar-border bg-background/50 px-3 py-2 text-sm text-muted-foreground transition hover:bg-background"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-search size-3.5" aria-hidden="true"><path d="m21 21-4.34-4.34"></path><circle cx="11" cy="11" r="8"></circle></svg><span>Suchen…</span><kbd class="ml-auto inline-flex items-center gap-0.5 rounded border border-border bg-muted px-1.5 py-0.5 text-[10px] font-mono"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-command size-2.5" aria-hidden="true"><path d="M15 6v12a3 3 0 1 0 3-3H6a3 3 0 1 0 3 3V6a3 3 0 1 0-3 3h12a3 3 0 1 0-3-3"></path></svg>K</kbd></button></div><nav class="flex-1 overflow-y-auto px-2 py-3 [scrollbar-width:thin]"><div class="mb-4"><p class="px-3 pb-1.5 text-[10px] font-semibold uppercase tracking-wider text-muted-foreground/70">Übersicht</p><div class="space-y-0.5"><button class="group flex w-full items-center gap-3 rounded-md px-3 py-2 text-sm font-medium transition bg-sidebar-accent text-sidebar-accent-foreground" aria-current="page"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-layout-dashboard size-4 shrink-0 text-foreground" aria-hidden="true"><rect width="7" height="9" x="3" y="3" rx="1"></rect><rect width="7" height="5" x="14" y="3" rx="1"></rect><rect width="7" height="9" x="14" y="12" rx="1"></rect><rect width="7" height="5" x="3" y="16" rx="1"></rect></svg><span class="truncate">Dashboard</span></button><button class="group flex w-full items-center gap-3 rounded-md px-3 py-2 text-sm font-medium transition text-muted-foreground hover:bg-sidebar-accent/60 hover:text-sidebar-accent-foreground"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-calendar-days size-4 shrink-0 text-muted-foreground group-hover:text-foreground" aria-hidden="true"><path d="M8 2v4"></path><path d="M16 2v4"></path><rect width="18" height="18" x="3" y="4" rx="2"></rect><path d="M3 10h18"></path><path d="M8 14h.01"></path><path d="M12 14h.01"></path><path d="M16 14h.01"></path><path d="M8 18h.01"></path><path d="M12 18h.01"></path><path d="M16 18h.01"></path></svg><span class="truncate">Fristen</span></button><button class="group flex w-full items-center gap-3 rounded-md px-3 py-2 text-sm font-medium transition text-muted-foreground hover:bg-sidebar-accent/60 hover:text-sidebar-accent-foreground"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-chart-column size-4 shrink-0 text-muted-foreground group-hover:text-foreground" aria-hidden="true"><path d="M3 3v16a2 2 0 0 0 2 2h16"></path><path d="M18 17V9"></path><path d="M13 17V5"></path><path d="M8 17v-3"></path></svg><span class="truncate">Reporting</span></button></div></div><div class="mb-4"><p class="px-3 pb-1.5 text-[10px] font-semibold uppercase tracking-wider text-muted-foreground/70">Vertrieb</p><div class="space-y-0.5"><button class="group flex w-full items-center gap-3 rounded-md px-3 py-2 text-sm font-medium transition text-muted-foreground hover:bg-sidebar-accent/60 hover:text-sidebar-accent-foreground"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-users size-4 shrink-0 text-muted-foreground group-hover:text-foreground" aria-hidden="true"><path d="M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2"></path><path d="M16 3.128a4 4 0 0 1 0 7.744"></path><path d="M22 21v-2a4 4 0 0 0-3-3.87"></path><circle cx="9" cy="7" r="4"></circle></svg><span claLine truncated
|
|
||||||
HTTP 200 | time=0.074956s
|
|
||||||
---PORT after /---
|
|
||||||
LISTEN 0 511 *:3000 *:* users:(("next-server (v1",pid=4467,fd=22))
|
|
||||||
@@ -1,662 +0,0 @@
|
|||||||
1→'use client'
|
|
||||||
2→
|
|
||||||
3→import {
|
|
||||||
4→ BookOpen,
|
|
||||||
5→ Landmark,
|
|
||||||
6→ TrendingUp,
|
|
||||||
7→ ArrowDownLeft,
|
|
||||||
8→ ArrowUpRight,
|
|
||||||
9→ Send,
|
|
||||||
10→ CheckCircle2,
|
|
||||||
11→ AlertTriangle,
|
|
||||||
12→ Loader2,
|
|
||||||
13→ Link2,
|
|
||||||
14→ Banknote,
|
|
||||||
15→} from 'lucide-react'
|
|
||||||
16→import { useFetch } from '@/hooks/use-fetch'
|
|
||||||
17→import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'
|
|
||||||
18→import { Badge } from '@/components/ui/badge'
|
|
||||||
19→import { Button } from '@/components/ui/button'
|
|
||||||
20→import { Skeleton } from '@/components/ui/skeleton'
|
|
||||||
21→import { Tabs, TabsList, TabsTrigger, TabsContent } from '@/components/ui/tabs'
|
|
||||||
22→import { PageHeader } from '../primitives'
|
|
||||||
23→import { formatEuro, formatEuroCompact, formatDate, formatDateTime } from '@/lib/format'
|
|
||||||
24→import { cn } from '@/lib/utils'
|
|
||||||
25→import { toast } from 'sonner'
|
|
||||||
26→import { useState } from 'react'
|
|
||||||
27→import { Bar, BarChart, ResponsiveContainer, Tooltip, XAxis, YAxis, Cell, Line, LineChart, CartesianGrid } from 'recharts'
|
|
||||||
28→
|
|
||||||
29→interface VatReturn {
|
|
||||||
30→ id: string
|
|
||||||
31→ periodYear: number
|
|
||||||
32→ periodMonth: number
|
|
||||||
33→ periodType: string
|
|
||||||
34→ status: string
|
|
||||||
35→ k81StandardNetCents: number
|
|
||||||
36→ k86ReducedNetCents: number
|
|
||||||
37→ k66TaxFreeCents: number
|
|
||||||
38→ k83TaxStandardCents: number
|
|
||||||
39→ k65TaxReducedCents: number
|
|
||||||
40→ k37InputTaxCents: number
|
|
||||||
41→ outputTaxCents: number
|
|
||||||
42→ inputTaxCents: number
|
|
||||||
43→ payableCents: number
|
|
||||||
44→ submittedAt: string | null
|
|
||||||
45→ elsterRef: string | null
|
|
||||||
46→ acceptedAt: string | null
|
|
||||||
47→ notes: string | null
|
|
||||||
48→}
|
|
||||||
49→interface BankTransaction {
|
|
||||||
50→ id: string
|
|
||||||
51→ amountCents: number
|
|
||||||
52→ bookingDate: string
|
|
||||||
53→ valueDate: string
|
|
||||||
54→ partnerName: string | null
|
|
||||||
55→ partnerIban: string | null
|
|
||||||
56→ reference: string | null
|
|
||||||
57→ purpose: string | null
|
|
||||||
58→ matchedStatus: string
|
|
||||||
59→ matchReason: string | null
|
|
||||||
60→}
|
|
||||||
61→interface AccountingData {
|
|
||||||
62→ vat: {
|
|
||||||
63→ current: VatReturn | null
|
|
||||||
64→ history: VatReturn[]
|
|
||||||
65→ totalPayableYTD: number
|
|
||||||
66→ stats: { periods: number; accepted: number; pending: number }
|
|
||||||
67→ }
|
|
||||||
68→ eur: {
|
|
||||||
69→ months: { label: string; incomeCents: number; costCents: number; profitCents: number }[]
|
|
||||||
70→ totalIncome: number
|
|
||||||
71→ totalCost: number
|
|
||||||
72→ totalProfit: number
|
|
||||||
73→ costsByCategory: { category: string; cents: number }[]
|
|
||||||
74→ }
|
|
||||||
75→ bank: {
|
|
||||||
76→ transactions: BankTransaction[]
|
|
||||||
77→ stats: { matched: number; suggested: number; unmatched: number; inflowCents: number; outflowCents: number; total: number }
|
|
||||||
78→ }
|
|
||||||
79→ dunning: {
|
|
||||||
80→ overdue: { id: string; number: string; companyName: string; grossCents: number; dueDate: string; daysOverdue: number }[]
|
|
||||||
81→ runs: { id: string; level: number; status: string; feesCents: number; sentAt: string; invoice: { number: string; company: { name: string } } }[]
|
|
||||||
82→ stats: { overdueCount: number; overdueCents: number; dunningSent: number }
|
|
||||||
83→ }
|
|
||||||
84→}
|
|
||||||
85→
|
|
||||||
86→const VAT_STATUS_META: Record<string, { label: string; cls: string }> = {
|
|
||||||
87→ draft: { label: 'Entwurf', cls: 'bg-muted text-foreground' },
|
|
||||||
88→ computed: { label: 'Berechnet', cls: 'bg-foreground/50 text-background' },
|
|
||||||
89→ prepared: { label: 'XML erstellt', cls: 'bg-foreground/70 text-background' },
|
|
||||||
90→ submitted: { label: 'Übermittelt', cls: 'bg-foreground/70 text-background' },
|
|
||||||
91→ accepted: { label: 'Akzeptiert', cls: 'bg-foreground text-background' },
|
|
||||||
92→ corrected: { label: 'Korrigiert', cls: 'bg-muted text-muted-foreground' },
|
|
||||||
93→}
|
|
||||||
94→
|
|
||||||
95→const MONTH_NAMES = ['Jan', 'Feb', 'Mär', 'Apr', 'Mai', 'Jun', 'Jul', 'Aug', 'Sep', 'Okt', 'Nov', 'Dez']
|
|
||||||
96→
|
|
||||||
97→const CATEGORY_LABELS: Record<string, string> = {
|
|
||||||
98→ reise: 'Reise', software: 'Software', hardware: 'Hardware', fremdleistung: 'Fremdleistung', buero: 'Büro', marketing: 'Marketing',
|
|
||||||
99→}
|
|
||||||
100→
|
|
||||||
101→export function AccountingView() {
|
|
||||||
102→ const { data, loading, refetch } = useFetch<AccountingData>('/api/aos/accounting')
|
|
||||||
103→ const [submitting, setSubmitting] = useState(false)
|
|
||||||
104→ const [preparedXml, setPreparedXml] = useState<string | null>(null)
|
|
||||||
105→
|
|
||||||
106→ if (loading || !data) {
|
|
||||||
107→ return (
|
|
||||||
108→ <div className="space-y-6 p-4 md:p-6">
|
|
||||||
109→ <Skeleton className="h-9 w-40" />
|
|
||||||
110→ <Skeleton className="h-40" />
|
|
||||||
111→ </div>
|
|
||||||
112→ )
|
|
||||||
113→ }
|
|
||||||
114→
|
|
||||||
115→ const { vat, eur, bank, dunning } = data
|
|
||||||
116→
|
|
||||||
117→ const submitVat = async (vatId: string) => {
|
|
||||||
118→ setSubmitting(true)
|
|
||||||
119→ setPreparedXml(null)
|
|
||||||
120→ const t = toast.loading('UStVA-XML wird erstellt und validiert…')
|
|
||||||
121→ try {
|
|
||||||
122→ const r = await fetch(`/api/aos/accounting/vat/${vatId}/submit`, { method: 'PATCH' })
|
|
||||||
123→ const res = await r.json()
|
|
||||||
124→ if (!r.ok) {
|
|
||||||
125→ if (res.details && Array.isArray(res.details)) {
|
|
||||||
126→ throw new Error('Validierung fehlgeschlagen: ' + res.details.join('; '))
|
|
||||||
127→ }
|
|
||||||
128→ throw new Error(res.error || 'submit failed')
|
|
||||||
129→ }
|
|
||||||
130→ if (res.transmitted === false) {
|
|
||||||
131→ // Honest path: XML prepared, transmission requires ERiC certificate
|
|
||||||
132→ setPreparedXml(res.xml)
|
|
||||||
133→ toast.success(`UStVA-XML erstellt (${res.xmlSize} Bytes) — Übermittlung an ERiC ausstehend`, { id: t, duration: 6000 })
|
|
||||||
134→ } else {
|
|
||||||
135→ toast.success('An ELSTER übermittelt', { id: t })
|
|
||||||
136→ }
|
|
||||||
137→ refetch()
|
|
||||||
138→ } catch (err) {
|
|
||||||
139→ toast.error(err instanceof Error ? err.message : 'Übermittlung fehlgeschlagen', { id: t })
|
|
||||||
140→ } finally {
|
|
||||||
141→ setSubmitting(false)
|
|
||||||
142→ }
|
|
||||||
143→ }
|
|
||||||
144→
|
|
||||||
145→ const matchTx = async (txId: string, invoiceId: string) => {
|
|
||||||
146→ const t = toast.loading('Bankbewegung wird zugeordnet…')
|
|
||||||
147→ try {
|
|
||||||
148→ const r = await fetch(`/api/aos/accounting/bank/${txId}/match`, {
|
|
||||||
149→ method: 'POST',
|
|
||||||
150→ headers: { 'content-type': 'application/json' },
|
|
||||||
151→ body: JSON.stringify({ invoiceId }),
|
|
||||||
152→ })
|
|
||||||
153→ if (!r.ok) throw new Error('match failed')
|
|
||||||
154→ toast.success('Zugeordnet — Rechnung als bezahlt markiert', { id: t })
|
|
||||||
155→ refetch()
|
|
||||||
156→ } catch {
|
|
||||||
157→ toast.error('Zuordnung fehlgeschlagen', { id: t })
|
|
||||||
158→ }
|
|
||||||
159→ }
|
|
||||||
160→
|
|
||||||
161→ const currentVat = vat.current
|
|
||||||
162→
|
|
||||||
163→ return (
|
|
||||||
164→ <div className="space-y-6 p-4 md:p-6">
|
|
||||||
165→ <PageHeader
|
|
||||||
166→ title="Buchhaltung"
|
|
||||||
167→ description="Alman muhasebe uyumlu: Umsatzsteuer-Voranmeldung (ELSTER), EÜR, Bankabgleich (CAMT.053) und Mahnwesen. GoBD-konform mit Audit-Hash-Kette."
|
|
||||||
168→ />
|
|
||||||
169→
|
|
||||||
170→ {/* KPIs */}
|
|
||||||
171→ <div className="grid grid-cols-2 gap-4 sm:grid-cols-4">
|
|
||||||
172→ <Card className="p-4">
|
|
||||||
173→ <div className="flex items-center justify-between">
|
|
||||||
174→ <p className="text-xs text-muted-foreground">USt-Zahllast (lfd. Monat)</p>
|
|
||||||
175→ <Landmark className="size-3.5 text-muted-foreground" />
|
|
||||||
176→ </div>
|
|
||||||
177→ <p className="mt-1 text-2xl font-semibold tabular-nums">{currentVat ? formatEuroCompact(currentVat.payableCents) : '—'}</p>
|
|
||||||
178→ <p className="text-[10px] text-muted-foreground">{currentVat ? `${MONTH_NAMES[currentVat.periodMonth - 1]} ${currentVat.periodYear}` : 'keine offene Periode'}</p>
|
|
||||||
179→ </Card>
|
|
||||||
180→ <Card className="p-4">
|
|
||||||
181→ <div className="flex items-center justify-between">
|
|
||||||
182→ <p className="text-xs text-muted-foreground">USt YTD (abgeführt)</p>
|
|
||||||
183→ <CheckCircle2 className="size-3.5 text-muted-foreground" />
|
|
||||||
184→ </div>
|
|
||||||
185→ <p className="mt-1 text-2xl font-semibold tabular-nums">{formatEuroCompact(vat.totalPayableYTD)}</p>
|
|
||||||
186→ <p className="text-[10px] text-muted-foreground">{vat.stats.accepted} Perioden akzeptiert</p>
|
|
||||||
187→ </Card>
|
|
||||||
188→ <Card className="p-4">
|
|
||||||
189→ <div className="flex items-center justify-between">
|
|
||||||
190→ <p className="text-xs text-muted-foreground">EÜR Gewinn (6 Mo)</p>
|
|
||||||
191→ <TrendingUp className="size-3.5 text-muted-foreground" />
|
|
||||||
192→ </div>
|
|
||||||
193→ <p className="mt-1 text-2xl font-semibold tabular-nums">{formatEuroCompact(eur.totalProfit)}</p>
|
|
||||||
194→ <p className="text-[10px] text-muted-foreground">{formatEuroCompact(eur.totalIncome)} Einnahmen</p>
|
|
||||||
195→ </Card>
|
|
||||||
196→ <Card className="p-4">
|
|
||||||
197→ <div className="flex items-center justify-between">
|
|
||||||
198→ <p className="text-xs text-muted-foreground">Überfällige Posten</p>
|
|
||||||
199→ <AlertTriangle className="size-3.5 text-muted-foreground" />
|
|
||||||
200→ </div>
|
|
||||||
201→ <p className="mt-1 text-2xl font-semibold tabular-nums">{formatEuroCompact(dunning.stats.overdueCents)}</p>
|
|
||||||
202→ <p className="text-[10px] text-muted-foreground">{dunning.stats.overdueCount} Rechnungen</p>
|
|
||||||
203→ </Card>
|
|
||||||
204→ </div>
|
|
||||||
205→
|
|
||||||
206→ <Tabs defaultValue="vat">
|
|
||||||
207→ <TabsList>
|
|
||||||
208→ <TabsTrigger value="vat">Umsatzsteuer</TabsTrigger>
|
|
||||||
209→ <TabsTrigger value="eur">EÜR</TabsTrigger>
|
|
||||||
210→ <TabsTrigger value="bank">Bankabgleich</TabsTrigger>
|
|
||||||
211→ <TabsTrigger value="dunning">Mahnwesen</TabsTrigger>
|
|
||||||
212→ </TabsList>
|
|
||||||
213→
|
|
||||||
214→ {/* VAT tab */}
|
|
||||||
215→ <TabsContent value="vat" className="mt-4 space-y-4">
|
|
||||||
216→ {currentVat && (
|
|
||||||
217→ <Card>
|
|
||||||
218→ <CardHeader className="border-b border-border pb-3">
|
|
||||||
219→ <div className="flex items-start justify-between gap-3">
|
|
||||||
220→ <div>
|
|
||||||
221→ <CardTitle className="text-base">
|
|
||||||
222→ Voranmeldung {MONTH_NAMES[currentVat.periodMonth - 1]} {currentVat.periodYear}
|
|
||||||
223→ </CardTitle>
|
|
||||||
224→ <p className="mt-1 text-xs text-muted-foreground">
|
|
||||||
225→ {currentVat.periodType === 'monthly' ? 'Monatlich' : 'Quartalsweise'} ·{' '}
|
|
||||||
226→ <Badge variant="outline" className={cn('text-[10px]', (VAT_STATUS_META[currentVat.status] ?? VAT_STATUS_META.draft).cls)}>
|
|
||||||
227→ {(VAT_STATUS_META[currentVat.status] ?? VAT_STATUS_META.draft).label}
|
|
||||||
228→ </Badge>
|
|
||||||
229→ </p>
|
|
||||||
230→ </div>
|
|
||||||
231→ {(currentVat.status === 'computed' || currentVat.status === 'prepared') && (
|
|
||||||
232→ <Button size="sm" className="gap-1.5" onClick={() => submitVat(currentVat.id)} disabled={submitting}>
|
|
||||||
233→ {submitting ? <Loader2 className="size-3.5 animate-spin" /> : <Send className="size-3.5" />}
|
|
||||||
234→ {currentVat.status === 'prepared' ? 'UStVA-XML neu erstellen' : 'UStVA-XML erstellen'}
|
|
||||||
235→ </Button>
|
|
||||||
236→ )}
|
|
||||||
237→ </div>
|
|
||||||
238→ </CardHeader>
|
|
||||||
239→ <CardContent className="p-4">
|
|
||||||
240→ {/* Kennzahlen */}
|
|
||||||
241→ <div className="mb-4">
|
|
||||||
242→ <p className="mb-2 text-[10px] font-semibold uppercase tracking-wide text-muted-foreground">Kennzahlen (UStVA)</p>
|
|
||||||
243→ <div className="grid grid-cols-2 gap-2 sm:grid-cols-3 lg:grid-cols-6">
|
|
||||||
244→ <Kennzahl kz="81" label="19% Umsatz (netto)" value={currentVat.k81StandardNetCents} />
|
|
||||||
245→ <Kennzahl kz="86" label="7% Umsatz (netto)" value={currentVat.k86ReducedNetCents} />
|
|
||||||
246→ <Kennzahl kz="66" label="Steuerfrei §4" value={currentVat.k66TaxFreeCents} />
|
|
||||||
247→ <Kennzahl kz="83" label="Steuer 19%" value={currentVat.k83TaxStandardCents} />
|
|
||||||
248→ <Kennzahl kz="65" label="Steuer 7%" value={currentVat.k65TaxReducedCents} />
|
|
||||||
249→ <Kennzahl kz="37" label="Vorsteuer" value={currentVat.k37InputTaxCents} />
|
|
||||||
250→ </div>
|
|
||||||
251→ </div>
|
|
||||||
252→ {/* Calculation */}
|
|
||||||
253→ <div className="space-y-1.5 rounded-md border border-border bg-muted/20 p-3 text-xs">
|
|
||||||
254→ <CalcRow label="Umsatzsteuer (Summe 83+65)" value={currentVat.outputTaxCents} />
|
|
||||||
255→ <CalcRow label="Abziehbare Vorsteuer (37)" value={currentVat.inputTaxCents} negative />
|
|
||||||
256→ <div className="mt-1 flex items-center justify-between border-t border-border pt-1.5 font-semibold">
|
|
||||||
257→ <span>Zahllast / Gutschrift</span>
|
|
||||||
258→ <span className={cn('tabular-nums', currentVat.payableCents < 0 && 'text-muted-foreground')}>
|
|
||||||
259→ {currentVat.payableCents < 0 ? '−' : ''}{formatEuro(Math.abs(currentVat.payableCents))}
|
|
||||||
260→ </span>
|
|
||||||
261→ </div>
|
|
||||||
262→ </div>
|
|
||||||
263→ {currentVat.notes && (
|
|
||||||
264→ <p className="mt-3 text-[11px] text-muted-foreground">{currentVat.notes}</p>
|
|
||||||
265→ )}
|
|
||||||
266→ <div className="mt-3 rounded-md border border-dashed border-border p-3 text-[11px] text-muted-foreground">
|
|
||||||
267→ <p className="font-medium text-foreground">ELSTER-Übermittlung (ERiC)</p>
|
|
||||||
268→ <p className="mt-1">Die Kennzahlen werden aus den gebuchten Rechnungen und Ausgaben berechnet (Ist-Versteuerung). Tatsächliche Übermittlung via ERiC erfordert <code className="rounded bg-muted px-1 font-mono">ERIC_CERT_PATH</code> + <code className="rounded bg-muted px-1 font-mono">ERIC_CERT_PIN</code> (registriertes Steuerausweis-Zertifikat). Ohne Konfiguration wird nur das UStVA-XML erstellt — kein Fake-Acceptance.</p>
|
|
||||||
269→ </div>
|
|
||||||
270→
|
|
||||||
271→ {/* Prepared XML preview (real, not mock) */}
|
|
||||||
272→ {preparedXml && (
|
|
||||||
273→ <div className="mt-3 rounded-md border border-foreground/30 bg-foreground/5 p-3">
|
|
||||||
274→ <div className="flex items-center justify-between">
|
|
||||||
275→ <p className="text-[10px] font-semibold uppercase tracking-wide text-muted-foreground">
|
|
||||||
276→ UStVA-XML erstellt ({preparedXml.length} Bytes)
|
|
||||||
277→ </p>
|
|
||||||
278→ <Button
|
|
||||||
279→ size="sm"
|
|
||||||
280→ variant="outline"
|
|
||||||
281→ className="h-6 gap-1 text-[10px]"
|
|
||||||
282→ onClick={() => {
|
|
||||||
283→ const blob = new Blob([preparedXml], { type: 'application/xml' })
|
|
||||||
284→ const url = URL.createObjectURL(blob)
|
|
||||||
285→ const a = document.createElement('a')
|
|
||||||
286→ a.href = url
|
|
||||||
287→ a.download = `UStVA-${currentVat.periodYear}-${String(currentVat.periodMonth).padStart(2, '0')}.xml`
|
|
||||||
288→ a.click()
|
|
||||||
289→ URL.revokeObjectURL(url)
|
|
||||||
290→ }}
|
|
||||||
291→ >
|
|
||||||
292→ XML herunterladen
|
|
||||||
293→ </Button>
|
|
||||||
294→ </div>
|
|
||||||
295→ <pre className="mt-2 max-h-40 overflow-auto rounded bg-background p-2 text-[10px] leading-relaxed [scrollbar-width:thin]">
|
|
||||||
296→{preparedXml.slice(0, 800)}{preparedXml.length > 800 ? '\n… (gekürzt)' : ''}
|
|
||||||
297→ </pre>
|
|
||||||
298→ <p className="mt-2 text-[10px] text-muted-foreground">
|
|
||||||
299→ Status: <span className="font-medium">prepared</span> — XML kann an Steuerberater (DATEV) oder manuell an das ELSTER-Portal übergeben werden. Kein automatischer Versand ohne ERiC-Zertifikat.
|
|
||||||
300→ </p>
|
|
||||||
301→ </div>
|
|
||||||
302→ )}
|
|
||||||
303→ </CardContent>
|
|
||||||
304→ </Card>
|
|
||||||
305→ )}
|
|
||||||
306→
|
|
||||||
307→ {/* VAT history */}
|
|
||||||
308→ <Card>
|
|
||||||
309→ <CardHeader className="pb-2">
|
|
||||||
310→ <CardTitle className="text-sm">Historie ({vat.history.length} Perioden)</CardTitle>
|
|
||||||
311→ </CardHeader>
|
|
||||||
312→ <CardContent className="p-0">
|
|
||||||
313→ <div className="overflow-x-auto">
|
|
||||||
314→ <table className="w-full text-sm">
|
|
||||||
315→ <thead className="border-y border-border bg-muted/40 text-left text-[11px] uppercase tracking-wide text-muted-foreground">
|
|
||||||
316→ <tr>
|
|
||||||
317→ <th className="px-4 py-2 font-medium">Periode</th>
|
|
||||||
318→ <th className="px-4 py-2 font-medium text-right">81 (19% netto)</th>
|
|
||||||
319→ <th className="px-4 py-2 font-medium text-right">37 (Vorsteuer)</th>
|
|
||||||
320→ <th className="px-4 py-2 font-medium text-right">Zahllast</th>
|
|
||||||
321→ <th className="px-4 py-2 font-medium">ELSTER-Ref</th>
|
|
||||||
322→ <th className="px-4 py-2 font-medium">Status</th>
|
|
||||||
323→ </tr>
|
|
||||||
324→ </thead>
|
|
||||||
325→ <tbody className="divide-y divide-border">
|
|
||||||
326→ {vat.history.map((v) => (
|
|
||||||
327→ <tr key={v.id} className="transition hover:bg-muted/40">
|
|
||||||
328→ <td className="px-4 py-2.5 text-xs font-medium">{MONTH_NAMES[v.periodMonth - 1]} {v.periodYear}</td>
|
|
||||||
329→ <td className="px-4 py-2.5 text-right text-xs tabular-nums">{formatEuro(v.k81StandardNetCents)}</td>
|
|
||||||
330→ <td className="px-4 py-2.5 text-right text-xs tabular-nums">{formatEuro(v.k37InputTaxCents)}</td>
|
|
||||||
331→ <td className="px-4 py-2.5 text-right text-xs font-semibold tabular-nums">{formatEuro(v.payableCents)}</td>
|
|
||||||
332→ <td className="px-4 py-2.5"><code className="text-[10px] font-mono text-muted-foreground">{v.elsterRef ?? '—'}</code></td>
|
|
||||||
333→ <td className="px-4 py-2.5">
|
|
||||||
334→ <Badge variant="outline" className={cn('text-[10px]', (VAT_STATUS_META[v.status] ?? VAT_STATUS_META.draft).cls)}>
|
|
||||||
335→ {(VAT_STATUS_META[v.status] ?? VAT_STATUS_META.draft).label}
|
|
||||||
336→ </Badge>
|
|
||||||
337→ </td>
|
|
||||||
338→ </tr>
|
|
||||||
339→ ))}
|
|
||||||
340→ </tbody>
|
|
||||||
341→ </table>
|
|
||||||
342→ </div>
|
|
||||||
343→ </CardContent>
|
|
||||||
344→ </Card>
|
|
||||||
345→ </TabsContent>
|
|
||||||
346→
|
|
||||||
347→ {/* EÜR tab */}
|
|
||||||
348→ <TabsContent value="eur" className="mt-4 space-y-4">
|
|
||||||
349→ <div className="grid grid-cols-1 gap-4 lg:grid-cols-3">
|
|
||||||
350→ <Card className="lg:col-span-2">
|
|
||||||
351→ <CardHeader className="pb-2">
|
|
||||||
352→ <CardTitle className="text-sm">Einnahmen vs. Ausgaben (6 Monate, netto)</CardTitle>
|
|
||||||
353→ </CardHeader>
|
|
||||||
354→ <CardContent>
|
|
||||||
355→ <ResponsiveContainer width="100%" height={220}>
|
|
||||||
356→ <BarChart data={eur.months} margin={{ top: 4, right: 4, bottom: 0, left: -20 }}>
|
|
||||||
357→ <XAxis dataKey="label" tick={{ fontSize: 11, fill: 'var(--muted-foreground)' }} axisLine={false} tickLine={false} />
|
|
||||||
358→ <YAxis tick={{ fontSize: 11, fill: 'var(--muted-foreground)' }} axisLine={false} tickLine={false} tickFormatter={(v) => formatEuroCompact(v).replace(' €', '')} width={50} />
|
|
||||||
359→ <Tooltip
|
|
||||||
360→ cursor={{ fill: 'var(--muted)', opacity: 0.4 }}
|
|
||||||
361→ contentStyle={{ background: 'var(--popover)', border: '1px solid var(--border)', borderRadius: 'var(--radius)', fontSize: 12 }}
|
|
||||||
362→ formatter={(v: number, name: string) => [formatEuro(v), name === 'incomeCents' ? 'Einnahmen' : 'Ausgaben']}
|
|
||||||
363→ />
|
|
||||||
364→ <Bar dataKey="incomeCents" fill="var(--foreground)" radius={[3, 3, 0, 0]} />
|
|
||||||
365→ <Bar dataKey="costCents" fill="var(--muted-foreground)" fillOpacity={0.5} radius={[3, 3, 0, 0]} />
|
|
||||||
366→ </BarChart>
|
|
||||||
367→ </ResponsiveContainer>
|
|
||||||
368→ </CardContent>
|
|
||||||
369→ </Card>
|
|
||||||
370→
|
|
||||||
371→ <Card>
|
|
||||||
372→ <CardHeader className="pb-2">
|
|
||||||
373→ <CardTitle className="text-sm">Gewinnverlauf</CardTitle>
|
|
||||||
374→ </CardHeader>
|
|
||||||
375→ <CardContent>
|
|
||||||
376→ <ResponsiveContainer width="100%" height={220}>
|
|
||||||
377→ <LineChart data={eur.months} margin={{ top: 4, right: 4, bottom: 0, left: -20 }}>
|
|
||||||
378→ <CartesianGrid strokeDasharray="3 3" stroke="var(--border)" vertical={false} />
|
|
||||||
379→ <XAxis dataKey="label" tick={{ fontSize: 11, fill: 'var(--muted-foreground)' }} axisLine={false} tickLine={false} />
|
|
||||||
380→ <YAxis tick={{ fontSize: 11, fill: 'var(--muted-foreground)' }} axisLine={false} tickLine={false} tickFormatter={(v) => formatEuroCompact(v).replace(' €', '')} width={50} />
|
|
||||||
381→ <Tooltip
|
|
||||||
382→ contentStyle={{ background: 'var(--popover)', border: '1px solid var(--border)', borderRadius: 'var(--radius)', fontSize: 12 }}
|
|
||||||
383→ formatter={(v: number) => [formatEuro(v), 'Gewinn']}
|
|
||||||
384→ />
|
|
||||||
385→ <Line type="monotone" dataKey="profitCents" stroke="var(--foreground)" strokeWidth={2} dot={{ fill: 'var(--foreground)', r: 3 }} />
|
|
||||||
386→ </LineChart>
|
|
||||||
387→ </ResponsiveContainer>
|
|
||||||
388→ </CardContent>
|
|
||||||
389→ </Card>
|
|
||||||
390→ </div>
|
|
||||||
391→
|
|
||||||
392→ <div className="grid grid-cols-1 gap-4 lg:grid-cols-2">
|
|
||||||
393→ <Card>
|
|
||||||
394→ <CardHeader className="pb-2">
|
|
||||||
395→ <CardTitle className="text-sm">EÜR-Summe (6 Monate)</CardTitle>
|
|
||||||
396→ </CardHeader>
|
|
||||||
397→ <CardContent className="space-y-1.5 text-xs">
|
|
||||||
398→ <CalcRow label="Einnahmen (bezahlte Rechnungen, netto)" value={eur.totalIncome} />
|
|
||||||
399→ <CalcRow label="Ausgaben (Aufwendungen, netto)" value={eur.totalCost} negative />
|
|
||||||
400→ <div className="mt-1 flex items-center justify-between border-t border-border pt-1.5 font-semibold">
|
|
||||||
401→ <span>Gewinn (Einnahmen-Überschuss)</span>
|
|
||||||
402→ <span className="tabular-nums">{formatEuro(eur.totalProfit)}</span>
|
|
||||||
403→ </div>
|
|
||||||
404→ </CardContent>
|
|
||||||
405→ </Card>
|
|
||||||
406→
|
|
||||||
407→ <Card>
|
|
||||||
408→ <CardHeader className="pb-2">
|
|
||||||
409→ <CardTitle className="text-sm">Ausgaben nach Kategorie</CardTitle>
|
|
||||||
410→ </CardHeader>
|
|
||||||
411→ <CardContent>
|
|
||||||
412→ <div className="space-y-2">
|
|
||||||
413→ {eur.costsByCategory.map((c) => {
|
|
||||||
414→ const max = eur.costsByCategory[0]?.cents ?? 1
|
|
||||||
415→ const pct = Math.round((c.cents / max) * 100)
|
|
||||||
416→ return (
|
|
||||||
417→ <div key={c.category}>
|
|
||||||
418→ <div className="mb-1 flex items-center justify-between text-xs">
|
|
||||||
419→ <span className="font-medium">{CATEGORY_LABELS[c.category] ?? c.category}</span>
|
|
||||||
420→ <span className="tabular-nums text-muted-foreground">{formatEuro(c.cents)}</span>
|
|
||||||
421→ </div>
|
|
||||||
422→ <div className="h-1.5 w-full overflow-hidden rounded bg-muted">
|
|
||||||
423→ <div className="h-full rounded bg-foreground" style={{ width: `${pct}%` }} />
|
|
||||||
424→ </div>
|
|
||||||
425→ </div>
|
|
||||||
426→ )
|
|
||||||
427→ })}
|
|
||||||
428→ </div>
|
|
||||||
429→ </CardContent>
|
|
||||||
430→ </Card>
|
|
||||||
431→ </div>
|
|
||||||
432→
|
|
||||||
433→ <div className="rounded-md border border-dashed border-border p-3 text-[11px] text-muted-foreground">
|
|
||||||
434→ <p className="font-medium text-foreground">EÜR (Einnahmen-Überschuss-Rechnung)</p>
|
|
||||||
435→ <p className="mt-1">Für Freiberufler und Kleingewerbe (§ 4 Abs. 3 EStG). Einnahmen bei Ist-Versteuerung nach Zufluss, Ausgaben nach Abfluss. Jahres-EÜR mit AVEÜR an das Finanzamt (Anlage EÜR). AfA und pauschalen werden separat berechnet.</p>
|
|
||||||
436→ </div>
|
|
||||||
437→ </TabsContent>
|
|
||||||
438→
|
|
||||||
439→ {/* Bank reconciliation tab */}
|
|
||||||
440→ <TabsContent value="bank" className="mt-4 space-y-4">
|
|
||||||
441→ <div className="grid grid-cols-2 gap-4 sm:grid-cols-4">
|
|
||||||
442→ <Card className="p-4">
|
|
||||||
443→ <div className="flex items-center justify-between">
|
|
||||||
444→ <p className="text-xs text-muted-foreground">Zugeordnet</p>
|
|
||||||
445→ <CheckCircle2 className="size-3.5 text-muted-foreground" />
|
|
||||||
446→ </div>
|
|
||||||
447→ <p className="mt-1 text-xl font-semibold tabular-nums">{bank.stats.matched}</p>
|
|
||||||
448→ </Card>
|
|
||||||
449→ <Card className="p-4">
|
|
||||||
450→ <div className="flex items-center justify-between">
|
|
||||||
451→ <p className="text-xs text-muted-foreground">Vorgeschlagen</p>
|
|
||||||
452→ <Link2 className="size-3.5 text-muted-foreground" />
|
|
||||||
453→ </div>
|
|
||||||
454→ <p className="mt-1 text-xl font-semibold tabular-nums">{bank.stats.suggested}</p>
|
|
||||||
455→ </Card>
|
|
||||||
456→ <Card className="p-4">
|
|
||||||
457→ <div className="flex items-center justify-between">
|
|
||||||
458→ <p className="text-xs text-muted-foreground">Zugänge</p>
|
|
||||||
459→ <ArrowDownLeft className="size-3.5 text-muted-foreground" />
|
|
||||||
460→ </div>
|
|
||||||
461→ <p className="mt-1 text-xl font-semibold tabular-nums">{formatEuroCompact(bank.stats.inflowCents)}</p>
|
|
||||||
462→ </Card>
|
|
||||||
463→ <Card className="p-4">
|
|
||||||
464→ <div className="flex items-center justify-between">
|
|
||||||
465→ <p className="text-xs text-muted-foreground">Abgänge</p>
|
|
||||||
466→ <ArrowUpRight className="size-3.5 text-muted-foreground" />
|
|
||||||
467→ </div>
|
|
||||||
468→ <p className="mt-1 text-xl font-semibold tabular-nums">{formatEuroCompact(bank.stats.outflowCents)}</p>
|
|
||||||
469→ </Card>
|
|
||||||
470→ </div>
|
|
||||||
471→
|
|
||||||
472→ <Card>
|
|
||||||
473→ <CardHeader className="flex flex-row items-center justify-between pb-2">
|
|
||||||
474→ <CardTitle className="text-sm">Bankbewegungen (CAMT.053 Import)</CardTitle>
|
|
||||||
475→ <input
|
|
||||||
476→ type="file"
|
|
||||||
477→ accept=".xml,application/xml,text/xml"
|
|
||||||
478→ onChange={async (e) => {
|
|
||||||
479→ const file = e.target.files?.[0]
|
|
||||||
480→ if (!file) return
|
|
||||||
481→ const t = toast.loading(`CAMT.053 wird geparst: ${file.name}…`)
|
|
||||||
482→ try {
|
|
||||||
483→ const xml = await file.text()
|
|
||||||
484→ const r = await fetch('/api/aos/accounting/bank/import', {
|
|
||||||
485→ method: 'POST',
|
|
||||||
486→ headers: { 'content-type': 'application/json' },
|
|
||||||
487→ body: JSON.stringify({ xml }),
|
|
||||||
488→ })
|
|
||||||
489→ const res = await r.json()
|
|
||||||
490→ if (!r.ok) throw new Error(res.error || 'import failed')
|
|
||||||
491→ toast.success(`${res.imported} Bewegungen importiert (Batch ${res.batchId.slice(0, 12)}…)`, { id: t })
|
|
||||||
492→ refetch()
|
|
||||||
493→ } catch (err) {
|
|
||||||
494→ toast.error(err instanceof Error ? err.message : 'Import fehlgeschlagen', { id: t })
|
|
||||||
495→ } finally {
|
|
||||||
496→ e.target.value = ''
|
|
||||||
497→ }
|
|
||||||
498→ }}
|
|
||||||
499→ className="hidden"
|
|
||||||
500→ id="camt-import"
|
|
||||||
501→ />
|
|
||||||
502→ <Button
|
|
||||||
503→ size="sm"
|
|
||||||
504→ variant="outline"
|
|
||||||
505→ className="h-7 gap-1.5 text-xs"
|
|
||||||
506→ onClick={() => document.getElementById('camt-import')?.click()}
|
|
||||||
507→ >
|
|
||||||
508→ <Banknote className="size-3.5" />
|
|
||||||
509→ CAMT.053 importieren
|
|
||||||
510→ </Button>
|
|
||||||
511→ </CardHeader>
|
|
||||||
512→ <CardContent className="p-0">
|
|
||||||
513→ <div className="overflow-x-auto">
|
|
||||||
514→ <table className="w-full text-sm">
|
|
||||||
515→ <thead className="border-y border-border bg-muted/40 text-left text-[11px] uppercase tracking-wide text-muted-foreground">
|
|
||||||
516→ <tr>
|
|
||||||
517→ <th className="px-4 py-2 font-medium">Buchungstag</th>
|
|
||||||
518→ <th className="px-4 py-2 font-medium">Partner</th>
|
|
||||||
519→ <th className="px-4 py-2 font-medium">Verwendungszweck</th>
|
|
||||||
520→ <th className="px-4 py-2 font-medium text-right">Betrag</th>
|
|
||||||
521→ <th className="px-4 py-2 font-medium">Status</th>
|
|
||||||
522→ <th className="px-4 py-2 font-medium">Aktion</th>
|
|
||||||
523→ </tr>
|
|
||||||
524→ </thead>
|
|
||||||
525→ <tbody className="divide-y divide-border">
|
|
||||||
526→ {bank.transactions.map((tx) => {
|
|
||||||
527→ const isIncome = tx.amountCents > 0
|
|
||||||
528→ return (
|
|
||||||
529→ <tr key={tx.id} className="transition hover:bg-muted/40">
|
|
||||||
530→ <td className="px-4 py-2.5 text-xs">{formatDate(tx.bookingDate)}</td>
|
|
||||||
531→ <td className="px-4 py-2.5 text-xs">
|
|
||||||
532→ <p className="font-medium">{tx.partnerName ?? '—'}</p>
|
|
||||||
533→ {tx.partnerIban && <p className="text-[10px] font-mono text-muted-foreground">{tx.partnerIban}</p>}
|
|
||||||
534→ </td>
|
|
||||||
535→ <td className="px-4 py-2.5">
|
|
||||||
536→ <p className="truncate text-xs">{tx.purpose ?? tx.reference ?? '—'}</p>
|
|
||||||
537→ {tx.matchReason && <p className="text-[10px] text-muted-foreground">{tx.matchReason}</p>}
|
|
||||||
538→ </td>
|
|
||||||
539→ <td className={cn('px-4 py-2.5 text-right text-xs font-semibold tabular-nums', isIncome ? 'text-foreground' : 'text-muted-foreground')}>
|
|
||||||
540→ {isIncome ? '+' : ''}{formatEuro(tx.amountCents)}
|
|
||||||
541→ </td>
|
|
||||||
542→ <td className="px-4 py-2.5">
|
|
||||||
543→ <Badge variant="outline" className={cn(
|
|
||||||
544→ 'text-[10px]',
|
|
||||||
545→ tx.matchedStatus === 'matched' && 'border-foreground/40',
|
|
||||||
546→ tx.matchedStatus === 'suggested' && 'border-foreground/30',
|
|
||||||
547→ )}>
|
|
||||||
548→ {tx.matchedStatus === 'matched' ? 'Zugeordnet' : tx.matchedStatus === 'suggested' ? 'Vorschlag' : 'Offen'}
|
|
||||||
549→ </Badge>
|
|
||||||
550→ </td>
|
|
||||||
551→ <td className="px-4 py-2.5">
|
|
||||||
552→ {tx.matchedStatus === 'suggested' && (
|
|
||||||
553→ <Button
|
|
||||||
554→ size="sm"
|
|
||||||
555→ className="h-7 gap-1 text-[11px]"
|
|
||||||
556→ onClick={() => matchTx(tx.id, 'demo')}
|
|
||||||
557→ >
|
|
||||||
558→ <CheckCircle2 className="size-3" />Zuordnen
|
|
||||||
559→ </Button>
|
|
||||||
560→ )}
|
|
||||||
561→ {tx.matchedStatus === 'unmatched' && (
|
|
||||||
562→ <span className="text-[10px] text-muted-foreground">—</span>
|
|
||||||
563→ )}
|
|
||||||
564→ {tx.matchedStatus === 'matched' && (
|
|
||||||
565→ <CheckCircle2 className="size-4 text-foreground" />
|
|
||||||
566→ )}
|
|
||||||
567→ </td>
|
|
||||||
568→ </tr>
|
|
||||||
569→ )
|
|
||||||
570→ })}
|
|
||||||
571→ </tbody>
|
|
||||||
572→ </table>
|
|
||||||
573→ </div>
|
|
||||||
574→ </CardContent>
|
|
||||||
575→ </Card>
|
|
||||||
576→ </TabsContent>
|
|
||||||
577→
|
|
||||||
578→ {/* Dunning tab */}
|
|
||||||
579→ <TabsContent value="dunning" className="mt-4 space-y-4">
|
|
||||||
580→ <div className="grid grid-cols-1 gap-4 lg:grid-cols-2">
|
|
||||||
581→ <Card>
|
|
||||||
582→ <CardHeader className="pb-2">
|
|
||||||
583→ <CardTitle className="flex items-center gap-2 text-sm">
|
|
||||||
584→ <AlertTriangle className="size-3.5 text-muted-foreground" />
|
|
||||||
585→ Überfällige Rechnungen ({dunning.overdue.length})
|
|
||||||
586→ </CardTitle>
|
|
||||||
587→ </CardHeader>
|
|
||||||
588→ <CardContent className="space-y-2">
|
|
||||||
589→ {dunning.overdue.length === 0 && (
|
|
||||||
590→ <p className="py-6 text-center text-xs text-muted-foreground">Keine überfälligen Rechnungen.</p>
|
|
||||||
591→ )}
|
|
||||||
592→ {dunning.overdue.map((inv) => (
|
|
||||||
593→ <div key={inv.id} className="rounded-md border border-border p-2.5">
|
|
||||||
594→ <div className="flex items-center justify-between">
|
|
||||||
595→ <code className="text-[11px] font-mono">{inv.number}</code>
|
|
||||||
596→ <Badge variant="outline" className="text-[10px]">{inv.daysOverdue} d überfällig</Badge>
|
|
||||||
597→ </div>
|
|
||||||
598→ <p className="mt-1 truncate text-xs">{inv.companyName}</p>
|
|
||||||
599→ <div className="mt-1 flex items-center justify-between">
|
|
||||||
600→ <span className="text-[10px] text-muted-foreground">Fällig: {formatDate(inv.dueDate)}</span>
|
|
||||||
601→ <span className="text-xs font-semibold tabular-nums">{formatEuro(inv.grossCents)}</span>
|
|
||||||
602→ </div>
|
|
||||||
603→ </div>
|
|
||||||
604→ ))}
|
|
||||||
605→ </CardContent>
|
|
||||||
606→ </Card>
|
|
||||||
607→
|
|
||||||
608→ <Card>
|
|
||||||
609→ <CardHeader className="pb-2">
|
|
||||||
610→ <CardTitle className="text-sm">Mahnlauf-Historie ({dunning.runs.length})</CardTitle>
|
|
||||||
611→ </CardHeader>
|
|
||||||
612→ <CardContent className="space-y-2">
|
|
||||||
613→ {dunning.runs.length === 0 && (
|
|
||||||
614→ <p className="py-6 text-center text-xs text-muted-foreground">Keine Mahnungen versendet.</p>
|
|
||||||
615→ )}
|
|
||||||
616→ {dunning.runs.map((run) => (
|
|
||||||
617→ <div key={run.id} className="rounded-md border border-border p-2.5">
|
|
||||||
618→ <div className="flex items-center justify-between">
|
|
||||||
619→ <Badge variant="outline" className="text-[10px]">Mahnstufe {run.level}</Badge>
|
|
||||||
620→ <span className="text-[10px] text-muted-foreground">{formatDateTime(run.sentAt)}</span>
|
|
||||||
621→ </div>
|
|
||||||
622→ <p className="mt-1 truncate text-xs">{run.invoice.company.name} · <code className="font-mono text-[10px]">{run.invoice.number}</code></p>
|
|
||||||
623→ {run.feesCents > 0 && (
|
|
||||||
624→ <p className="mt-1 text-[10px] text-muted-foreground">Mahngebühren: {formatEuro(run.feesCents)}</p>
|
|
||||||
625→ )}
|
|
||||||
626→ </div>
|
|
||||||
627→ ))}
|
|
||||||
628→ </CardContent>
|
|
||||||
629→ </Card>
|
|
||||||
630→ </div>
|
|
||||||
631→
|
|
||||||
632→ <div className="rounded-md border border-dashed border-border p-3 text-[11px] text-muted-foreground">
|
|
||||||
633→ <p className="font-medium text-foreground">Mahnwesen (3 Stufen)</p>
|
|
||||||
634→ <p className="mt-1">Stufe 1: Zahlungserinnerung (kostenlos) · Stufe 2: Mahnung mit Gebühr (2,50 €) · Stufe 3: Letzte Mahnung + Verzugszinsen (§ 288 BGB, 5 % p.a.). Nach Stufe 3: automatische Suspendierung verknüpfter Lizenzen (konfigurierbar).</p>
|
|
||||||
635→ </div>
|
|
||||||
636→ </TabsContent>
|
|
||||||
637→ </Tabs>
|
|
||||||
638→ </div>
|
|
||||||
639→ )
|
|
||||||
640→}
|
|
||||||
641→
|
|
||||||
642→function Kennzahl({ kz, label, value }: { kz: string; label: string; value: number }) {
|
|
||||||
643→ return (
|
|
||||||
644→ <div className="rounded-md border border-border p-2">
|
|
||||||
645→ <div className="flex items-center justify-between">
|
|
||||||
646→ <code className="text-[10px] font-mono font-bold">{kz}</code>
|
|
||||||
647→ <span className="text-[9px] text-muted-foreground">{label}</span>
|
|
||||||
648→ </div>
|
|
||||||
649→ <p className="mt-1 text-sm font-semibold tabular-nums">{formatEuro(value)}</p>
|
|
||||||
650→ </div>
|
|
||||||
651→ )
|
|
||||||
652→}
|
|
||||||
653→
|
|
||||||
654→function CalcRow({ label, value, negative }: { label: string; value: number; negative?: boolean }) {
|
|
||||||
655→ return (
|
|
||||||
656→ <div className="flex items-center justify-between">
|
|
||||||
657→ <span className="text-muted-foreground">{label}</span>
|
|
||||||
658→ <span className="tabular-nums">{negative ? '−' : ''}{formatEuro(value)}</span>
|
|
||||||
659→ </div>
|
|
||||||
660→ )
|
|
||||||
661→}
|
|
||||||
662→
|
|
||||||
@@ -1,895 +0,0 @@
|
|||||||
1→// AOS — Agency Operating System
|
|
||||||
2→// One deployment = one agency (single tenant). SQLite for this build.
|
|
||||||
3→// Money is integer cents, tax rates are basis points. No floats for money.
|
|
||||||
4→
|
|
||||||
5→generator client {
|
|
||||||
6→ provider = "prisma-client-js"
|
|
||||||
7→}
|
|
||||||
8→
|
|
||||||
9→datasource db {
|
|
||||||
10→ provider = "sqlite"
|
|
||||||
11→ url = env("DATABASE_URL")
|
|
||||||
12→}
|
|
||||||
13→
|
|
||||||
14→// ---------------------------------------------------------------------------
|
|
||||||
15→// Platform
|
|
||||||
16→// ---------------------------------------------------------------------------
|
|
||||||
17→
|
|
||||||
18→model User {
|
|
||||||
19→ id String @id @default(cuid())
|
|
||||||
20→ email String @unique
|
|
||||||
21→ name String
|
|
||||||
22→ role String @default("owner") // owner|admin|sales|pm|developer|finance|readonly|client
|
|
||||||
23→ createdAt DateTime @default(now())
|
|
||||||
24→ updatedAt DateTime @updatedAt
|
|
||||||
25→}
|
|
||||||
26→
|
|
||||||
27→// Module registry — installed/enabled/disabled state of each domain module
|
|
||||||
28→model Module {
|
|
||||||
29→ id String @id // crm|leads|projects|licenses|sales-docs|finance|support|...
|
|
||||||
30→ version String @default("1.0.0")
|
|
||||||
31→ enabled Boolean @default(true)
|
|
||||||
32→ installed Boolean @default(true)
|
|
||||||
33→ nav String? // JSON: [{label,route,permission}]
|
|
||||||
34→ events String? // JSON: {emits:[],listens:[]}
|
|
||||||
35→ updatedAt DateTime @updatedAt
|
|
||||||
36→ createdAt DateTime @default(now())
|
|
||||||
37→}
|
|
||||||
38→
|
|
||||||
39→model Setting {
|
|
||||||
40→ key String @id
|
|
||||||
41→ value String // typed at app layer (encrypted secrets handled separately)
|
|
||||||
42→ updatedAt DateTime @updatedAt
|
|
||||||
43→}
|
|
||||||
44→
|
|
||||||
45→model AuditLog {
|
|
||||||
46→ id String @id @default(cuid())
|
|
||||||
47→ actor String? // user id or "system"
|
|
||||||
48→ action String // e.g. "crm.deal:update"
|
|
||||||
49→ entity String
|
|
||||||
50→ entityId String
|
|
||||||
51→ before String? // JSON
|
|
||||||
52→ after String? // JSON
|
|
||||||
53→ hash String? // hash chain
|
|
||||||
54→ createdAt DateTime @default(now())
|
|
||||||
55→}
|
|
||||||
56→
|
|
||||||
57→// ---------------------------------------------------------------------------
|
|
||||||
58→// CRM (Phase 1)
|
|
||||||
59→// ---------------------------------------------------------------------------
|
|
||||||
60→
|
|
||||||
61→model Company {
|
|
||||||
62→ id String @id @default(cuid())
|
|
||||||
63→ name String
|
|
||||||
64→ legalForm String? // GmbH, UG, e.K., GbR, AG, Einzelunternehmen...
|
|
||||||
65→ vatId String? // USt-IdNr
|
|
||||||
66→ registerCourt String?
|
|
||||||
67→ registerNumber String? // HRB ...
|
|
||||||
68→ website String?
|
|
||||||
69→ email String?
|
|
||||||
70→ phone String?
|
|
||||||
71→ city String?
|
|
||||||
72→ zip String?
|
|
||||||
73→ street String?
|
|
||||||
74→ source String? // lead-finder|import|manual|referral|agency|self-signup
|
|
||||||
75→ tags String? // comma separated
|
|
||||||
76→
|
|
||||||
77→ // --- B2B Agency / Reseller (PRD §6.5) ---
|
|
||||||
78→ // A company may be a regular client OR an agency (reseller). Agencies
|
|
||||||
79→ // onboard their own clients and license them; they cannot create invoices
|
|
||||||
80→ // (they must use their own accounting system, e.g. lexoffice/sevdesk via REST API).
|
|
||||||
81→ isAgency Boolean @default(false)
|
|
||||||
82→ // Agency approval: pending (just signed up) → approved (admin allowed) → rejected.
|
|
||||||
83→ agencyStatus String? // null when not an agency; "pending"|"approved"|"rejected"
|
|
||||||
84→ agencyAppliedAt DateTime?
|
|
||||||
85→ agencyApprovedAt DateTime?
|
|
||||||
86→ agencyRejectedAt DateTime?
|
|
||||||
87→ agencyRejectReason String?
|
|
||||||
88→ // Admin-set discount percentage applied to all licenses this agency buys
|
|
||||||
89→ // from us. Range 0-20 (admin decision only). Default 0.
|
|
||||||
90→ agencyDiscountPct Int @default(0)
|
|
||||||
91→ // Self-serve clients belong to an agency. NULL = direct client of ours.
|
|
||||||
92→ parentAgencyId String? // FK to Company(id) — the agency that owns this client
|
|
||||||
93→ parentAgency Company? @relation("AgencyClients", fields: [parentAgencyId], references: [id])
|
|
||||||
94→ agencyClients Company[] @relation("AgencyClients")
|
|
||||||
95→
|
|
||||||
96→ createdAt DateTime @default(now())
|
|
||||||
97→ updatedAt DateTime @updatedAt
|
|
||||||
98→ persons Person[]
|
|
||||||
99→ deals Deal[]
|
|
||||||
100→ leads Lead[]
|
|
||||||
101→ licenses License[]
|
|
||||||
102→ invoices Invoice[]
|
|
||||||
103→ projects Project[]
|
|
||||||
104→ contracts Contract[]
|
|
||||||
105→ expenses Expense[]
|
|
||||||
106→ tickets Ticket[]
|
|
||||||
107→ agencyApplication AgencyApplication?
|
|
||||||
108→}
|
|
||||||
109→
|
|
||||||
110→model Person {
|
|
||||||
111→ id String @id @default(cuid())
|
|
||||||
112→ companyId String?
|
|
||||||
113→ company Company? @relation(fields: [companyId], references: [id])
|
|
||||||
114→ firstName String
|
|
||||||
115→ lastName String
|
|
||||||
116→ email String?
|
|
||||||
117→ phone String?
|
|
||||||
118→ role String? // Geschäftsführer, Marketing, IT...
|
|
||||||
119→ createdAt DateTime @default(now())
|
|
||||||
120→ updatedAt DateTime @updatedAt
|
|
||||||
121→}
|
|
||||||
122→
|
|
||||||
123→model Deal {
|
|
||||||
124→ id String @id @default(cuid())
|
|
||||||
125→ companyId String
|
|
||||||
126→ company Company @relation(fields: [companyId], references: [id])
|
|
||||||
127→ title String
|
|
||||||
128→ valueCents Int @default(0)
|
|
||||||
129→ probability Int @default(0) // 0-100
|
|
||||||
130→ stage String @default("lead") // pipeline stage key
|
|
||||||
131→ expectedClose DateTime?
|
|
||||||
132→ lossReason String?
|
|
||||||
133→ ownerId String?
|
|
||||||
134→ createdAt DateTime @default(now())
|
|
||||||
135→ updatedAt DateTime @updatedAt
|
|
||||||
136→}
|
|
||||||
137→
|
|
||||||
138→// ---------------------------------------------------------------------------
|
|
||||||
139→// Leads Finder (Phase 2)
|
|
||||||
140→// ---------------------------------------------------------------------------
|
|
||||||
141→
|
|
||||||
142→model Lead {
|
|
||||||
143→ id String @id @default(cuid())
|
|
||||||
144→ // discovered company info (may become a Company when approved)
|
|
||||||
145→ companyName String
|
|
||||||
146→ website String?
|
|
||||||
147→ city String?
|
|
||||||
148→ branch String?
|
|
||||||
149→ // audit + scoring
|
|
||||||
150→ score Int @default(0) // 0-100 weighted rule score
|
|
||||||
151→ scoreLabel String? // new-site|redesign|seo|aeo|shop|maintenance|accessibility
|
|
||||||
152→ evidence String? // JSON array of {id,check,status,detail}
|
|
||||||
153→ explanation String? // LLM draft "why this lead" — every claim links to an evidence id
|
|
||||||
154→ suggestedAngle String? // proposed outreach angle
|
|
||||||
155→ status String @default("pending") // pending|approved|rejected|snoozed|converted
|
|
||||||
156→ reviewReason String?
|
|
||||||
157→ source String? // serpapi|tavily|apify|firecrawl
|
|
||||||
158→ radiusKm Int?
|
|
||||||
159→ // when converted, link to CRM company + deal
|
|
||||||
160→ companyId String?
|
|
||||||
161→ company Company? @relation(fields: [companyId], references: [id])
|
|
||||||
162→ createdAt DateTime @default(now())
|
|
||||||
163→ reviewedAt DateTime?
|
|
||||||
164→ updatedAt DateTime @updatedAt
|
|
||||||
165→}
|
|
||||||
166→
|
|
||||||
167→// ---------------------------------------------------------------------------
|
|
||||||
168→// Projects (Phase 3)
|
|
||||||
169→// ---------------------------------------------------------------------------
|
|
||||||
170→
|
|
||||||
171→model Project {
|
|
||||||
172→ id String @id @default(cuid())
|
|
||||||
173→ companyId String
|
|
||||||
174→ company Company @relation(fields: [companyId], references: [id])
|
|
||||||
175→ name String
|
|
||||||
176→ type String // website|shop|app|retainer
|
|
||||||
177→ status String @default("planning") // planning|active|review|done|on-hold|cancelled
|
|
||||||
178→ budgetType String @default("fixed") // fixed|time-materials|retainer
|
|
||||||
179→ budgetHours Int?
|
|
||||||
180→ spentHours Int @default(0)
|
|
||||||
181→ fixedPriceCents Int?
|
|
||||||
182→ startDate DateTime?
|
|
||||||
183→ dueDate DateTime?
|
|
||||||
184→ progress Int @default(0) // 0-100
|
|
||||||
185→ createdAt DateTime @default(now())
|
|
||||||
186→ updatedAt DateTime @updatedAt
|
|
||||||
187→ tasks Task[]
|
|
||||||
188→ timeEntries TimeEntry[]
|
|
||||||
189→ approvals PortalApproval[]
|
|
||||||
190→}
|
|
||||||
191→
|
|
||||||
192→model Task {
|
|
||||||
193→ id String @id @default(cuid())
|
|
||||||
194→ projectId String
|
|
||||||
195→ project Project @relation(fields: [projectId], references: [id])
|
|
||||||
196→ title String
|
|
||||||
197→ description String?
|
|
||||||
198→ status String @default("todo") // todo|in-progress|review|done
|
|
||||||
199→ assignee String?
|
|
||||||
200→ estimateMin Int?
|
|
||||||
201→ priority String @default("medium") // low|medium|high
|
|
||||||
202→ createdAt DateTime @default(now())
|
|
||||||
203→ updatedAt DateTime @updatedAt
|
|
||||||
204→ comments TaskComment[]
|
|
||||||
205→}
|
|
||||||
206→
|
|
||||||
207→model TaskComment {
|
|
||||||
208→ id String @id @default(cuid())
|
|
||||||
209→ taskId String
|
|
||||||
210→ task Task @relation(fields: [taskId], references: [id])
|
|
||||||
211→ author String
|
|
||||||
212→ body String
|
|
||||||
213→ createdAt DateTime @default(now())
|
|
||||||
214→}
|
|
||||||
215→
|
|
||||||
216→model TimeEntry {
|
|
||||||
217→ id String @id @default(cuid())
|
|
||||||
218→ projectId String
|
|
||||||
219→ project Project @relation(fields: [projectId], references: [id])
|
|
||||||
220→ taskId String? // optional link to a specific task
|
|
||||||
221→ userId String?
|
|
||||||
222→ description String
|
|
||||||
223→ minutes Int
|
|
||||||
224→ billable Boolean @default(true)
|
|
||||||
225→ rateCentsPerHour Int?
|
|
||||||
226→ invoiced Boolean @default(false)
|
|
||||||
227→ locked Boolean @default(false) // locked after PM approval
|
|
||||||
228→ date DateTime @default(now())
|
|
||||||
229→ createdAt DateTime @default(now())
|
|
||||||
230→}
|
|
||||||
231→
|
|
||||||
232→// ---------------------------------------------------------------------------
|
|
||||||
233→// Licenses (Phase 4)
|
|
||||||
234→// ---------------------------------------------------------------------------
|
|
||||||
235→
|
|
||||||
236→model License {
|
|
||||||
237→ id String @id @default(cuid())
|
|
||||||
238→ key String @unique
|
|
||||||
239→ companyId String
|
|
||||||
240→ company Company @relation(fields: [companyId], references: [id])
|
|
||||||
241→ product String // e.g. aos-cms, restov1, wp-plugin-xyz
|
|
||||||
242→ plan String // starter|pro|enterprise
|
|
||||||
243→ status String @default("active") // active|suspended|revoked|expired|cancelled
|
|
||||||
244→ // environment: demo licenses are feature-limited / watermarked / time-boxed
|
|
||||||
245→ // and can be promoted to production via the license server.
|
|
||||||
246→ environment String @default("production") // demo|production
|
|
||||||
247→ // Modular licensing: a license may be the "core" license, or a module add-on.
|
|
||||||
248→ // Module licenses reference their parent core license via parentId.
|
|
||||||
249→ parentId String? // null = core license; non-null = module add-on
|
|
||||||
250→ parent License? @relation("LicenseModules", fields: [parentId], references: [id])
|
|
||||||
251→ modules License[] @relation("LicenseModules")
|
|
||||||
252→ // The module key this license grants (only when parentId is set).
|
|
||||||
253→ // e.g. "online-order", "payment", "reservation", "delivery", "table-service"
|
|
||||||
254→ module String? // null for core licenses
|
|
||||||
255→ maxActivations Int @default(1)
|
|
||||||
256→ validUntil DateTime?
|
|
||||||
257→ token String? // Ed25519-signed token (mocked)
|
|
||||||
258→ // Suspend/bloke reason + timestamp — set when status -> suspended.
|
|
||||||
259→ suspendReason String?
|
|
||||||
260→ suspendedAt DateTime?
|
|
||||||
261→
|
|
||||||
262→ // --- B2B Subscription & Billing (German law) ---
|
|
||||||
263→ // Kündigung frist: 3 months (90 days) notice period before the next renewal.
|
|
||||||
264→ // A client can cancel, but the cancellation only takes effect at the end of
|
|
||||||
265→ // the notice period. Set on issuance, defaults to 90 days.
|
|
||||||
266→ noticePeriodDays Int @default(90)
|
|
||||||
267→ // Trial: first 14 days are a free trial. Subscription can be cancelled within
|
|
||||||
268→ // these 14 days at any time with immediate effect (no charge). Day 15 the
|
|
||||||
269→ // paid subscription starts.
|
|
||||||
270→ trialEndsAt DateTime? // null = no trial (e.g. agency-issued)
|
|
||||||
271→ subscriptionStartsAt DateTime? // when the paid subscription begins (trial + 1 day)
|
|
||||||
272→ // Billing cycle: monthly or yearly. Yearly gets a discount on the total.
|
|
||||||
273→ billingCycle String @default("monthly") // monthly|yearly
|
|
||||||
274→ // The price in cents per billing cycle BEFORE any discount.
|
|
||||||
275→ // For monthly: this is the monthly price (e.g. 5000 = 50 €).
|
|
||||||
276→ // For yearly: this is the yearly total (e.g. 60000 = 600 € before yearly discount).
|
|
||||||
277→ priceCents Int @default(0)
|
|
||||||
278→ // Discount percentage applied to this license (0-100).
|
|
||||||
279→ // For agencies: copied from Company.agencyDiscountPct at issue time.
|
|
||||||
280→ // For yearly billing: a yearly discount (e.g. 10%) is applied on top.
|
|
||||||
281→ discountPct Int @default(0)
|
|
||||||
282→ // The effective amount actually charged (priceCents - all discounts).
|
|
||||||
283→ // Computed at issue time and stored for audit/GoBD.
|
|
||||||
284→ netPriceCents Int @default(0)
|
|
||||||
285→ // Cancellation tracking (Kündigung).
|
|
||||||
286→ cancelledAt DateTime? // when the client cancelled
|
|
||||||
287→ cancellationEffectiveAt DateTime? // when the cancellation takes effect (notice period end)
|
|
||||||
288→ cancellationReason String?
|
|
||||||
289→ // Stripe integration (optional — populated when paid via Stripe).
|
|
||||||
290→ stripeCustomerId String?
|
|
||||||
291→ stripeSubscriptionId String?
|
|
||||||
292→ stripePriceId String?
|
|
||||||
293→
|
|
||||||
294→ createdAt DateTime @default(now())
|
|
||||||
295→ activations LicenseActivation[]
|
|
||||||
296→}
|
|
||||||
297→
|
|
||||||
298→model LicenseActivation {
|
|
||||||
299→ id String @id @default(cuid())
|
|
||||||
300→ licenseId String
|
|
||||||
301→ license License @relation(fields: [licenseId], references: [id])
|
|
||||||
302→ domain String
|
|
||||||
303→ fingerprint String?
|
|
||||||
304→ environment String @default("production") // production|staging
|
|
||||||
305→ version String?
|
|
||||||
306→ lastCheck DateTime @default(now())
|
|
||||||
307→ createdAt DateTime @default(now())
|
|
||||||
308→}
|
|
||||||
309→
|
|
||||||
310→// Asset & renewal register (what the agency manages/pays for on behalf of clients)
|
|
||||||
311→model Asset {
|
|
||||||
312→ id String @id @default(cuid())
|
|
||||||
313→ name String
|
|
||||||
314→ type String // domain|hosting|ssl|plugin-seat|saas
|
|
||||||
315→ provider String? // Ionos, Strato, Cloudflare...
|
|
||||||
316→ companyId String? // may be internal asset
|
|
||||||
317→ costCentsPerMonth Int?
|
|
||||||
318→ renewalDate DateTime
|
|
||||||
319→ rebill Boolean @default(false)
|
|
||||||
320→ markupPct Int @default(0)
|
|
||||||
321→ status String @default("active") // active|expiring|expired|cancelled
|
|
||||||
322→ createdAt DateTime @default(now())
|
|
||||||
323→ updatedAt DateTime @updatedAt
|
|
||||||
324→}
|
|
||||||
325→
|
|
||||||
326→// ---------------------------------------------------------------------------
|
|
||||||
327→// Finance (Phase 5)
|
|
||||||
328→// ---------------------------------------------------------------------------
|
|
||||||
329→
|
|
||||||
330→model Invoice {
|
|
||||||
331→ id String @id @default(cuid())
|
|
||||||
332→ number String @unique // gapless, e.g. RE-2026-0001
|
|
||||||
333→ companyId String
|
|
||||||
334→ company Company @relation(fields: [companyId], references: [id])
|
|
||||||
335→ status String @default("draft") // draft|sent|paid|overdue|cancelled|storno
|
|
||||||
336→ type String @default("final") // final|partial|recurring|credit
|
|
||||||
337→ issueDate DateTime @default(now())
|
|
||||||
338→ dueDate DateTime
|
|
||||||
339→ paidDate DateTime?
|
|
||||||
340→ netCents Int @default(0)
|
|
||||||
341→ taxBp Int @default(1900) // 19% as basis points
|
|
||||||
342→ grossCents Int @default(0)
|
|
||||||
343→ // E-Rechnung / compliance
|
|
||||||
344→ zugferd Boolean @default(false)
|
|
||||||
345→ xrechnung Boolean @default(false)
|
|
||||||
346→ datevExported Boolean @default(false)
|
|
||||||
347→ projectId String?
|
|
||||||
348→ createdAt DateTime @default(now())
|
|
||||||
349→ updatedAt DateTime @updatedAt
|
|
||||||
350→ lines InvoiceLine[]
|
|
||||||
351→ dunningRuns DunningRun[]
|
|
||||||
352→}
|
|
||||||
353→
|
|
||||||
354→model InvoiceLine {
|
|
||||||
355→ id String @id @default(cuid())
|
|
||||||
356→ invoiceId String
|
|
||||||
357→ invoice Invoice @relation(fields: [invoiceId], references: [id])
|
|
||||||
358→ description String
|
|
||||||
359→ quantity Int @default(1)
|
|
||||||
360→ unitCents Int
|
|
||||||
361→ totalCents Int
|
|
||||||
362→}
|
|
||||||
363→
|
|
||||||
364→// ---------------------------------------------------------------------------
|
|
||||||
365→// Contracts / Verträge (Phase 5 — adapted from PerfEx Contracts, Germanized)
|
|
||||||
366→// German contract types: Werkvertrag, Dienstvertrag, Wartungsvertrag/SLA,
|
|
||||||
367→// AVV (Auftragsverarbeitungsvertrag), NDA, AVV
|
|
||||||
368→// ---------------------------------------------------------------------------
|
|
||||||
369→
|
|
||||||
370→model Contract {
|
|
||||||
371→ id String @id @default(cuid())
|
|
||||||
372→ number String @unique // gapless, e.g. VER-2026-0001
|
|
||||||
373→ companyId String
|
|
||||||
374→ company Company @relation(fields: [companyId], references: [id])
|
|
||||||
375→ type String // werkvertrag|dienstvertrag|wartung-sla|avv|nda|dpa
|
|
||||||
376→ title String
|
|
||||||
377→ status String @default("draft") // draft|sent|signed|active|expired|terminated
|
|
||||||
378→ valueCents Int @default(0)
|
|
||||||
379→ startDate DateTime?
|
|
||||||
380→ endDate DateTime? // null = unbefristet
|
|
||||||
381→ templateId String? // reference to a stored template
|
|
||||||
382→ dealId String? // optional link to originating deal
|
|
||||||
383→ projectId String? // optional link to project
|
|
||||||
384→ // E-signature hook (mock)
|
|
||||||
385→ signedAt DateTime?
|
|
||||||
386→ signedBy String? // signer name/email
|
|
||||||
387→ signedIp String?
|
|
||||||
388→ signToken String? // unique token for the signing link
|
|
||||||
389→ notes String?
|
|
||||||
390→ createdAt DateTime @default(now())
|
|
||||||
391→ updatedAt DateTime @updatedAt
|
|
||||||
392→}
|
|
||||||
393→
|
|
||||||
394→// ---------------------------------------------------------------------------
|
|
||||||
395→// Expenses / Ausgaben (adapted from PerfEx Expenses, Germanized for DATEV)
|
|
||||||
396→// ---------------------------------------------------------------------------
|
|
||||||
397→
|
|
||||||
398→model Expense {
|
|
||||||
399→ id String @id @default(cuid())
|
|
||||||
400→ number String @unique // gapless, e.g. AUS-2026-0001
|
|
||||||
401→ categoryId String // reise|software|hardware|fremdleistung|buero|marketing
|
|
||||||
402→ vendor String? // supplier / merchant
|
|
||||||
403→ description String
|
|
||||||
404→ amountCents Int // net amount
|
|
||||||
405→ taxBp Int @default(1900)
|
|
||||||
406→ grossCents Int @default(0)
|
|
||||||
407→ date DateTime @default(now())
|
|
||||||
408→ // linking
|
|
||||||
409→ companyId String? // customer this is billable to
|
|
||||||
410→ company Company? @relation(fields: [companyId], references: [id])
|
|
||||||
411→ projectId String? // project this relates to
|
|
||||||
412→ billable Boolean @default(false) // convert to customer invoice
|
|
||||||
413→ markupPct Int @default(0) // markup when re-billed
|
|
||||||
414→ // recurring
|
|
||||||
415→ recurring Boolean @default(false)
|
|
||||||
416→ recurringInterval String? // monthly|quarterly|yearly
|
|
||||||
417→ // receipt + export
|
|
||||||
418→ receiptHash String? // SHA-256 of stored receipt file (content-addressed)
|
|
||||||
419→ datevExported Boolean @default(false)
|
|
||||||
420→ // conversion
|
|
||||||
421→ convertedInvoiceId String? // link to the invoice created from this expense
|
|
||||||
422→ status String @default("recorded") // recorded|approved|invoiced|rejected
|
|
||||||
423→ createdAt DateTime @default(now())
|
|
||||||
424→ updatedAt DateTime @updatedAt
|
|
||||||
425→}
|
|
||||||
426→
|
|
||||||
427→// ---------------------------------------------------------------------------
|
|
||||||
428→// Support Tickets (PRD §6.7 + PerfEx Support Tickets + AI Integration)
|
|
||||||
429→// ---------------------------------------------------------------------------
|
|
||||||
430→
|
|
||||||
431→model Ticket {
|
|
||||||
432→ id String @id @default(cuid())
|
|
||||||
433→ number String @unique // gapless, e.g. TKT-2026-0001
|
|
||||||
434→ subject String
|
|
||||||
435→ status String @default("open") // open|pending|resolved|closed
|
|
||||||
436→ priority String @default("normal") // low|normal|high|urgent
|
|
||||||
437→ categoryId String // bug|anfrage|aenderung|konto|rechnung|hosting
|
|
||||||
438→ companyId String
|
|
||||||
439→ company Company @relation(fields: [companyId], references: [id])
|
|
||||||
440→ projectId String?
|
|
||||||
441→ licenseId String?
|
|
||||||
442→ // --- Ticket routing (agency model) ---
|
|
||||||
443→ // If the client belongs to an agency, the ticket is routed to that agency
|
|
||||||
444→ // (agencyCompanyId). The agency handles it; only if the agency escalates
|
|
||||||
445→ // does the ticket reach us (routedToAgency = false, escalatedToAdmin = true).
|
|
||||||
446→ agencyCompanyId String? // the reseller that owns this client (if any)
|
|
||||||
447→ routedToAgency Boolean @default(false) // ticket sent to agency inbox
|
|
||||||
448→ escalatedToAdmin Boolean @default(false) // agency escalated to us
|
|
||||||
449→ escalatedAt DateTime?
|
|
||||||
450→ // SLA
|
|
||||||
451→ slaResponseHours Int @default(8) // first response target
|
|
||||||
452→ slaResolveHours Int @default(48) // resolution target
|
|
||||||
453→ slaRespondedAt DateTime?
|
|
||||||
454→ slaResolvedAt DateTime?
|
|
||||||
455→ // AI
|
|
||||||
456→ aiSummary String? // LLM-generated summary of the conversation
|
|
||||||
457→ // assignee
|
|
||||||
458→ assignee String?
|
|
||||||
459→ createdAt DateTime @default(now())
|
|
||||||
460→ updatedAt DateTime @updatedAt
|
|
||||||
461→ messages TicketMessage[]
|
|
||||||
462→}
|
|
||||||
463→
|
|
||||||
464→model TicketMessage {
|
|
||||||
465→ id String @id @default(cuid())
|
|
||||||
466→ ticketId String
|
|
||||||
467→ ticket Ticket @relation(fields: [ticketId], references: [id])
|
|
||||||
468→ fromType String // customer|staff|system|agency
|
|
||||||
469→ fromName String
|
|
||||||
470→ body String
|
|
||||||
471→ createdAt DateTime @default(now())
|
|
||||||
472→}
|
|
||||||
473→
|
|
||||||
474→// ---------------------------------------------------------------------------
|
|
||||||
475→// Agency Applications (PRD §6.5 — reseller onboarding)
|
|
||||||
476→// ---------------------------------------------------------------------------
|
|
||||||
477→// When a company signs up, they may choose to become an agency (reseller).
|
|
||||||
478→// The application is stored here and awaits admin approval. On approval,
|
|
||||||
479→// the Company.isAgency flag is set, Company.agencyStatus = "approved", and
|
|
||||||
480→// an email is sent to the applicant with their discount percentage.
|
|
||||||
481→model AgencyApplication {
|
|
||||||
482→ id String @id @default(cuid())
|
|
||||||
483→ companyId String @unique
|
|
||||||
484→ company Company @relation(fields: [companyId], references: [id])
|
|
||||||
485→ status String @default("pending") // pending|approved|rejected
|
|
||||||
486→ // Discount the admin grants this agency (0-20%). Applied to all licenses
|
|
||||||
487→ // the agency buys from us. Admin-only decision.
|
|
||||||
488→ discountPct Int @default(0) // 0-20
|
|
||||||
489→ // Business justification fields (filled by the applicant)
|
|
||||||
490→ businessModel String? // e.g. "Webdesign agency", "IT consultant"
|
|
||||||
491→ expectedClientVolume String? // e.g. "10-20 clients"
|
|
||||||
492→ referredBy String? // how did they hear about us
|
|
||||||
493→ // Review
|
|
||||||
494→ reviewedBy String?
|
|
||||||
495→ reviewedAt DateTime?
|
|
||||||
496→ rejectReason String?
|
|
||||||
497→ appliedAt DateTime @default(now())
|
|
||||||
498→ createdAt DateTime @default(now())
|
|
||||||
499→ updatedAt DateTime @updatedAt
|
|
||||||
500→}
|
|
||||||
501→
|
|
||||||
502→// ---------------------------------------------------------------------------
|
|
||||||
503→// Estimates / Angebote (PRD §6.5 sales-docs — quotes that convert to invoice)
|
|
||||||
504→// ---------------------------------------------------------------------------
|
|
||||||
505→
|
|
||||||
506→model Estimate {
|
|
||||||
507→ id String @id @default(cuid())
|
|
||||||
508→ number String @unique // gapless, e.g. AN-2026-0001
|
|
||||||
509→ companyId String
|
|
||||||
510→ dealId String? // originating deal
|
|
||||||
511→ projectId String? // creates project when accepted
|
|
||||||
512→ subject String
|
|
||||||
513→ status String @default("draft") // draft|sent|accepted|rejected|expired
|
|
||||||
514→ validUntil DateTime?
|
|
||||||
515→ issueDate DateTime @default(now())
|
|
||||||
516→ acceptedAt DateTime?
|
|
||||||
517→ acceptedBy String?
|
|
||||||
518→ notes String?
|
|
||||||
519→ netCents Int @default(0)
|
|
||||||
520→ taxBp Int @default(1900)
|
|
||||||
521→ grossCents Int @default(0)
|
|
||||||
522→ // AI
|
|
||||||
523→ aiDraftFromBrief String? // flag: was this drafted from a brief via AI
|
|
||||||
524→ createdAt DateTime @default(now())
|
|
||||||
525→ updatedAt DateTime @updatedAt
|
|
||||||
526→ lines EstimateLine[]
|
|
||||||
527→}
|
|
||||||
528→
|
|
||||||
529→model EstimateLine {
|
|
||||||
530→ id String @id @default(cuid())
|
|
||||||
531→ estimateId String
|
|
||||||
532→ estimate Estimate @relation(fields: [estimateId], references: [id])
|
|
||||||
533→ description String
|
|
||||||
534→ quantity Int @default(1)
|
|
||||||
535→ unitCents Int
|
|
||||||
536→ totalCents Int
|
|
||||||
537→}
|
|
||||||
538→
|
|
||||||
539→// ---------------------------------------------------------------------------
|
|
||||||
540→// Accounting / Buchhaltung (adapted from Haben, German-law compliant)
|
|
||||||
541→// VAT return (Umsatzsteuer-Voranmeldung), EÜR, bank reconciliation, dunning.
|
|
||||||
542→// PRD §6.6: double-entry + ELSTER out of scope; this covers the agency-facing
|
|
||||||
543→// compliance layer (compute, validate, mock-submit) + bank matching.
|
|
||||||
544→// ---------------------------------------------------------------------------
|
|
||||||
545→
|
|
||||||
546→// Bank transactions imported from CAMT.053 or PSD2 (FinTS).
|
|
||||||
547→model BankTransaction {
|
|
||||||
548→ id String @id @default(cuid())
|
|
||||||
549→ amountCents Int // signed: + credit (incoming), - debit (outgoing)
|
|
||||||
550→ bookingDate DateTime
|
|
||||||
551→ valueDate DateTime
|
|
||||||
552→ partnerName String?
|
|
||||||
553→ partnerIban String?
|
|
||||||
554→ reference String?
|
|
||||||
555→ purpose String?
|
|
||||||
556→ matchedInvoiceId String?
|
|
||||||
557→ matchedStatus String @default("unmatched")
|
|
||||||
558→ matchReason String?
|
|
||||||
559→ importBatchId String?
|
|
||||||
560→ importedAt DateTime @default(now())
|
|
||||||
561→ createdAt DateTime @default(now())
|
|
||||||
562→}
|
|
||||||
563→
|
|
||||||
564→// VAT pre-registration periods (Umsatzsteuer-Voranmeldung)
|
|
||||||
565→model VatReturn {
|
|
||||||
566→ id String @id @default(cuid())
|
|
||||||
567→ periodYear Int
|
|
||||||
568→ periodMonth Int
|
|
||||||
569→ periodType String @default("monthly")
|
|
||||||
570→ status String @default("draft")
|
|
||||||
571→ k81StandardNetCents Int @default(0)
|
|
||||||
572→ k86ReducedNetCents Int @default(0)
|
|
||||||
573→ k66TaxFreeCents Int @default(0)
|
|
||||||
574→ k83TaxStandardCents Int @default(0)
|
|
||||||
575→ k65TaxReducedCents Int @default(0)
|
|
||||||
576→ k37InputTaxCents Int @default(0)
|
|
||||||
577→ outputTaxCents Int @default(0)
|
|
||||||
578→ inputTaxCents Int @default(0)
|
|
||||||
579→ payableCents Int @default(0)
|
|
||||||
580→ submittedAt DateTime?
|
|
||||||
581→ elsterRef String?
|
|
||||||
582→ acceptedAt DateTime?
|
|
||||||
583→ notes String?
|
|
||||||
584→ createdAt DateTime @default(now())
|
|
||||||
585→ updatedAt DateTime @updatedAt
|
|
||||||
586→}
|
|
||||||
587→
|
|
||||||
588→// Dunning levels for overdue invoices (Mahnwesen)
|
|
||||||
589→model DunningRun {
|
|
||||||
590→ id String @id @default(cuid())
|
|
||||||
591→ invoiceId String
|
|
||||||
592→ invoice Invoice @relation(fields: [invoiceId], references: [id])
|
|
||||||
593→ level Int
|
|
||||||
594→ status String @default("sent")
|
|
||||||
595→ feesCents Int @default(0)
|
|
||||||
596→ sentAt DateTime @default(now())
|
|
||||||
597→ createdAt DateTime @default(now())
|
|
||||||
598→}
|
|
||||||
599→
|
|
||||||
600→// ---------------------------------------------------------------------------
|
|
||||||
601→// Public API (PRD §5.5) — API tokens with scopes, webhooks with HMAC signing
|
|
||||||
602→// ---------------------------------------------------------------------------
|
|
||||||
603→
|
|
||||||
604→model ApiToken {
|
|
||||||
605→ id String @id @default(cuid())
|
|
||||||
606→ name String
|
|
||||||
607→ // The token shown to the user ONCE. We store only its SHA-256 hash so a
|
|
||||||
608→ // compromised DB does not leak usable tokens (like GitHub PATs).
|
|
||||||
609→ tokenHash String @unique
|
|
||||||
610→ tokenPrefix String // first 8 chars for identification (e.g. "aos_abc1…")
|
|
||||||
611→ scopes String // JSON array of scope strings, e.g. ["crm.company:read","finance.invoice:read"]
|
|
||||||
612→ lastUsedAt DateTime?
|
|
||||||
613→ expiresAt DateTime?
|
|
||||||
614→ revokedAt DateTime?
|
|
||||||
615→ createdAt DateTime @default(now())
|
|
||||||
616→}
|
|
||||||
617→
|
|
||||||
618→model Webhook {
|
|
||||||
619→ id String @id @default(cuid())
|
|
||||||
620→ url String // https endpoint to deliver to
|
|
||||||
621→ events String // JSON array, e.g. ["invoice.paid","contract.signed"]
|
|
||||||
622→ secret String // HMAC signing secret (stored, needed to verify signatures)
|
|
||||||
623→ active Boolean @default(true)
|
|
||||||
624→ // delivery stats
|
|
||||||
625→ sentCount Int @default(0)
|
|
||||||
626→ failCount Int @default(0)
|
|
||||||
627→ lastSentAt DateTime?
|
|
||||||
628→ lastStatus Int? // last HTTP status code received
|
|
||||||
629→ createdAt DateTime @default(now())
|
|
||||||
630→ updatedAt DateTime @updatedAt
|
|
||||||
631→}
|
|
||||||
632→
|
|
||||||
633→// ---------------------------------------------------------------------------
|
|
||||||
634→// Client Portal (PRD §6.3) — milestone approvals with evidence
|
|
||||||
635→// ---------------------------------------------------------------------------
|
|
||||||
636→
|
|
||||||
637→model PortalApproval {
|
|
||||||
638→ id String @id @default(cuid())
|
|
||||||
639→ projectId String
|
|
||||||
640→ project Project @relation(fields: [projectId], references: [id])
|
|
||||||
641→ title String // e.g. "Design-Entwürfe freigeben"
|
|
||||||
642→ description String?
|
|
||||||
643→ status String @default("pending") // pending|approved|rejected|changes-requested
|
|
||||||
644→ // evidence (PRD §6.3: "approvals with timestamp and IP evidence")
|
|
||||||
645→ decidedAt DateTime?
|
|
||||||
646→ decidedBy String? // client name
|
|
||||||
647→ decidedIp String? // real client IP at decision time
|
|
||||||
648→ decision String? // free-text reason/feedback
|
|
||||||
649→ // content hash for tamper-evidence
|
|
||||||
650→ contentHash String?
|
|
||||||
651→ createdAt DateTime @default(now())
|
|
||||||
652→ updatedAt DateTime @updatedAt
|
|
||||||
653→}
|
|
||||||
654→
|
|
||||||
655→// ---------------------------------------------------------------------------
|
|
||||||
656→// Knowledge Base (PRD §6.7) — internal + client-facing docs with versioning
|
|
||||||
657→// ---------------------------------------------------------------------------
|
|
||||||
658→
|
|
||||||
659→model Article {
|
|
||||||
660→ id String @id @default(cuid())
|
|
||||||
661→ slug String @unique
|
|
||||||
662→ title String
|
|
||||||
663→ category String // onboarding|launch-checklist|templates|handbuch|faq
|
|
||||||
664→ visibility String @default("internal") // internal|client|public
|
|
||||||
665→ excerpt String?
|
|
||||||
666→ content String // markdown
|
|
||||||
667→ tags String? // comma separated
|
|
||||||
668→ version Int @default(1)
|
|
||||||
669→ authorId String?
|
|
||||||
670→ authorName String?
|
|
||||||
671→ published Boolean @default(true)
|
|
||||||
672→ viewCount Int @default(0)
|
|
||||||
673→ createdAt DateTime @default(now())
|
|
||||||
674→ updatedAt DateTime @updatedAt
|
|
||||||
675→}
|
|
||||||
676→
|
|
||||||
677→// ---------------------------------------------------------------------------
|
|
||||||
678→// Haben-cloned features: Belege, Pauschalen, Anlagen/AfA, Kasse
|
|
||||||
679→// ---------------------------------------------------------------------------
|
|
||||||
680→
|
|
||||||
681→// Belege (receipts/documents) — content-addressed storage (PRD §5.5)
|
|
||||||
682→model Beleg {
|
|
||||||
683→ id String @id @default(cuid())
|
|
||||||
684→ number String @unique // gapless, e.g. BEL-2026-0001
|
|
||||||
685→ type String // rechnung-eingang|rechnung-ausgang|quittung|kassenbeleg|bankbeleg|sonstiges
|
|
||||||
686→ // content-addressed (SHA-256 hash of the file content)
|
|
||||||
687→ fileHash String @unique
|
|
||||||
688→ fileName String
|
|
||||||
689→ fileType String // application/pdf, image/jpeg, etc.
|
|
||||||
690→ fileSizeBytes Int
|
|
||||||
691→ // metadata extracted from the document
|
|
||||||
692→ vendor String? // Rechnungssteller
|
|
||||||
693→ invoiceNumber String? // Rechnungsnummer des Lieferanten
|
|
||||||
694→ amountCents Int? // Bruttobetrag auf dem Beleg
|
|
||||||
695→ amountNetCents Int? // Netto (falls extrahiert)
|
|
||||||
696→ taxBp Int? // USt %
|
|
||||||
697→ bookingDate DateTime?
|
|
||||||
698→ // linking
|
|
||||||
699→ expenseId String? // link to Expense if billable
|
|
||||||
700→ invoiceId String? // link to Invoice if outgoing
|
|
||||||
701→ // OCR / AI
|
|
||||||
702→ ocrText String? // extracted text (optional, via Jina/AI)
|
|
||||||
703→ // GoBD
|
|
||||||
704→ archivedAt DateTime?
|
|
||||||
705→ retentionUntil DateTime? // Aufbewahrung bis
|
|
||||||
706→ createdAt DateTime @default(now())
|
|
||||||
707→}
|
|
||||||
708→
|
|
||||||
709→// Pauschalen (flat-rate allowances) — Homeoffice, Kilometer, Verpflegung
|
|
||||||
710→model Pauschale {
|
|
||||||
711→ id String @id @default(cuid())
|
|
||||||
712→ type String // homeoffice|kilometer|verpflegung
|
|
||||||
713→ // homeoffice: €4.17/day (2026: €6.92/day up to €1.260/year)
|
|
||||||
714→ // kilometer: €0.30/km (car), €0.38/km (car w/ pass), or actual
|
|
||||||
715→ // verpflegung: €14 (8-14h), €24 (>14h, same day), €28 (overnight)
|
|
||||||
716→ date DateTime
|
|
||||||
717→ userId String? // employee
|
|
||||||
718→ amountCents Int // computed amount
|
|
||||||
719→ // details per type
|
|
||||||
720→ days Int? // homeoffice: 1; verpflegung: 1
|
|
||||||
721→ km Int? // kilometer: distance
|
|
||||||
722→ vehicleType String? // kilometer: auto|rad|fuss
|
|
||||||
723→ tripPurpose String? // kilometer: geschäftlich|fortbildung|umzug
|
|
||||||
724→ hoursAway Int? // verpflegung: hours away from office
|
|
||||||
725→ overnight Boolean @default(false) // verpflegung: overnight stay
|
|
||||||
726→ description String?
|
|
||||||
727→ projectId String? // link to project if billable
|
|
||||||
728→ expenseId String? // link to generated expense
|
|
||||||
729→ createdAt DateTime @default(now())
|
|
||||||
730→}
|
|
||||||
731→
|
|
||||||
732→// Anlagenverzeichnis & AfA (asset register + depreciation)
|
|
||||||
733→model Anlage {
|
|
||||||
734→ id String @id @default(cuid())
|
|
||||||
735→ number String @unique // e.g. ANL-2026-0001
|
|
||||||
736→ name String // "MacBook Pro 16"
|
|
||||||
737→ category String // hardware|software|mobiliar|fahrzeug|immobilie
|
|
||||||
738→ // acquisition
|
|
||||||
739→ purchaseDate DateTime
|
|
||||||
740→ purchaseCostCents Int // Anschaffungskosten (netto)
|
|
||||||
741→ taxBp Int @default(1900) // USt bei Anschaffung
|
|
||||||
742→ // AfA (depreciation)
|
|
||||||
743→ afaMethod String @default("linear") // linear|degressiv
|
|
||||||
744→ usefulLifeYears Int @default(3) // Nutzungsdauer (AfA-Tabelle)
|
|
||||||
745→ salvageValueCents Int @default(0) // Restwert
|
|
||||||
746→ // GWG (Geringwertiger Wirtschaftsgüter ≤ €800 net → Sofortabschreibung)
|
|
||||||
747→ isGWG Boolean @default(false) // GWG ≤ €800 → immediate expense
|
|
||||||
748→ // Sammelposten (€251-€1000 → Sammelabschreibung über 5 Jahre)
|
|
||||||
749→ isSammelposten Boolean @default(false)
|
|
||||||
750→ // computed
|
|
||||||
751→ annualAfaCents Int @default(0) // jährliche AfA
|
|
||||||
752→ accumulatedAfaCents Int @default(0) // kumulierte AfA
|
|
||||||
753→ bookValueCents Int @default(0) // Buchwert (purchase - accumulated AfA)
|
|
||||||
754→ // status
|
|
||||||
755→ status String @default("active") // active|sold|scrapped|fully-depreciated
|
|
||||||
756→ soldDate DateTime?
|
|
||||||
757→ soldPriceCents Int?
|
|
||||||
758→ createdAt DateTime @default(now())
|
|
||||||
759→ updatedAt DateTime @updatedAt
|
|
||||||
760→}
|
|
||||||
761→
|
|
||||||
762→// Kassenbuch (cash book for Barzahlungen — § 146 AO, § 22 UStG)
|
|
||||||
763→model KassenbuchEntry {
|
|
||||||
764→ id String @id @default(cuid())
|
|
||||||
765→ number String @unique // gapless, e.g. KAS-2026-0001
|
|
||||||
766→ date DateTime
|
|
||||||
767→ type String // einnahme|ausgabe
|
|
||||||
768→ description String
|
|
||||||
769→ amountCents Int // signed: + for einnahme, - for ausgabe
|
|
||||||
770→ taxBp Int? // USt % (if applicable)
|
|
||||||
771→ taxFree Boolean @default(false) // steuerfrei
|
|
||||||
772→ // receipt link
|
|
||||||
773→ belegId String? // link to Beleg (Kassenbeleg)
|
|
||||||
774→ // balance after this entry (laufender Kassenstand)
|
|
||||||
775→ balanceCents Int @default(0)
|
|
||||||
776→ // GoBD: Kassenbuch ist unveränderlich (elektronische Aufzeichnung)
|
|
||||||
777→ createdAt DateTime @default(now())
|
|
||||||
778→}
|
|
||||||
779→
|
|
||||||
780→
|
|
||||||
781→// ---------------------------------------------------------------------------
|
|
||||||
782→// SKR03/SKR04 Kontenrahmen + doppelte Buchführung (Haben clone)
|
|
||||||
783→// ---------------------------------------------------------------------------
|
|
||||||
784→
|
|
||||||
785→model Konto {
|
|
||||||
786→ id String @id @default(cuid())
|
|
||||||
787→ nummer String @unique
|
|
||||||
788→ name String
|
|
||||||
789→ rahmen String @default("skr04")
|
|
||||||
790→ art String // aktiv|passiv|ertrag|aufwand
|
|
||||||
791→ parentId String?
|
|
||||||
792→ locked Boolean @default(false)
|
|
||||||
793→ sollBuchungen Buchungssatz[] @relation("SollKonto")
|
|
||||||
794→ habenBuchungen Buchungssatz[] @relation("HabenKonto")
|
|
||||||
795→ createdAt DateTime @default(now())
|
|
||||||
796→}
|
|
||||||
797→
|
|
||||||
798→model Buchungssatz {
|
|
||||||
799→ id String @id @default(cuid())
|
|
||||||
800→ number String @unique
|
|
||||||
801→ belegdatum DateTime
|
|
||||||
802→ buchungsdatum DateTime @default(now())
|
|
||||||
803→ sollKontoId String
|
|
||||||
804→ sollKonto Konto @relation("SollKonto", fields: [sollKontoId], references: [id])
|
|
||||||
805→ habenKontoId String
|
|
||||||
806→ habenKonto Konto @relation("HabenKonto", fields: [habenKontoId], references: [id])
|
|
||||||
807→ betragCents Int
|
|
||||||
808→ buchungstext String
|
|
||||||
809→ belegNummer String?
|
|
||||||
810→ steuerBp Int?
|
|
||||||
811→ steuerKontoId String?
|
|
||||||
812→ festgeschrieben Boolean @default(false)
|
|
||||||
813→ festgeschriebenAt DateTime?
|
|
||||||
814→ festgeschriebenHash String?
|
|
||||||
815→ belegId String?
|
|
||||||
816→ invoiceId String?
|
|
||||||
817→ expenseId String?
|
|
||||||
818→ reverseCharge Boolean @default(false)
|
|
||||||
819→ par19UStG Boolean @default(false)
|
|
||||||
820→ createdAt DateTime @default(now())
|
|
||||||
821→}
|
|
||||||
822→
|
|
||||||
823→model EuerEntry {
|
|
||||||
824→ id String @id @default(cuid())
|
|
||||||
825→ jahr Int
|
|
||||||
826→ zeile String
|
|
||||||
827→ label String
|
|
||||||
828→ art String
|
|
||||||
829→ betragCents Int
|
|
||||||
830→ kontoNummern String?
|
|
||||||
831→ createdAt DateTime @default(now())
|
|
||||||
832→}
|
|
||||||
833→
|
|
||||||
834→model Jahreserklaerung {
|
|
||||||
835→ id String @id @default(cuid())
|
|
||||||
836→ jahr Int
|
|
||||||
837→ art String
|
|
||||||
838→ status String @default("draft")
|
|
||||||
839→ kennzahlen String?
|
|
||||||
840→ elsterRef String?
|
|
||||||
841→ submittedAt DateTime?
|
|
||||||
842→ acceptedAt DateTime?
|
|
||||||
843→ notes String?
|
|
||||||
844→ createdAt DateTime @default(now())
|
|
||||||
845→ updatedAt DateTime @updatedAt
|
|
||||||
846→}
|
|
||||||
847→
|
|
||||||
848→model Jahresarchiv {
|
|
||||||
849→ id String @id @default(cuid())
|
|
||||||
850→ jahr Int
|
|
||||||
851→ prevArchivId String?
|
|
||||||
852→ archivHash String @unique
|
|
||||||
853→ buchungenCount Int
|
|
||||||
854→ belegeCount Int
|
|
||||||
855→ rechnungenCount Int
|
|
||||||
856→ zipFileName String
|
|
||||||
857→ zipSizeBytes Int
|
|
||||||
858→ createdDate DateTime @default(now())
|
|
||||||
859→ createdBy String
|
|
||||||
860→ notes String?
|
|
||||||
861→}
|
|
||||||
862→
|
|
||||||
863→// ---------------------------------------------------------------------------
|
|
||||||
864→// Custom Fields (PRD §5.5: "Custom fields: JSONB with a schema table per entity")
|
|
||||||
865→// ---------------------------------------------------------------------------
|
|
||||||
866→
|
|
||||||
867→model CustomFieldDef {
|
|
||||||
868→ id String @id @default(cuid())
|
|
||||||
869→ entityType String // company|person|deal|project|invoice|ticket|contract
|
|
||||||
870→ key String // field key, e.g. "branche", "lead_source_detail"
|
|
||||||
871→ label String // display label, e.g. "Branche"
|
|
||||||
872→ type String // string|number|boolean|date|select|multiselect
|
|
||||||
873→ options String? // JSON array for select/multiselect
|
|
||||||
874→ required Boolean @default(false)
|
|
||||||
875→ sortOrder Int @default(0)
|
|
||||||
876→ values CustomFieldValue[]
|
|
||||||
877→ createdAt DateTime @default(now())
|
|
||||||
878→ updatedAt DateTime @updatedAt
|
|
||||||
879→
|
|
||||||
880→ @@unique([entityType, key])
|
|
||||||
881→}
|
|
||||||
882→
|
|
||||||
883→model CustomFieldValue {
|
|
||||||
884→ id String @id @default(cuid())
|
|
||||||
885→ fieldDefId String
|
|
||||||
886→ fieldDef CustomFieldDef @relation(fields: [fieldDefId], references: [id])
|
|
||||||
887→ entityType String // denormalized for fast lookup
|
|
||||||
888→ entityId String // the entity's ID
|
|
||||||
889→ value String? // JSON-encoded value (string, number, bool, array)
|
|
||||||
890→ createdAt DateTime @default(now())
|
|
||||||
891→ updatedAt DateTime @updatedAt
|
|
||||||
892→
|
|
||||||
893→ @@unique([entityType, entityId, fieldDefId])
|
|
||||||
894→}
|
|
||||||
895→
|
|
||||||
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
@@ -1,426 +0,0 @@
|
|||||||
1→Initializing deployment
|
|
||||||
2→Cloning Repo github.com/cetinmustafa83/aos.git to /etc/dokploy/applications/dfm-aos-lgbcnc/code: ✅
|
|
||||||
3→Cloning into '/etc/dokploy/applications/dfm-aos-lgbcnc/code'...
|
|
||||||
4→remote: Enumerating objects: 1836, done.
|
|
||||||
5→remote: Counting objects: 0% (1/1836)
remote: Counting objects: 1% (19/1836)
remote: Counting objects: 2% (37/1836)
remote: Counting objects: 3% (56/1836)
remote: Counting objects: 4% (74/1836)
remote: Counting objects: 5% (92/1836)
remote: Counting objects: 6% (111/1836)
remote: Counting objects: 7% (129/1836)
remote: Counting objects: 8% (147/1836)
remote: Counting objects: 9% (166/1836)
remote: Counting objects: 10% (184/1836)
remote: Counting objects: 11% (202/1836)
remote: Counting objects: 12% (221/1836)
remote: Counting objects: 13% (239/1836)
remote: Counting objects: 14% (258/1836)
remote: Counting objects: 15% (276/1836)
remote: Counting objects: 16% (294/1836)
remote: Counting objects: 17% (313/1836)
remote: Counting objects: 18% (331/1836)
remote: Counting objects: 19% (349/1836)
remote: Counting objects: 20% (368/1836)
remote: Counting objects: 21% (386/1836)
remote: Counting objects: 22% (404/1836)
remote: Counting objects: 23% (423/1836)
remote: Counting objects: 24% (441/1836)
remote: Counting objects: 25% (459/1836)
remote: Counting objects: 26% (478/1836)
remote: Counting objects: 27% (496/1836)
remote: Counting objects: 28% (515/1836)
remote: Counting objects: 29% (533/1836)
remote: Counting objects: 30% (551/1836)
remote: Counting objects: 31% (570/1836)
remote: Counting objects: 32% (588/1836)
remote: Counting objects: 33% (606/1836)
remote: Counting objects: 34% (625/1836)
remote: Counting objects: 35% (643/1836)
remote: Counting objects: 36% (661/1836)
remote: Counting objects: 37% (680/1836)
remote: Counting objects: 38% (698/1836)
remote: Counting objects: 39% (717/1836)
remote: Counting objects: 40% (735/1836)
remote: Counting objects: 41% (753/1836)
remote: Counting objects: 42% (772/1836)
remote: Counting objects: 43% (790/1836)
remote: Counting objects: 44% (808/1836)
remote: Counting objects: 45% (827/1836)
remote: Counting objects: 46% (845/1836)
remote: Counting objects: 47% (863/1836)
remote: Counting objects: 48% (882/1836)
remote: Counting objects: 49% (900/1836)
remote: Counting objects: 50% (918/1836)
remote: Counting objects: 51% (937/1836)
remote: Counting objects: 52% (955/1836)
remote: Counting objects: 53% (974/1836)
remote: Counting objects: 54% (992/1836)
remote: Counting objects: 55% (1010/1836)
remote: Counting objects: 56% (1029/1836)
remote: Counting objects: 57% (1047/1836)
remote: Counting objects: 58% (1065/1836)
remote: Counting objects: 59% (1084/1836)
remote: Counting objects: 60% (1102/1836)
remote: Counting objects: 61% (1120/1836)
remote: Counting objects: 62% (1139/1836)
remote: Counting objects: 63% (1157/1836)
remote: Counting objects: 64% (1176/1836)
remote: Counting objects: 65% (1194/1836)
remote: Counting objects: 66% (1212/1836)
remote: Counting objects: 67% (1231/1836)
remote: Counting objects: 68% (1249/1836)
remote: Counting objects: 69% (1267/1836)
remote: Counting objects: 70% (1286/1836)
remote: Counting objects: 71% (1304/1836)
remote: Counting objects: 72% (1322/1836)
remote: Counting objects: 73% (1341/1836)
remote: Counting objects: 74% (1359/1836)
remote: Counting objects: 75% (1377/1836)
remote: Counting objects: 76% (1396/1836)
remote: Counting objects: 77% (1414/1836)
remote: Counting objects: 78% (1433/1836)
remote: Counting objects: 79% (1451/1836)
remote: Counting objects: 80% (1469/1836)
remote: Counting objects: 81% (1488/1836)
remote: Counting objects: 82% (1506/1836)
remote: Counting objects: 83% (1524/1836)
remote: Counting objects: 84% (1543/1836)
remote: Counting objects: 85% (1561/1836)
remote: Counting objects: 86% (1579/1836)
remote: Counting objects: 87% (1598/1836)
remote: Counting objects: 88% (1616/1836)
remote: Counting objects: 89% (1635/1836)
remote: Counting objects: 90% (1653/1836)
remote: Counting objects: 91% (1671/1836)
remote: Counting objects: 92% (1690/1836)
remote: Counting objects: 93% (1708/1836)
remote: Counting objects: 94% (1726/1836)
remote: Counting objects: 95% (1745/1836)
remote: Counting objects: 96% (1763/1836)
remote: Counting objects: 97% (1781/1836)
remote: Counting objects: 98% (1800/1836)
remLine truncated
|
|
||||||
6→remote: Compressing objects: 0% (1/1379)
remote: Compressing objects: 1% (14/1379)
remote: Compressing objects: 2% (28/1379)
remote: Compressing objects: 3% (42/1379)
remote: Compressing objects: 4% (56/1379)
remote: Compressing objects: 5% (69/1379)
remote: Compressing objects: 6% (83/1379)
remote: Compressing objects: 7% (97/1379)
remote: Compressing objects: 8% (111/1379)
remote: Compressing objects: 9% (125/1379)
remote: Compressing objects: 10% (138/1379)
remote: Compressing objects: 11% (152/1379)
remote: Compressing objects: 12% (166/1379)
remote: Compressing objects: 13% (180/1379)
remote: Compressing objects: 14% (194/1379)
remote: Compressing objects: 15% (207/1379)
remote: Compressing objects: 16% (221/1379)
remote: Compressing objects: 17% (235/1379)
remote: Compressing objects: 18% (249/1379)
remote: Compressing objects: 19% (263/1379)
remote: Compressing objects: 20% (276/1379)
remote: Compressing objects: 21% (290/1379)
remote: Compressing objects: 22% (304/1379)
remote: Compressing objects: 23% (318/1379)
remote: Compressing objects: 24% (331/1379)
remote: Compressing objects: 25% (345/1379)
remote: Compressing objects: 26% (359/1379)
remote: Compressing objects: 27% (373/1379)
remote: Compressing objects: 28% (387/1379)
remote: Compressing objects: 29% (400/1379)
remote: Compressing objects: 30% (414/1379)
remote: Compressing objects: 31% (428/1379)
remote: Compressing objects: 32% (442/1379)
remote: Compressing objects: 33% (456/1379)
remote: Compressing objects: 34% (469/1379)
remote: Compressing objects: 35% (483/1379)
remote: Compressing objects: 36% (497/1379)
remote: Compressing objects: 37% (511/1379)
remote: Compressing objects: 38% (525/1379)
remote: Compressing objects: 39% (538/1379)
remote: Compressing objects: 40% (552/1379)
remote: Compressing objects: 41% (566/1379)
remote: Compressing objects: 42% (580/1379)
remote: Compressing objects: 43% (593/1379)
remote: Compressing objects: 44% (607/1379)
remote: Compressing objects: 45% (621/1379)
remote: Compressing objects: 46% (635/1379)
remote: Compressing objects: 47% (649/1379)
remote: Compressing objects: 48% (662/1379)
remote: Compressing objects: 49% (676/1379)
remote: Compressing objects: 50% (690/1379)
remote: Compressing objects: 51% (704/1379)
remote: Compressing objects: 52% (718/1379)
remote: Compressing objects: 53% (731/1379)
remote: Compressing objects: 54% (745/1379)
remote: Compressing objects: 55% (759/1379)
remote: Compressing objects: 56% (773/1379)
remote: Compressing objects: 57% (787/1379)
remote: Compressing objects: 58% (800/1379)
remote: Compressing objects: 59% (814/1379)
remote: Compressing objects: 60% (828/1379)
remote: Compressing objects: 61% (842/1379)
remote: Compressing objects: 62% (855/1379)
remote: Compressing objects: 63% (869/1379)
remote: Compressing objects: 64% (883/1379)
remote: Compressing objects: 65% (897/1379)
remote: Compressing objects: 66% (911/1379)
remote: Compressing objects: 67% (924/1379)
remote: Compressing objects: 68% (938/1379)
remote: Compressing objects: 69% (952/1379)
remote: Compressing objects: 70% (966/1379)
remote: Compressing objects: 71% (980/1379)
remote: Compressing objects: 72% (993/1379)
remote: Compressing objects: 73% (1007/1379)
remote: Compressing objects: 74% (1021/1379)
remote: Compressing objects: 75% (1035/1379)
remote: Compressing objects: 76% (1049/1379)
remote: Compressing objects: 77% (1062/1379)
remote: Compressing objects: 78% (1076/1379)
remote: Compressing objects: 79% (1090/1379)
remote: Compressing objects: 80% (1104/1379)
remote: Compressing objects: 81% (1117/1379)
remote: Compressing objects: 82% (1131/1379)
remote: Compressing objects: 83% (1145/1379)
remote: Compressing objects: 84% (1159/1379)
remote: Compressing objects: 85% (1173/1379)
remote: Compressing objects: 86% (1186/1379)
remote: Compressing objects: 87% (1200/1379)
remote: Compressing objects: 88% (1214/1379)
remote: Compressing objects: 89% (1228/1379)
remote: Compressing objects: 90% (1242/1379)
remote: Compressing objects: 91% (1255/1379)
remote: Compressing objects: 92% (1269/1379)
remote: Compressing objects: 93% (1283/1379) Line truncated
|
|
||||||
7→Receiving objects: 0% (1/1836)
Receiving objects: 1% (19/1836)
Receiving objects: 2% (37/1836)
Receiving objects: 3% (56/1836)
Receiving objects: 4% (74/1836)
Receiving objects: 5% (92/1836)
Receiving objects: 6% (111/1836)
Receiving objects: 7% (129/1836)
Receiving objects: 8% (147/1836)
Receiving objects: 9% (166/1836)
Receiving objects: 10% (184/1836)
Receiving objects: 11% (202/1836)
Receiving objects: 12% (221/1836)
Receiving objects: 13% (239/1836)
Receiving objects: 14% (258/1836)
Receiving objects: 15% (276/1836)
Receiving objects: 16% (294/1836)
Receiving objects: 17% (313/1836)
Receiving objects: 18% (331/1836)
Receiving objects: 19% (349/1836)
Receiving objects: 20% (368/1836)
Receiving objects: 21% (386/1836)
Receiving objects: 22% (404/1836)
Receiving objects: 23% (423/1836)
Receiving objects: 24% (441/1836)
Receiving objects: 25% (459/1836)
Receiving objects: 26% (478/1836)
Receiving objects: 27% (496/1836)
Receiving objects: 28% (515/1836)
Receiving objects: 29% (533/1836)
Receiving objects: 30% (551/1836)
Receiving objects: 31% (570/1836)
Receiving objects: 32% (588/1836)
Receiving objects: 33% (606/1836)
Receiving objects: 34% (625/1836)
Receiving objects: 35% (643/1836)
Receiving objects: 36% (661/1836)
Receiving objects: 37% (680/1836)
Receiving objects: 38% (698/1836)
Receiving objects: 39% (717/1836)
Receiving objects: 40% (735/1836)
Receiving objects: 41% (753/1836)
Receiving objects: 42% (772/1836)
Receiving objects: 43% (790/1836)
Receiving objects: 44% (808/1836)
Receiving objects: 45% (827/1836), 14.90 MiB | 29.78 MiB/s
Receiving objects: 46% (845/1836), 14.90 MiB | 29.78 MiB/s
Receiving objects: 47% (863/1836), 14.90 MiB | 29.78 MiB/s
Receiving objects: 48% (882/1836), 14.90 MiB | 29.78 MiB/s
Receiving objects: 49% (900/1836), 14.90 MiB | 29.78 MiB/s
Receiving objects: 50% (918/1836), 14.90 MiB | 29.78 MiB/s
Receiving objects: 51% (937/1836), 14.90 MiB | 29.78 MiB/s
Receiving objects: 52% (955/1836), 14.90 MiB | 29.78 MiB/s
Receiving objects: 52% (973/1836), 30.91 MiB | 30.91 MiB/s
Receiving objects: 53% (974/1836), 30.91 MiB | 30.91 MiB/s
Receiving objects: 54% (992/1836), 30.91 MiB | 30.91 MiB/s
Receiving objects: 55% (1010/1836), 30.91 MiB | 30.91 MiB/s
Receiving objects: 56% (1029/1836), 30.91 MiB | 30.91 MiB/s
Receiving objects: 57% (1047/1836), 30.91 MiB | 30.91 MiB/s
Receiving objects: 58% (1065/1836), 30.91 MiB | 30.91 MiB/s
Receiving objects: 59% (1084/1836), 30.91 MiB | 30.91 MiB/s
Receiving objects: 60% (1102/1836), 30.91 MiB | 30.91 MiB/s
Receiving objects: 61% (1120/1836), 30.91 MiB | 30.91 MiB/s
Receiving objects: 62% (1139/1836), 30.91 MiB | 30.91 MiB/s
Receiving objects: 63% (1157/1836), 30.91 MiB | 30.91 MiB/s
Receiving objects: 64% (1176/1836), 30.91 MiB | 30.91 MiB/s
Receiving objects: 65% (1194/1836), 30.91 MiB | 30.91 MiB/s
Receiving objects: 66% (1212/1836), 30.91 MiB | 30.91 MiB/s
Receiving objects: 67% (1231/1836), 30.91 MiB | 30.91 MiB/s
Receiving objects: 68% (1249/1836), 30.91 MiB | 30.91 MiB/s
Receiving objects: 69% (1267/1836), 30.91 MiB | 30.91 MiB/s
Receiving objects: 70% (1286/1836), 30.91 MiB | 30.91 MiB/s
Receiving objects: 71% (1304/1836), 30.91 MiB | 30.91 MiB/s
Receiving objects: 72% (1322/1836), 30.91 MiB | 30.91 MiB/s
Receiving objects: 73% (1341/1836), 30.91 MiB | 30.91 MiB/s
Receiving objects: 74% (1359/1836), 30.91 MiB | 30.91 MiB/s
Receiving objects: 75% (1377/1836), 30.91 MiB | 30.91 MiB/s
Receiving objects: 76% (1396/1836), 30.91 MiB | 30.91 MiB/s
Receiving objects: 77% (1414/1836), 30.91 MiB | 30.91 MiB/s
Receiving objects: 78% (1433/1836), 30.91 MiB | 30.91 MiB/s
Receiving objects: 79% (1451/1836), 30.91 MiB | 30.91 MiB/s
Receiving objects: 80% (1469/1836), 30.91 MiB | 30.91 MiB/s
Receiving objects: 81% (1488/1836), 30.91 MiB | 30.91 MiB/s
Receiving objects: 82% (1506/1836), 30.91 MiB | 30.91 MiB/s
Receiving objects: 83% (1524/1836), 30.91 MiB | 30.91 MiB/s
Receiving objects: 84% (1543/1836), 30.91 MiB | 30.91 MiB/s
Receiving objects: 85% (1561/1836), 30.91 MiB | 30.91 MiB/s
Receiving objects: 86% (1579/1836), 30.91 MiB | 30.91 MiB/s
Receiving objects: 87% (1598/1836), 30.91 MiB | 30.91 MiB/s
Receiving objects: 88% (1616/1836), 30.91 MiB | 30.91 MiB/s
Receiving objects: 89% (1635/1836), 30.91 MiB | 30.91 MiB/s
Receiving objects: 90% (1653/1836), 30.91 MiB | 30.91 MiB/s
Receiving objects: 91% (1671/1836), 30.91 MiB | 30.91 MiB/s
Receiving objects: 92% (1690/1836), 30.91 MiB | 30.91 MiB/s
Receiving objects: 93% (1708/1836), 30.91 MiB | 30.91 MiB/s
Receiving objects: 94% (1726/1836), 30.91 MiB | 30.91 MiB/s
Receiving objects: 95% (1745/1836), 47.46 MiB | 31.63 MiB/s
Receiving objects: 96% (1763/1836), 47.46 MiB | 31.63 MiB/s
Receiving objects: 97% (1781/1836), 47.46 MiB | 31.63 MiB/s
Receiving objects: 98% (1800/1836), 47.46 MiB | 31.63 MiB/s
Receiving objects: 99% (1818/1836), 47.46 MiB | 31.63 MiB/s
remote: Total 183Line truncated
|
|
||||||
8→Receiving objects: 100% (1836/1836), 47.46 MiB | 31.63 MiB/s␍Receiving objects: 100% (1836/1836), 47.65 MiB | 31.60 MiB/s, done.
|
|
||||||
9→Resolving deltas: 0% (0/316)␍Resolving deltas: 1% (4/316)␍Resolving deltas: 2% (7/316)␍Resolving deltas: 3% (10/316)␍Resolving deltas: 4% (13/316)␍Resolving deltas: 5% (16/316)␍Resolving deltas: 6% (19/316)␍Resolving deltas: 7% (23/316)␍Resolving deltas: 8% (26/316)␍Resolving deltas: 9% (29/316)␍Resolving deltas: 10% (32/316)␍Resolving deltas: 11% (35/316)␍Resolving deltas: 12% (38/316)␍Resolving deltas: 13% (42/316)␍Resolving deltas: 14% (45/316)␍Resolving deltas: 15% (48/316)␍Resolving deltas: 16% (51/316)␍Resolving deltas: 17% (54/316)␍Resolving deltas: 18% (57/316)␍Resolving deltas: 19% (61/316)␍Resolving deltas: 20% (64/316)␍Resolving deltas: 21% (67/316)␍Resolving deltas: 22% (70/316)␍Resolving deltas: 23% (73/316)␍Resolving deltas: 24% (76/316)␍Resolving deltas: 25% (79/316)␍Resolving deltas: 26% (83/316)␍Resolving deltas: 27% (86/316)␍Resolving deltas: 28% (89/316)␍Resolving deltas: 29% (92/316)␍Resolving deltas: 30% (95/316)␍Resolving deltas: 31% (98/316)␍Resolving deltas: 32% (102/316)␍Resolving deltas: 33% (105/316)␍Resolving deltas: 34% (108/316)␍Resolving deltas: 35% (111/316)␍Resolving deltas: 36% (114/316)␍Resolving deltas: 37% (117/316)␍Resolving deltas: 38% (121/316)␍Resolving deltas: 39% (124/316)␍Resolving deltas: 40% (127/316)␍Resolving deltas: 41% (130/316)␍Resolving deltas: 42% (133/316)␍Resolving deltas: 43% (136/316)␍Resolving deltas: 44% (140/316)␍Resolving deltas: 45% (143/316)␍Resolving deltas: 46% (146/316)␍Resolving deltas: 47% (149/316)␍Resolving deltas: 48% (152/316)␍Resolving deltas: 49% (155/316)␍Resolving deltas: 50% (159/316)␍Resolving deltas: 51% (162/316)␍Resolving deltas: 52% (165/316)␍Resolving deltas: 53% (168/316)␍Resolving deltas: 54% (171/316)␍Resolving deltas: 55% (174/316)␍Resolving deltas: 56% (177/316)␍Resolving deltas: 57% (182/316)␍Resolving deltas: 58% (184/316)␍Resolving deltas: 59% (188/316)␍Resolving deltas: 60% (190/316)␍Resolving deltas: 61% (193/316)␍Resolving deltas: 62% (196/316)␍Resolving deltas: 63% (200/316)␍Resolving deltas: 64% (203/316)␍Resolving deltas: 65% (206/316)␍Resolving deltas: 66% (209/316)␍Resolving deltas: 67% (213/316)␍Resolving deltas: 68% (215/316)␍Resolving deltas: 69% (219/316)␍Resolving deltas: 70% (222/316)␍Resolving deltas: 71% (225/316)␍Resolving deltas: 72% (229/316)␍Resolving deltas: 73% (231/316)␍Resolving deltas: 74% (234/316)␍Resolving deltas: 75% (237/316)␍Resolving deltas: 76% (241/316)␍Resolving deltas: 77% (244/316)␍Resolving deltas: 78% (247/316)␍Resolving deltas: 79% (250/316)␍Resolving deltas: 80% (253/316)␍Resolving deltas: 81% (256/316)␍Resolving deltas: 82% (260/316)␍Resolving deltas: 83% (263/316)␍Resolving deltas: 84% (267/316)␍Resolving deltas: 85% (269/316)␍Resolving deltas: 86% (272/316)␍Resolving deltas: 87% (276/316)␍Resolving deltas: 88% (279/316)␍Resolving deltas: 89% (282/316)␍Resolving deltas: 90% (285/316)␍Resolving deltas: 91% (288/316)␍Resolving deltas: 92% (291/316)␍Resolving deltas: 93% (294/316)␍Resolving deltas: 94% (298/316)␍Resolving deltas: 95% (301/316)␍Resolving deltas: 96% (304/316)␍Resolving deltas: 97% (307/316)␍Resolving deltas: 98% (310/316)␍Resolving deltas: 99% (313/316)␍Resolving deltas: 100% (316/316)␍Resolving deltas: 100% (316/316), done.
|
|
||||||
10→> Installing railpack, please wait…
|
|
||||||
11→____ _ _ _
|
|
||||||
12→| _ \ __ _(_) |_ __ __ _ ___| | __
|
|
||||||
13→| |_) / _` | | | '_ \ / _` |/ __| |/ /
|
|
||||||
14→| _ < (_| | | | |_) | (_| | (__| <
|
|
||||||
15→|_| \_\__,_|_|_| .__/ \__,_|\___|_|\_\
|
|
||||||
16→|_|
|
|
||||||
17→Railpack is now installed!
|
|
||||||
18→Run 'railpack --help' to get started
|
|
||||||
19→railpack-dfm-aos-lgbcnc-INtHrR
|
|
||||||
20→Preparing Railpack build plan...
|
|
||||||
21→╭─────────────────╮
|
|
||||||
22→│ Railpack 0.15.4 │
|
|
||||||
23→╰─────────────────╯
|
|
||||||
24→↳ Detected Node
|
|
||||||
25→↳ Using bun package manager
|
|
||||||
26→Packages
|
|
||||||
27→──────────
|
|
||||||
28→bun │ 1.4.4 │ railpack default (latest)
|
|
||||||
29→node │ 26.12.1 │ railpack default (latest)
|
|
||||||
30→Steps
|
|
||||||
31→──────────
|
|
||||||
32→▸ install
|
|
||||||
33→$ bun install --frozen-lockfile
|
|
||||||
34→▸ build
|
|
||||||
35→$ bun run build
|
|
||||||
36→Deploy
|
|
||||||
37→──────────
|
|
||||||
38→$ bun run start
|
|
||||||
39→✅ Railpack prepare completed.
|
|
||||||
40→Building with Railpack frontend...
|
|
||||||
41→#0 building with "railpack-dfm-aos-lgbcnc-INtHrR" instance using docker-container driver
|
|
||||||
42→#1 [internal] booting buildkit
|
|
||||||
43→#1 pulling image moby/buildkit:buildx-stable-1
|
|
||||||
44→#1 pulling image moby/buildkit:buildx-stable-1 1.1s done
|
|
||||||
45→#1 creating container buildx_buildkit_railpack-dfm-aos-lgbcnc-inthrr0
|
|
||||||
46→#1 creating container buildx_buildkit_railpack-dfm-aos-lgbcnc-inthrr0 0.6s done
|
|
||||||
47→#1 DONE 1.7s
|
|
||||||
48→#2 resolve image config for docker-image://ghcr.io/railwayapp/railpack-frontend:v0.15.4
|
|
||||||
49→#2 DONE 1.4s
|
|
||||||
50→#3 docker-image://ghcr.io/railwayapp/railpack-frontend:v0.15.4@sha256:7e0535e519d9d00793d0bb4e652be5d48373ab5e0c7d9b90ef6bc40147290ff7
|
|
||||||
51→#3 resolve ghcr.io/railwayapp/railpack-frontend:v0.15.4@sha256:7e0535e519d9d00793d0bb4e652be5d48373ab5e0c7d9b90ef6bc40147290ff7 0.0s done
|
|
||||||
52→#3 sha256:76fdf18f436616aff2234f2d325d888d31af103f333a8f491d539dce0106e849 0B / 7.90MB 0.2s
|
|
||||||
53→#3 sha256:76fdf18f436616aff2234f2d325d888d31af103f333a8f491d539dce0106e849 2.10MB / 7.90MB 0.3s
|
|
||||||
54→#3 sha256:1074353eec0db2c1d81d5af2671e56e00cf5738486f5762609ea33d606f88612 0B / 3.86MB 0.2s
|
|
||||||
55→#3 sha256:76fdf18f436616aff2234f2d325d888d31af103f333a8f491d539dce0106e849 7.90MB / 7.90MB 0.4s done
|
|
||||||
56→#3 sha256:1074353eec0db2c1d81d5af2671e56e00cf5738486f5762609ea33d606f88612 3.86MB / 3.86MB 0.5s done
|
|
||||||
57→#3 extracting sha256:1074353eec0db2c1d81d5af2671e56e00cf5738486f5762609ea33d606f88612 0.1s done
|
|
||||||
58→#3 DONE 0.7s
|
|
||||||
59→#3 docker-image://ghcr.io/railwayapp/railpack-frontend:v0.15.4@sha256:7e0535e519d9d00793d0bb4e652be5d48373ab5e0c7d9b90ef6bc40147290ff7
|
|
||||||
60→#3 extracting sha256:76fdf18f436616aff2234f2d325d888d31af103f333a8f491d539dce0106e849 0.1s done
|
|
||||||
61→#3 DONE 0.8s
|
|
||||||
62→#4 load build definition from railpack-plan.json
|
|
||||||
63→#4 transferring dockerfile: 5.11kB done
|
|
||||||
64→#4 DONE 0.0s
|
|
||||||
65→#5 [railpack] secrets hash
|
|
||||||
66→#5 DONE 0.0s
|
|
||||||
67→#6 loading .
|
|
||||||
68→#6 DONE 0.0s
|
|
||||||
69→#7 [railpack] loading secrets
|
|
||||||
70→#7 resolve docker.io/library/alpine:latest
|
|
||||||
71→#7 ...
|
|
||||||
72→#8 docker-image://ghcr.io/railwayapp/railpack-builder:latest
|
|
||||||
73→#8 resolve ghcr.io/railwayapp/railpack-builder:latest 0.9s done
|
|
||||||
74→#8 DONE 1.0s
|
|
||||||
75→#8 docker-image://ghcr.io/railwayapp/railpack-builder:latest
|
|
||||||
76→#8 sha256:193926ad1d06489b7487e8ac4ae2d0874e6ff05cf65d874d2af508830fc03def 0B / 119B 0.2s
|
|
||||||
77→#8 sha256:df614908d6aba31e983953b17fd48496d27425529b3947c3d5583c4cc9c15c9a 0B / 868.40kB 0.2s
|
|
||||||
78→#8 sha256:193926ad1d06489b7487e8ac4ae2d0874e6ff05cf65d874d2af508830fc03def 119B / 119B 0.3s done
|
|
||||||
79→#8 sha256:df614908d6aba31e983953b17fd48496d27425529b3947c3d5583c4cc9c15c9a 868.40kB / 868.40kB 0.3s done
|
|
||||||
80→#8 sha256:604add184d03d4cf6e2ff1c4b9013b265eb9c11570afe28ce8f9dc417b98ea3f 0B / 237.08MB 0.2s
|
|
||||||
81→#8 sha256:08a1e03b3da5bb4a1059032dca3216f33ddfc4a48a45db88921f5bb2e9a8fa2d 0B / 53.72MB 0.2s
|
|
||||||
82→#8 sha256:4f4fb700ef54461cfa02571ae0db9a0dc1e0cdb5577484a6d75e68dc38e8acc1 0B / 32B 0.2s
|
|
||||||
83→#8 ...
|
|
||||||
84→#5 [railpack] secrets hash
|
|
||||||
85→#5 DONE 0.0s
|
|
||||||
86→#8 docker-image://ghcr.io/railwayapp/railpack-builder:latest
|
|
||||||
87→#8 sha256:4f4fb700ef54461cfa02571ae0db9a0dc1e0cdb5577484a6d75e68dc38e8acc1 32B / 32B 0.2s done
|
|
||||||
88→#8 sha256:4dc3950125ebc9ed195e1101fc6c02e2fce113ba0f53bfb05b2cdf58747df9af 0B / 67.81MB 0.2s
|
|
||||||
89→#8 sha256:08a1e03b3da5bb4a1059032dca3216f33ddfc4a48a45db88921f5bb2e9a8fa2d 7.34MB / 53.72MB 0.5s
|
|
||||||
90→#8 sha256:62fe2e747f69f2f414c7e9eb1553155cf0a658398f0462557f458821dce2b29d 0B / 25.64MB 0.2s
|
|
||||||
91→#8 sha256:604add184d03d4cf6e2ff1c4b9013b265eb9c11570afe28ce8f9dc417b98ea3f 17.83MB / 237.08MB 0.6s
|
|
||||||
92→#8 sha256:4dc3950125ebc9ed195e1101fc6c02e2fce113ba0f53bfb05b2cdf58747df9af 7.34MB / 67.81MB 0.5s
|
|
||||||
93→#8 sha256:08a1e03b3da5bb4a1059032dca3216f33ddfc4a48a45db88921f5bb2e9a8fa2d 14.68MB / 53.72MB 0.8s
|
|
||||||
94→#8 sha256:62fe2e747f69f2f414c7e9eb1553155cf0a658398f0462557f458821dce2b29d 6.29MB / 25.64MB 0.5s
|
|
||||||
95→#8 sha256:604add184d03d4cf6e2ff1c4b9013b265eb9c11570afe28ce8f9dc417b98ea3f 30.41MB / 237.08MB 0.9s
|
|
||||||
96→#8 sha256:4dc3950125ebc9ed195e1101fc6c02e2fce113ba0f53bfb05b2cdf58747df9af 14.68MB / 67.81MB 0.8s
|
|
||||||
97→#8 sha256:62fe2e747f69f2f414c7e9eb1553155cf0a658398f0462557f458821dce2b29d 10.49MB / 25.64MB 0.6s
|
|
||||||
98→#8 sha256:08a1e03b3da5bb4a1059032dca3216f33ddfc4a48a45db88921f5bb2e9a8fa2d 18.87MB / 53.72MB 1.1s
|
|
||||||
99→#8 sha256:62fe2e747f69f2f414c7e9eb1553155cf0a658398f0462557f458821dce2b29d 14.68MB / 25.64MB 0.8s
|
|
||||||
100→#8 sha256:62fe2e747f69f2f414c7e9eb1553155cf0a658398f0462557f458821dce2b29d 17.83MB / 25.64MB 0.9s
|
|
||||||
101→#8 sha256:604add184d03d4cf6e2ff1c4b9013b265eb9c11570afe28ce8f9dc417b98ea3f 48.23MB / 237.08MB 1.4s
|
|
||||||
102→#8 sha256:08a1e03b3da5bb4a1059032dca3216f33ddfc4a48a45db88921f5bb2e9a8fa2d 23.07MB / 53.72MB 1.4s
|
|
||||||
103→#8 sha256:4dc3950125ebc9ed195e1101fc6c02e2fce113ba0f53bfb05b2cdf58747df9af 22.02MB / 67.81MB 1.1s
|
|
||||||
104→#8 sha256:62fe2e747f69f2f414c7e9eb1553155cf0a658398f0462557f458821dce2b29d 23.07MB / 25.64MB 1.1s
|
|
||||||
105→#8 sha256:08a1e03b3da5bb4a1059032dca3216f33ddfc4a48a45db88921f5bb2e9a8fa2d 26.21MB / 53.72MB 1.5s
|
|
||||||
106→#8 sha256:4dc3950125ebc9ed195e1101fc6c02e2fce113ba0f53bfb05b2cdf58747df9af 29.36MB / 67.81MB 1.4s
|
|
||||||
107→#8 sha256:62fe2e747f69f2f414c7e9eb1553155cf0a658398f0462557f458821dce2b29d 25.64MB / 25.64MB 1.3s done
|
|
||||||
108→#8 ...
|
|
||||||
109→#7 [railpack] loading secrets
|
|
||||||
110→#7 resolve docker.io/library/alpine:latest 1.5s done
|
|
||||||
111→#7 sha256:7b229517ed222597277036d94892173207d01a731ab3a88eeb1de2e963a2c788 3.85MB / 3.85MB 0.9s done
|
|
||||||
112→#7 extracting sha256:7b229517ed222597277036d94892173207d01a731ab3a88eeb1de2e963a2c788 0.5s done
|
|
||||||
113→#7 DONE 2.9s
|
|
||||||
114→#8 docker-image://ghcr.io/railwayapp/railpack-builder:latest
|
|
||||||
115→#8 sha256:08a1e03b3da5bb4a1059032dca3216f33ddfc4a48a45db88921f5bb2e9a8fa2d 30.15MB / 53.72MB 1.7s
|
|
||||||
116→#8 sha256:604add184d03d4cf6e2ff1c4b9013b265eb9c11570afe28ce8f9dc417b98ea3f 69.21MB / 237.08MB 1.8s
|
|
||||||
117→#8 sha256:4dc3950125ebc9ed195e1101fc6c02e2fce113ba0f53bfb05b2cdf58747df9af 35.65MB / 67.81MB 1.5s
|
|
||||||
118→#8 sha256:4846f29007305297af653c57bf9b60ba8f676a38695c68d98460063442581671 0B / 49.39MB 0.2s
|
|
||||||
119→#8 sha256:08a1e03b3da5bb4a1059032dca3216f33ddfc4a48a45db88921f5bb2e9a8fa2d 35.65MB / 53.72MB 2.0s
|
|
||||||
120→#8 sha256:4dc3950125ebc9ed195e1101fc6c02e2fce113ba0f53bfb05b2cdf58747df9af 40.89MB / 67.81MB 1.7s
|
|
||||||
121→#8 sha256:4846f29007305297af653c57bf9b60ba8f676a38695c68d98460063442581671 6.29MB / 49.39MB 0.5s
|
|
||||||
122→#8 sha256:604add184d03d4cf6e2ff1c4b9013b265eb9c11570afe28ce8f9dc417b98ea3f 83.89MB / 237.08MB 2.1s
|
|
||||||
123→#8 sha256:08a1e03b3da5bb4a1059032dca3216f33ddfc4a48a45db88921f5bb2e9a8fa2d 40.89MB / 53.72MB 2.3s
|
|
||||||
124→#8 sha256:4dc3950125ebc9ed195e1101fc6c02e2fce113ba0f53bfb05b2cdf58747df9af 48.23MB / 67.81MB 2.0s
|
|
||||||
125→#8 sha256:4846f29007305297af653c57bf9b60ba8f676a38695c68d98460063442581671 10.49MB / 49.39MB 0.6s
|
|
||||||
126→#8 sha256:604add184d03d4cf6e2ff1c4b9013b265eb9c11570afe28ce8f9dc417b98ea3f 97.52MB / 237.08MB 2.4s
|
|
||||||
127→#8 sha256:4dc3950125ebc9ed195e1101fc6c02e2fce113ba0f53bfb05b2cdf58747df9af 52.43MB / 67.81MB 2.1s
|
|
||||||
128→#8 sha256:4846f29007305297af653c57bf9b60ba8f676a38695c68d98460063442581671 14.68MB / 49.39MB 0.8s
|
|
||||||
129→#8 ...
|
|
||||||
130→#9 [railpack] copy secrets hash
|
|
||||||
131→#9 DONE 0.7s
|
|
||||||
132→#8 docker-image://ghcr.io/railwayapp/railpack-builder:latest
|
|
||||||
133→#8 sha256:4846f29007305297af653c57bf9b60ba8f676a38695c68d98460063442581671 18.87MB / 49.39MB 0.9s
|
|
||||||
134→#8 sha256:08a1e03b3da5bb4a1059032dca3216f33ddfc4a48a45db88921f5bb2e9a8fa2d 46.14MB / 53.72MB 2.6s
|
|
||||||
135→#8 sha256:4846f29007305297af653c57bf9b60ba8f676a38695c68d98460063442581671 23.07MB / 49.39MB 1.1s
|
|
||||||
136→#8 sha256:604add184d03d4cf6e2ff1c4b9013b265eb9c11570afe28ce8f9dc417b98ea3f 111.15MB / 237.08MB 2.7s
|
|
||||||
137→#8 sha256:4dc3950125ebc9ed195e1101fc6c02e2fce113ba0f53bfb05b2cdf58747df9af 59.77MB / 67.81MB 2.4s
|
|
||||||
138→#8 sha256:08a1e03b3da5bb4a1059032dca3216f33ddfc4a48a45db88921f5bb2e9a8fa2d 51.38MB / 53.72MB 2.9s
|
|
||||||
139→#8 sha256:4dc3950125ebc9ed195e1101fc6c02e2fce113ba0f53bfb05b2cdf58747df9af 63.96MB / 67.81MB 2.6s
|
|
||||||
140→#8 sha256:4846f29007305297af653c57bf9b60ba8f676a38695c68d98460063442581671 30.41MB / 49.39MB 1.4s
|
|
||||||
141→#8 sha256:604add184d03d4cf6e2ff1c4b9013b265eb9c11570afe28ce8f9dc417b98ea3f 126.88MB / 237.08MB 3.0s
|
|
||||||
142→#8 sha256:4846f29007305297af653c57bf9b60ba8f676a38695c68d98460063442581671 36.70MB / 49.39MB 1.5s
|
|
||||||
143→#8 ...
|
|
||||||
144→#10 [railpack] hash used secrets
|
|
||||||
145→#10 DONE 0.7s
|
|
||||||
146→#8 docker-image://ghcr.io/railwayapp/railpack-builder:latest
|
|
||||||
147→#8 sha256:08a1e03b3da5bb4a1059032dca3216f33ddfc4a48a45db88921f5bb2e9a8fa2d 53.72MB / 53.72MB 3.2s done
|
|
||||||
148→#8 sha256:4dc3950125ebc9ed195e1101fc6c02e2fce113ba0f53bfb05b2cdf58747df9af 67.81MB / 67.81MB 2.9s done
|
|
||||||
149→#8 ...
|
|
||||||
150→#11 [railpack] copy used secrets hash
|
|
||||||
151→#11 DONE 0.0s
|
|
||||||
152→#8 docker-image://ghcr.io/railwayapp/railpack-builder:latest
|
|
||||||
153→#8 sha256:604add184d03d4cf6e2ff1c4b9013b265eb9c11570afe28ce8f9dc417b98ea3f 145.75MB / 237.08MB 3.3s
|
|
||||||
154→#8 sha256:4846f29007305297af653c57bf9b60ba8f676a38695c68d98460063442581671 40.89MB / 49.39MB 1.7s
|
|
||||||
155→#8 sha256:4846f29007305297af653c57bf9b60ba8f676a38695c68d98460063442581671 46.14MB / 49.39MB 1.8s
|
|
||||||
156→#8 sha256:604add184d03d4cf6e2ff1c4b9013b265eb9c11570afe28ce8f9dc417b98ea3f 168.15MB / 237.08MB 3.6s
|
|
||||||
157→#8 sha256:4846f29007305297af653c57bf9b60ba8f676a38695c68d98460063442581671 49.39MB / 49.39MB 2.0s
|
|
||||||
158→#8 sha256:604add184d03d4cf6e2ff1c4b9013b265eb9c11570afe28ce8f9dc417b98ea3f 181.40MB / 237.08MB 3.8s
|
|
||||||
159→#8 sha256:4846f29007305297af653c57bf9b60ba8f676a38695c68d98460063442581671 49.39MB / 49.39MB 2.2s done
|
|
||||||
160→#8 extracting sha256:4846f29007305297af653c57bf9b60ba8f676a38695c68d98460063442581671
|
|
||||||
161→#8 sha256:604add184d03d4cf6e2ff1c4b9013b265eb9c11570afe28ce8f9dc417b98ea3f 205.52MB / 237.08MB 4.1s
|
|
||||||
162→#8 ...
|
|
||||||
163→#6 loading .
|
|
||||||
164→#6 transferring context: 127.67MB 3.8s done
|
|
||||||
165→#6 DONE 4.0s
|
|
||||||
166→#8 docker-image://ghcr.io/railwayapp/railpack-builder:latest
|
|
||||||
167→#8 sha256:604add184d03d4cf6e2ff1c4b9013b265eb9c11570afe28ce8f9dc417b98ea3f 231.05MB / 237.08MB 4.4s
|
|
||||||
168→#8 ...
|
|
||||||
169→#12 docker-image://ghcr.io/railwayapp/railpack-runtime:latest
|
|
||||||
170→#12 resolve ghcr.io/railwayapp/railpack-runtime:latest 0.9s done
|
|
||||||
171→#12 sha256:75dc09925ca146a3efecc887098f8f1313da0fb1b0c8d36d628b6cae320665ec 7.39MB / 7.39MB 0.3s done
|
|
||||||
172→#12 sha256:ecc510c1e359bdc007b39802570bb7e4dec7d6ebccf357c3201a74299113e05e 29.84MB / 29.84MB 0.7s done
|
|
||||||
173→#12 extracting sha256:ecc510c1e359bdc007b39802570bb7e4dec7d6ebccf357c3201a74299113e05e 3.4s done
|
|
||||||
174→#12 extracting sha256:75dc09925ca146a3efecc887098f8f1313da0fb1b0c8d36d628b6cae320665ec 0.6s done
|
|
||||||
175→#12 DONE 5.6s
|
|
||||||
176→#8 docker-image://ghcr.io/railwayapp/railpack-builder:latest
|
|
||||||
177→#8 sha256:604add184d03d4cf6e2ff1c4b9013b265eb9c11570afe28ce8f9dc417b98ea3f 237.08MB / 237.08MB 4.7s done
|
|
||||||
178→#8 extracting sha256:4846f29007305297af653c57bf9b60ba8f676a38695c68d98460063442581671 2.7s done
|
|
||||||
179→#8 extracting sha256:62fe2e747f69f2f414c7e9eb1553155cf0a658398f0462557f458821dce2b29d
|
|
||||||
180→#8 extracting sha256:62fe2e747f69f2f414c7e9eb1553155cf0a658398f0462557f458821dce2b29d 1.7s done
|
|
||||||
181→#8 DONE 9.4s
|
|
||||||
182→#13 install apt packages: libatomic1
|
|
||||||
183→#13 0.232 Get:1 http://deb.debian.org/debian trixie InRelease [140 kB]
|
|
||||||
184→#13 0.314 Get:2 http://deb.debian.org/debian trixie-updates InRelease [47.3 kB]
|
|
||||||
185→#13 0.345 Get:3 http://deb.debian.org/debian-security trixie-security InRelease [43.4 kB]
|
|
||||||
186→#13 0.374 Get:4 http://deb.debian.org/debian trixie/main amd64 Packages [9678 kB]
|
|
||||||
187→#13 0.549 Get:5 http://deb.debian.org/debian trixie-updates/main amd64 Packages [720 B]
|
|
||||||
188→#13 0.575 Get:6 http://deb.debian.org/debian-security trixie-security/main amd64 Packages [270 kB]
|
|
||||||
189→#13 2.260 Fetched 10.2 MB in 2s (4830 kB/s)
|
|
||||||
190→#13 2.260 Reading package lists...
|
|
||||||
191→#13 4.151 Reading package lists...
|
|
||||||
192→#13 5.983 Building dependency tree...
|
|
||||||
193→#13 6.439 Reading state information...
|
|
||||||
194→#13 6.939 The following NEW packages will be installed:
|
|
||||||
195→#13 6.941 libatomic1
|
|
||||||
196→#13 7.101 0 upgraded, 1 newly installed, 0 to remove and 3 not upgraded.
|
|
||||||
197→#13 7.101 Need to get 9308 B of archives.
|
|
||||||
198→#13 7.101 After this operation, 46.1 kB of additional disk space will be used.
|
|
||||||
199→#13 7.101 Get:1 http://deb.debian.org/debian trixie/main amd64 libatomic1 amd64 14.2.0-19 [9308 B]
|
|
||||||
200→#13 7.542 debconf: unable to initialize frontend: Dialog
|
|
||||||
201→#13 7.543 debconf: (TERM is not set, so the dialog frontend is not usable.)
|
|
||||||
202→#13 7.543 debconf: falling back to frontend: Readline
|
|
||||||
203→#13 7.543 debconf: unable to initialize frontend: Readline
|
|
||||||
204→#13 7.543 debconf: (Can't locate Term/ReadLine.pm in @INC (you may need to install the Term::ReadLine module) (@INC entries checked: /etc/perl /usr/local/lib/x86_64-linux-gnu/perl/5.40.1 /usr/local/share/perl/5.40.1 /usr/lib/x86_64-linux-gnu/perl5/5.40 /usr/share/perl5 /usr/lib/x86_64-linux-gnu/perl-base /usr/lib/x86_64-linux-gnu/perl/5.40 /usr/share/perl/5.40 /usr/local/lib/site_perl) at /usr/share/perl5/Debconf/FrontEnd/Readline.pm line 8, <STDIN> line 1.)
|
|
||||||
205→#13 7.543 debconf: falling back to frontend: Teletype
|
|
||||||
206→#13 7.550 debconf: unable to initialize frontend: Teletype
|
|
||||||
207→#13 7.550 debconf: (This frontend requires a controlling tty.)
|
|
||||||
208→#13 7.550 debconf: falling back to frontend: Noninteractive
|
|
||||||
209→#13 ...
|
|
||||||
210→#8 docker-image://ghcr.io/railwayapp/railpack-builder:latest
|
|
||||||
211→#8 extracting sha256:4dc3950125ebc9ed195e1101fc6c02e2fce113ba0f53bfb05b2cdf58747df9af 4.6s done
|
|
||||||
212→#8 DONE 14.0s
|
|
||||||
213→#8 docker-image://ghcr.io/railwayapp/railpack-builder:latest
|
|
||||||
214→#8 extracting sha256:4f4fb700ef54461cfa02571ae0db9a0dc1e0cdb5577484a6d75e68dc38e8acc1 done
|
|
||||||
215→#8 extracting sha256:08a1e03b3da5bb4a1059032dca3216f33ddfc4a48a45db88921f5bb2e9a8fa2d
|
|
||||||
216→#8 ...
|
|
||||||
217→#13 install apt packages: libatomic1
|
|
||||||
218→#13 8.681 Fetched 9308 B in 0s (65.4 kB/s)
|
|
||||||
219→#13 8.727 Selecting previously unselected package libatomic1:amd64.
|
|
||||||
220→#13 8.727 (Reading database ... ␍(Reading database ... 5%␍(Reading database ... 10%␍(Reading database ... 15%␍(Reading database ... 20%␍(Reading database ... 25%␍(Reading database ... 30%␍(Reading database ... 35%␍(Reading database ... 40%␍(Reading database ... 45%␍(Reading database ... 50%␍(Reading database ... 55%␍(Reading database ... 60%␍(Reading database ... 65%␍(Reading database ... 70%␍(Reading database ... 75%␍(Reading database ... 80%␍(Reading database ... 85%␍(Reading database ... 90%␍(Reading database ... 95%␍(Reading database ... 100%␍(Reading database ... 6228 files and directories currently installed.)
|
|
||||||
221→#13 8.735 Preparing to unpack .../libatomic1_14.2.0-19_amd64.deb ...
|
|
||||||
222→#13 8.756 Unpacking libatomic1:amd64 (14.2.0-19) ...
|
|
||||||
223→#13 8.817 Setting up libatomic1:amd64 (14.2.0-19) ...
|
|
||||||
224→#13 8.823 Processing triggers for libc-bin (2.41-12+deb13u4) ...
|
|
||||||
225→#13 DONE 9.4s
|
|
||||||
226→#8 docker-image://ghcr.io/railwayapp/railpack-builder:latest
|
|
||||||
227→#8 extracting sha256:08a1e03b3da5bb4a1059032dca3216f33ddfc4a48a45db88921f5bb2e9a8fa2d 1.1s done
|
|
||||||
228→#8 extracting sha256:604add184d03d4cf6e2ff1c4b9013b265eb9c11570afe28ce8f9dc417b98ea3f
|
|
||||||
229→#8 extracting sha256:604add184d03d4cf6e2ff1c4b9013b265eb9c11570afe28ce8f9dc417b98ea3f 7.1s done
|
|
||||||
230→#8 DONE 22.2s
|
|
||||||
231→#8 docker-image://ghcr.io/railwayapp/railpack-builder:latest
|
|
||||||
232→#8 extracting sha256:df614908d6aba31e983953b17fd48496d27425529b3947c3d5583c4cc9c15c9a 0.0s done
|
|
||||||
233→#8 extracting sha256:193926ad1d06489b7487e8ac4ae2d0874e6ff05cf65d874d2af508830fc03def done
|
|
||||||
234→#8 DONE 22.2s
|
|
||||||
235→#14 mkdir /etc/mise
|
|
||||||
236→#14 DONE 1.5s
|
|
||||||
237→#15 create mise config
|
|
||||||
238→#15 DONE 0.0s
|
|
||||||
239→#16 install mise packages: bun, node
|
|
||||||
240→#16 0.142 mise by @jdx – installing 2 tools
|
|
||||||
241→#16 3.151 mise ███████████░░░░░ 0/2 · 3.0s
|
|
||||||
242→#16 3.151 bun@1.4.4 downloading 2.7s 51.8/51.8 MB · 22.0 MB/s
|
|
||||||
243→#16 3.151 node@26.12.1 downloading 2.7s 62.1/62.9 MB · 24.6 MB/s
|
|
||||||
244→#16 3.856 mise bun@1.4.4 1.4.4
|
|
||||||
245→#16 3.869 mise ✓ bun@1.4.4 3.4s bun-linux-x64.zip
|
|
||||||
246→#16 4.708 mise node@26.12.1 v26.12.1
|
|
||||||
247→#16 4.828 mise node@26.12.1 11.20.0
|
|
||||||
248→#16 4.861 mise ✓ node@26.12.1 4.4s node-v26.12.1-linux-x64.tar.gz
|
|
||||||
249→#16 4.861 mise ████████████████ 2/2 · installed 2 tools in 4.7s
|
|
||||||
250→#16 DONE 5.7s
|
|
||||||
251→#17 mkdir -p /app/node_modules/.cache
|
|
||||||
252→#17 DONE 0.2s
|
|
||||||
253→#18 copy bun.lock
|
|
||||||
254→#18 DONE 0.0s
|
|
||||||
255→#19 copy package.json
|
|
||||||
256→#19 DONE 0.1s
|
|
||||||
257→#20 copy /mise/shims
|
|
||||||
258→#20 DONE 0.0s
|
|
||||||
259→#21 copy skills/podcast-generate/package.json
|
|
||||||
260→#21 DONE 0.0s
|
|
||||||
261→#22 copy skills/skill-finder-cn/package.json
|
|
||||||
262→#22 DONE 0.0s
|
|
||||||
263→#23 copy skills/stock-analysis-skill/package.json
|
|
||||||
264→#23 DONE 0.0s
|
|
||||||
265→#24 copy skills/storyboard-manager/package.json
|
|
||||||
266→#24 DONE 0.0s
|
|
||||||
267→#25 copy prisma
|
|
||||||
268→#25 DONE 0.0s
|
|
||||||
269→#26 bun install --frozen-lockfile
|
|
||||||
270→#26 0.115 bun install v1.4.4 (38afee6c8)
|
|
||||||
271→#26 ...
|
|
||||||
272→#27 copy /mise/installs
|
|
||||||
273→#27 ...
|
|
||||||
274→#26 bun install --frozen-lockfile
|
|
||||||
275→#26 14.31
|
|
||||||
276→#26 14.31 + @tailwindcss/postcss@4.1.18
|
|
||||||
277→#26 14.31 + @types/react@19.2.8
|
|
||||||
278→#26 14.31 + @types/react-dom@19.2.3
|
|
||||||
279→#26 14.31 + bun-types@1.3.6
|
|
||||||
280→#26 14.31 + eslint@9.39.2
|
|
||||||
281→#26 14.31 + eslint-config-next@16.1.3
|
|
||||||
282→#26 14.31 + tailwindcss@4.1.18
|
|
||||||
283→#26 14.31 + tw-animate-css@1.4.0
|
|
||||||
284→#26 14.31 + typescript@5.9.3
|
|
||||||
285→#26 14.31 + @dnd-kit/core@6.3.1
|
|
||||||
286→#26 14.31 + @dnd-kit/sortable@10.0.0
|
|
||||||
287→#26 14.31 + @dnd-kit/utilities@3.2.2
|
|
||||||
288→#26 14.31 + @hookform/resolvers@5.2.2
|
|
||||||
289→#26 14.31 + @hugeicons/core-free-icons@4.3.5
|
|
||||||
290→#26 14.31 + @hugeicons/react@1.1.10
|
|
||||||
291→#26 14.31 + @mdxeditor/editor@3.52.3
|
|
||||||
292→#26 14.31 + @prisma/client@6.19.2
|
|
||||||
293→#26 14.31 + @radix-ui/react-accordion@1.2.12
|
|
||||||
294→#26 14.31 + @radix-ui/react-alert-dialog@1.1.15
|
|
||||||
295→#26 14.31 + @radix-ui/react-aspect-ratio@1.1.8
|
|
||||||
296→#26 14.31 + @radix-ui/react-avatar@1.1.11
|
|
||||||
297→#26 14.31 + @radix-ui/react-checkbox@1.3.3
|
|
||||||
298→#26 14.31 + @radix-ui/react-collapsible@1.1.12
|
|
||||||
299→#26 14.31 + @radix-ui/react-context-menu@2.2.16
|
|
||||||
300→#26 14.31 + @radix-ui/react-dialog@1.1.15
|
|
||||||
301→#26 14.31 + @radix-ui/react-dropdown-menu@2.1.16
|
|
||||||
302→#26 14.31 + @radix-ui/react-hover-card@1.1.15
|
|
||||||
303→#26 14.31 + @radix-ui/react-label@2.1.8
|
|
||||||
304→#26 14.31 + @radix-ui/react-menubar@1.1.16
|
|
||||||
305→#26 14.31 + @radix-ui/react-navigation-menu@1.2.14
|
|
||||||
306→#26 14.31 + @radix-ui/react-popover@1.1.15
|
|
||||||
307→#26 14.31 + @radix-ui/react-progress@1.1.8
|
|
||||||
308→#26 14.31 + @radix-ui/react-radio-group@1.3.8
|
|
||||||
309→#26 14.31 + @radix-ui/react-scroll-area@1.2.10
|
|
||||||
310→#26 14.31 + @radix-ui/react-select@2.2.6
|
|
||||||
311→#26 14.31 + @radix-ui/react-separator@1.1.8
|
|
||||||
312→#26 14.31 + @radix-ui/react-slider@1.3.6
|
|
||||||
313→#26 14.31 + @radix-ui/react-slot@1.2.4
|
|
||||||
314→#26 14.31 + @radix-ui/react-switch@1.2.6
|
|
||||||
315→#26 14.31 + @radix-ui/react-tabs@1.1.13
|
|
||||||
316→#26 14.31 + @radix-ui/react-toast@1.2.15
|
|
||||||
317→#26 14.31 + @radix-ui/react-toggle@1.1.10
|
|
||||||
318→#26 14.31 + @radix-ui/react-toggle-group@1.1.11
|
|
||||||
319→#26 14.31 + @radix-ui/react-tooltip@1.2.8
|
|
||||||
320→#26 14.31 + @reactuses/core@6.1.9
|
|
||||||
321→#26 14.31 + @tanstack/react-query@5.90.19
|
|
||||||
322→#26 14.31 + @tanstack/react-table@8.21.3
|
|
||||||
323→#26 14.31 + class-variance-authority@0.7.1
|
|
||||||
324→#26 14.31 + clsx@2.1.1
|
|
||||||
325→#26 14.31 + cmdk@1.1.1
|
|
||||||
326→#26 14.31 + date-fns@4.1.0
|
|
||||||
327→#26 14.31 + embla-carousel-react@8.6.0
|
|
||||||
328→#26 14.31 + framer-motion@14.7.1
|
|
||||||
329→#26 14.31 + imapflow@2.9.1
|
|
||||||
330→#26 14.31 + input-otp@1.4.2
|
|
||||||
331→#26 14.31 + lucide-react@1.62.0
|
|
||||||
332→#26 14.31 + motion@12.43.0
|
|
||||||
333→#26 14.31 + next@16.1.3
|
|
||||||
334→#26 14.31 + next-auth@4.24.13
|
|
||||||
335→#26 14.31 + next-intl@4.7.0
|
|
||||||
336→#26 14.31 + next-themes@0.4.6
|
|
||||||
337→#26 14.31 + prisma@6.19.2
|
|
||||||
338→#26 14.31 + react@19.2.3
|
|
||||||
339→#26 14.31 + react-day-picker@9.13.0
|
|
||||||
340→#26 14.31 + react-dom@19.2.3
|
|
||||||
341→#26 14.31 + react-hook-form@7.71.1
|
|
||||||
342→#26 14.31 + react-markdown@10.1.0
|
|
||||||
343→#26 14.31 + react-resizable-panels@3.0.6
|
|
||||||
344→#26 14.31 + react-syntax-highlighter@15.6.6
|
|
||||||
345→#26 14.31 + recharts@2.15.4
|
|
||||||
346→#26 14.31 + sharp@0.34.5
|
|
||||||
347→#26 14.31 + sonner@2.0.7
|
|
||||||
348→#26 14.31 + tailwind-merge@3.7.0
|
|
||||||
349→#26 14.31 + tailwindcss-animate@1.0.7
|
|
||||||
350→#26 14.31 + uuid@11.1.0
|
|
||||||
351→#26 14.31 + vaul@1.1.2
|
|
||||||
352→#26 14.31 + z-ai-web-dev-sdk@0.0.18
|
|
||||||
353→#26 14.31 + zod@4.3.5
|
|
||||||
354→#26 14.31 + zustand@5.0.10
|
|
||||||
355→#26 14.31
|
|
||||||
356→#26 14.31 858 packages installed [14.19s]
|
|
||||||
357→#26 DONE 16.1s
|
|
||||||
358→#28 copy / /app
|
|
||||||
359→#28 ...
|
|
||||||
360→#27 copy /mise/installs
|
|
||||||
361→#27 DONE 7.3s
|
|
||||||
362→#29 copy /usr/local/bin/mise
|
|
||||||
363→#29 DONE 1.2s
|
|
||||||
364→#28 copy / /app
|
|
||||||
365→#28 ...
|
|
||||||
366→#30 copy /etc/mise/config.toml
|
|
||||||
367→#30 DONE 0.1s
|
|
||||||
368→#31 copy /root/.local/state/mise
|
|
||||||
369→#31 DONE 0.0s
|
|
||||||
370→#28 copy / /app
|
|
||||||
371→#28 DONE 2.7s
|
|
||||||
372→#32 bun run build
|
|
||||||
373→#32 0.169 $ next build && cp -r .next/static .next/standalone/.next/ && cp -r public .next/standalone/
|
|
||||||
374→#32 0.359 ⚠ You are using a non-standard "NODE_ENV" value in your environment. This creates inconsistencies in the project and is strongly advised against. Read more: https://nextjs.org/docs/messages/non-standard-node-env
|
|
||||||
375→#32 1.293 ▲ Next.js 16.1.3 (Turbopack)
|
|
||||||
376→#32 1.294 - Environments: .env
|
|
||||||
377→#32 1.294
|
|
||||||
378→#32 1.340 Creating an optimized production build ...
|
|
||||||
379→#32 13.17 (node:98) [DEP0205] DeprecationWarning: `module.register()` is deprecated. Use `module.registerHooks()` instead.
|
|
||||||
380→#32 13.17 (Use `node --trace-deprecation ...` to show where the warning was created)
|
|
||||||
381→#32 31.57
|
|
||||||
382→#32 31.57 > Build error occurred
|
|
||||||
383→#32 31.57 Error: Turbopack build failed with 1 errors:
|
|
||||||
384→#32 31.57 ./node_modules/@prisma/client/index-browser.js:1:16
|
|
||||||
385→#32 31.57 Module not found: Can't resolve '.prisma/client/index-browser'
|
|
||||||
386→#32 31.57 [0m[31m[1m>[22m[39m[90m 1 |[39m [36mconst[39m prisma [33m=[39m require([32m'.prisma/client/index-browser'[39m)
|
|
||||||
387→#32 31.57 [90m |[39m [31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m
|
|
||||||
388→#32 31.57 [90m 2 |[39m
|
|
||||||
389→#32 31.57 [90m 3 |[39m module[33m.[39mexports [33m=[39m prisma
|
|
||||||
390→#32 31.57 [90m 4 |[39m[0m
|
|
||||||
391→#32 31.57
|
|
||||||
392→#32 31.57
|
|
||||||
393→#32 31.57
|
|
||||||
394→#32 31.57 Import trace:
|
|
||||||
395→#32 31.57 Client Component Browser:
|
|
||||||
396→#32 31.57 ./node_modules/@prisma/client/index-browser.js [Client Component Browser]
|
|
||||||
397→#32 31.57 ./src/lib/db.ts [Client Component Browser]
|
|
||||||
398→#32 31.57 ./src/components/aos/portal-shell.tsx [Client Component Browser]
|
|
||||||
399→#32 31.57 ./src/components/aos/app-shell.tsx [Client Component Browser]
|
|
||||||
400→#32 31.57 ./src/components/aos/app-shell.tsx [Server Component]
|
|
||||||
401→#32 31.57 ./src/app/page.tsx [Server Component]
|
|
||||||
402→#32 31.57
|
|
||||||
403→#32 31.57 https://nextjs.org/docs/messages/module-not-found
|
|
||||||
404→#32 31.57
|
|
||||||
405→#32 31.57
|
|
||||||
406→#32 31.57 at ./node_modules/ (prisma/client/index-browser.js:1:16)
|
|
||||||
407→#32 31.57 at <unknown> (https://nextjs.org/docs/messages/module-not-found)
|
|
||||||
408→#32 31.72 error: script "build" exited with code 1
|
|
||||||
409→#32 ERROR: process "bun run build" did not complete successfully: exit code: 1
|
|
||||||
410→------
|
|
||||||
411→> bun run build:
|
|
||||||
412→31.57 ./src/components/aos/app-shell.tsx [Client Component Browser]
|
|
||||||
413→31.57 ./src/components/aos/app-shell.tsx [Server Component]
|
|
||||||
414→31.57 ./src/app/page.tsx [Server Component]
|
|
||||||
415→31.57
|
|
||||||
416→31.57 https://nextjs.org/docs/messages/module-not-found
|
|
||||||
417→31.57
|
|
||||||
418→31.57
|
|
||||||
419→31.57 at ./node_modules/ (prisma/client/index-browser.js:1:16)
|
|
||||||
420→31.57 at <unknown> (https://nextjs.org/docs/messages/module-not-found)
|
|
||||||
421→31.72 error: script "build" exited with code 1
|
|
||||||
422→------
|
|
||||||
423→ERROR: failed to build: failed to solve: process "bun run build" did not complete successfully: exit code: 1
|
|
||||||
424→❌ Railpack build failed
|
|
||||||
425→railpack-dfm-aos-lgbcnc-INtHrR removed
|
|
||||||
426→Error occurred ❌, check the logs for details.
|
|
||||||
@@ -1,426 +0,0 @@
|
|||||||
Initializing deployment
|
|
||||||
Cloning Repo github.com/cetinmustafa83/aos.git to /etc/dokploy/applications/dfm-aos-lgbcnc/code: ✅
|
|
||||||
Cloning into '/etc/dokploy/applications/dfm-aos-lgbcnc/code'...
|
|
||||||
remote: Enumerating objects: 1836, done.
|
|
||||||
remote: Counting objects: 0% (1/1836)
remote: Counting objects: 1% (19/1836)
remote: Counting objects: 2% (37/1836)
remote: Counting objects: 3% (56/1836)
remote: Counting objects: 4% (74/1836)
remote: Counting objects: 5% (92/1836)
remote: Counting objects: 6% (111/1836)
remote: Counting objects: 7% (129/1836)
remote: Counting objects: 8% (147/1836)
remote: Counting objects: 9% (166/1836)
remote: Counting objects: 10% (184/1836)
remote: Counting objects: 11% (202/1836)
remote: Counting objects: 12% (221/1836)
remote: Counting objects: 13% (239/1836)
remote: Counting objects: 14% (258/1836)
remote: Counting objects: 15% (276/1836)
remote: Counting objects: 16% (294/1836)
remote: Counting objects: 17% (313/1836)
remote: Counting objects: 18% (331/1836)
remote: Counting objects: 19% (349/1836)
remote: Counting objects: 20% (368/1836)
remote: Counting objects: 21% (386/1836)
remote: Counting objects: 22% (404/1836)
remote: Counting objects: 23% (423/1836)
remote: Counting objects: 24% (441/1836)
remote: Counting objects: 25% (459/1836)
remote: Counting objects: 26% (478/1836)
remote: Counting objects: 27% (496/1836)
remote: Counting objects: 28% (515/1836)
remote: Counting objects: 29% (533/1836)
remote: Counting objects: 30% (551/1836)
remote: Counting objects: 31% (570/1836)
remote: Counting objects: 32% (588/1836)
remote: Counting objects: 33% (606/1836)
remote: Counting objects: 34% (625/1836)
remote: Counting objects: 35% (643/1836)
remote: Counting objects: 36% (661/1836)
remote: Counting objects: 37% (680/1836)
remote: Counting objects: 38% (698/1836)
remote: Counting objects: 39% (717/1836)
remote: Counting objects: 40% (735/1836)
remote: Counting objects: 41% (753/1836)
remote: Counting objects: 42% (772/1836)
remote: Counting objects: 43% (790/1836)
remote: Counting objects: 44% (808/1836)
remote: Counting objects: 45% (827/1836)
remote: Counting objects: 46% (845/1836)
remote: Counting objects: 47% (863/1836)
remote: Counting objects: 48% (882/1836)
remote: Counting objects: 49% (900/1836)
remote: Counting objects: 50% (918/1836)
remote: Counting objects: 51% (937/1836)
remote: Counting objects: 52% (955/1836)
remote: Counting objects: 53% (974/1836)
remote: Counting objects: 54% (992/1836)
remote: Counting objects: 55% (1010/1836)
remote: Counting objects: 56% (1029/1836)
remote: Counting objects: 57% (1047/1836)
remote: Counting objects: 58% (1065/1836)
remote: Counting objects: 59% (1084/1836)
remote: Counting objects: 60% (1102/1836)
remote: Counting objects: 61% (1120/1836)
remote: Counting objects: 62% (1139/1836)
remote: Counting objects: 63% (1157/1836)
remote: Counting objects: 64% (1176/1836)
remote: Counting objects: 65% (1194/1836)
remote: Counting objects: 66% (1212/1836)
remote: Counting objects: 67% (1231/1836)
remote: Counting objects: 68% (1249/1836)
remote: Counting objects: 69% (1267/1836)
remote: Counting objects: 70% (1286/1836)
remote: Counting objects: 71% (1304/1836)
remote: Counting objects: 72% (1322/1836)
remote: Counting objects: 73% (1341/1836)
remote: Counting objects: 74% (1359/1836)
remote: Counting objects: 75% (1377/1836)
remote: Counting objects: 76% (1396/1836)
remote: Counting objects: 77% (1414/1836)
remote: Counting objects: 78% (1433/1836)
remote: Counting objects: 79% (1451/1836)
remote: Counting objects: 80% (1469/1836)
remote: Counting objects: 81% (1488/1836)
remote: Counting objects: 82% (1506/1836)
remote: Counting objects: 83% (1524/1836)
remote: Counting objects: 84% (1543/1836)
remote: Counting objects: 85% (1561/1836)
remote: Counting objects: 86% (1579/1836)
remote: Counting objects: 87% (1598/1836)
remote: Counting objects: 88% (1616/1836)
remote: Counting objects: 89% (1635/1836)
remote: Counting objects: 90% (1653/1836)
remote: Counting objects: 91% (1671/1836)
remote: Counting objects: 92% (1690/1836)
remote: Counting objects: 93% (1708/1836)
remote: Counting objects: 94% (1726/1836)
remote: Counting objects: 95% (1745/1836)
remote: Counting objects: 96% (1763/1836)
remote: Counting objects: 97% (1781/1836)
remote: Counting objects: 98% (1800/1836)
remote: CounLine truncated
|
|
||||||
remote: Compressing objects: 0% (1/1379)
remote: Compressing objects: 1% (14/1379)
remote: Compressing objects: 2% (28/1379)
remote: Compressing objects: 3% (42/1379)
remote: Compressing objects: 4% (56/1379)
remote: Compressing objects: 5% (69/1379)
remote: Compressing objects: 6% (83/1379)
remote: Compressing objects: 7% (97/1379)
remote: Compressing objects: 8% (111/1379)
remote: Compressing objects: 9% (125/1379)
remote: Compressing objects: 10% (138/1379)
remote: Compressing objects: 11% (152/1379)
remote: Compressing objects: 12% (166/1379)
remote: Compressing objects: 13% (180/1379)
remote: Compressing objects: 14% (194/1379)
remote: Compressing objects: 15% (207/1379)
remote: Compressing objects: 16% (221/1379)
remote: Compressing objects: 17% (235/1379)
remote: Compressing objects: 18% (249/1379)
remote: Compressing objects: 19% (263/1379)
remote: Compressing objects: 20% (276/1379)
remote: Compressing objects: 21% (290/1379)
remote: Compressing objects: 22% (304/1379)
remote: Compressing objects: 23% (318/1379)
remote: Compressing objects: 24% (331/1379)
remote: Compressing objects: 25% (345/1379)
remote: Compressing objects: 26% (359/1379)
remote: Compressing objects: 27% (373/1379)
remote: Compressing objects: 28% (387/1379)
remote: Compressing objects: 29% (400/1379)
remote: Compressing objects: 30% (414/1379)
remote: Compressing objects: 31% (428/1379)
remote: Compressing objects: 32% (442/1379)
remote: Compressing objects: 33% (456/1379)
remote: Compressing objects: 34% (469/1379)
remote: Compressing objects: 35% (483/1379)
remote: Compressing objects: 36% (497/1379)
remote: Compressing objects: 37% (511/1379)
remote: Compressing objects: 38% (525/1379)
remote: Compressing objects: 39% (538/1379)
remote: Compressing objects: 40% (552/1379)
remote: Compressing objects: 41% (566/1379)
remote: Compressing objects: 42% (580/1379)
remote: Compressing objects: 43% (593/1379)
remote: Compressing objects: 44% (607/1379)
remote: Compressing objects: 45% (621/1379)
remote: Compressing objects: 46% (635/1379)
remote: Compressing objects: 47% (649/1379)
remote: Compressing objects: 48% (662/1379)
remote: Compressing objects: 49% (676/1379)
remote: Compressing objects: 50% (690/1379)
remote: Compressing objects: 51% (704/1379)
remote: Compressing objects: 52% (718/1379)
remote: Compressing objects: 53% (731/1379)
remote: Compressing objects: 54% (745/1379)
remote: Compressing objects: 55% (759/1379)
remote: Compressing objects: 56% (773/1379)
remote: Compressing objects: 57% (787/1379)
remote: Compressing objects: 58% (800/1379)
remote: Compressing objects: 59% (814/1379)
remote: Compressing objects: 60% (828/1379)
remote: Compressing objects: 61% (842/1379)
remote: Compressing objects: 62% (855/1379)
remote: Compressing objects: 63% (869/1379)
remote: Compressing objects: 64% (883/1379)
remote: Compressing objects: 65% (897/1379)
remote: Compressing objects: 66% (911/1379)
remote: Compressing objects: 67% (924/1379)
remote: Compressing objects: 68% (938/1379)
remote: Compressing objects: 69% (952/1379)
remote: Compressing objects: 70% (966/1379)
remote: Compressing objects: 71% (980/1379)
remote: Compressing objects: 72% (993/1379)
remote: Compressing objects: 73% (1007/1379)
remote: Compressing objects: 74% (1021/1379)
remote: Compressing objects: 75% (1035/1379)
remote: Compressing objects: 76% (1049/1379)
remote: Compressing objects: 77% (1062/1379)
remote: Compressing objects: 78% (1076/1379)
remote: Compressing objects: 79% (1090/1379)
remote: Compressing objects: 80% (1104/1379)
remote: Compressing objects: 81% (1117/1379)
remote: Compressing objects: 82% (1131/1379)
remote: Compressing objects: 83% (1145/1379)
remote: Compressing objects: 84% (1159/1379)
remote: Compressing objects: 85% (1173/1379)
remote: Compressing objects: 86% (1186/1379)
remote: Compressing objects: 87% (1200/1379)
remote: Compressing objects: 88% (1214/1379)
remote: Compressing objects: 89% (1228/1379)
remote: Compressing objects: 90% (1242/1379)
remote: Compressing objects: 91% (1255/1379)
remote: Compressing objects: 92% (1269/1379)
remote: Compressing objects: 93% (1283/1379)
remotLine truncated
|
|
||||||
Receiving objects: 0% (1/1836)
Receiving objects: 1% (19/1836)
Receiving objects: 2% (37/1836)
Receiving objects: 3% (56/1836)
Receiving objects: 4% (74/1836)
Receiving objects: 5% (92/1836)
Receiving objects: 6% (111/1836)
Receiving objects: 7% (129/1836)
Receiving objects: 8% (147/1836)
Receiving objects: 9% (166/1836)
Receiving objects: 10% (184/1836)
Receiving objects: 11% (202/1836)
Receiving objects: 12% (221/1836)
Receiving objects: 13% (239/1836)
Receiving objects: 14% (258/1836)
Receiving objects: 15% (276/1836)
Receiving objects: 16% (294/1836)
Receiving objects: 17% (313/1836)
Receiving objects: 18% (331/1836)
Receiving objects: 19% (349/1836)
Receiving objects: 20% (368/1836)
Receiving objects: 21% (386/1836)
Receiving objects: 22% (404/1836)
Receiving objects: 23% (423/1836)
Receiving objects: 24% (441/1836)
Receiving objects: 25% (459/1836)
Receiving objects: 26% (478/1836)
Receiving objects: 27% (496/1836)
Receiving objects: 28% (515/1836)
Receiving objects: 29% (533/1836)
Receiving objects: 30% (551/1836)
Receiving objects: 31% (570/1836)
Receiving objects: 32% (588/1836)
Receiving objects: 33% (606/1836)
Receiving objects: 34% (625/1836)
Receiving objects: 35% (643/1836)
Receiving objects: 36% (661/1836)
Receiving objects: 37% (680/1836)
Receiving objects: 38% (698/1836)
Receiving objects: 39% (717/1836)
Receiving objects: 40% (735/1836)
Receiving objects: 41% (753/1836)
Receiving objects: 42% (772/1836)
Receiving objects: 43% (790/1836)
Receiving objects: 44% (808/1836)
Receiving objects: 45% (827/1836), 14.90 MiB | 29.78 MiB/s
Receiving objects: 46% (845/1836), 14.90 MiB | 29.78 MiB/s
Receiving objects: 47% (863/1836), 14.90 MiB | 29.78 MiB/s
Receiving objects: 48% (882/1836), 14.90 MiB | 29.78 MiB/s
Receiving objects: 49% (900/1836), 14.90 MiB | 29.78 MiB/s
Receiving objects: 50% (918/1836), 14.90 MiB | 29.78 MiB/s
Receiving objects: 51% (937/1836), 14.90 MiB | 29.78 MiB/s
Receiving objects: 52% (955/1836), 14.90 MiB | 29.78 MiB/s
Receiving objects: 52% (973/1836), 30.91 MiB | 30.91 MiB/s
Receiving objects: 53% (974/1836), 30.91 MiB | 30.91 MiB/s
Receiving objects: 54% (992/1836), 30.91 MiB | 30.91 MiB/s
Receiving objects: 55% (1010/1836), 30.91 MiB | 30.91 MiB/s
Receiving objects: 56% (1029/1836), 30.91 MiB | 30.91 MiB/s
Receiving objects: 57% (1047/1836), 30.91 MiB | 30.91 MiB/s
Receiving objects: 58% (1065/1836), 30.91 MiB | 30.91 MiB/s
Receiving objects: 59% (1084/1836), 30.91 MiB | 30.91 MiB/s
Receiving objects: 60% (1102/1836), 30.91 MiB | 30.91 MiB/s
Receiving objects: 61% (1120/1836), 30.91 MiB | 30.91 MiB/s
Receiving objects: 62% (1139/1836), 30.91 MiB | 30.91 MiB/s
Receiving objects: 63% (1157/1836), 30.91 MiB | 30.91 MiB/s
Receiving objects: 64% (1176/1836), 30.91 MiB | 30.91 MiB/s
Receiving objects: 65% (1194/1836), 30.91 MiB | 30.91 MiB/s
Receiving objects: 66% (1212/1836), 30.91 MiB | 30.91 MiB/s
Receiving objects: 67% (1231/1836), 30.91 MiB | 30.91 MiB/s
Receiving objects: 68% (1249/1836), 30.91 MiB | 30.91 MiB/s
Receiving objects: 69% (1267/1836), 30.91 MiB | 30.91 MiB/s
Receiving objects: 70% (1286/1836), 30.91 MiB | 30.91 MiB/s
Receiving objects: 71% (1304/1836), 30.91 MiB | 30.91 MiB/s
Receiving objects: 72% (1322/1836), 30.91 MiB | 30.91 MiB/s
Receiving objects: 73% (1341/1836), 30.91 MiB | 30.91 MiB/s
Receiving objects: 74% (1359/1836), 30.91 MiB | 30.91 MiB/s
Receiving objects: 75% (1377/1836), 30.91 MiB | 30.91 MiB/s
Receiving objects: 76% (1396/1836), 30.91 MiB | 30.91 MiB/s
Receiving objects: 77% (1414/1836), 30.91 MiB | 30.91 MiB/s
Receiving objects: 78% (1433/1836), 30.91 MiB | 30.91 MiB/s
Receiving objects: 79% (1451/1836), 30.91 MiB | 30.91 MiB/s
Receiving objects: 80% (1469/1836), 30.91 MiB | 30.91 MiB/s
Receiving objects: 81% (1488/1836), 30.91 MiB | 30.91 MiB/s
Receiving objects: 82% (1506/1836), 30.91 MiB | 30.91 MiB/s
Receiving objects: 83% (1524/1836), 30.91 MiB | 30.91 MiB/s
Receiving objects: 84% (1543/1836), 30.91 MiB | 30.91 MiB/s
Receiving objects: 85% (1561/1836), 30.91 MiB | 30.91 MiB/s
Receiving objects: 86% (1579/1836), 30.91 MiB | 30.91 MiB/s
Receiving objects: 87% (1598/1836), 30.91 MiB | 30.91 MiB/s
Receiving objects: 88% (1616/1836), 30.91 MiB | 30.91 MiB/s
Receiving objects: 89% (1635/1836), 30.91 MiB | 30.91 MiB/s
Receiving objects: 90% (1653/1836), 30.91 MiB | 30.91 MiB/s
Receiving objects: 91% (1671/1836), 30.91 MiB | 30.91 MiB/s
Receiving objects: 92% (1690/1836), 30.91 MiB | 30.91 MiB/s
Receiving objects: 93% (1708/1836), 30.91 MiB | 30.91 MiB/s
Receiving objects: 94% (1726/1836), 30.91 MiB | 30.91 MiB/s
Receiving objects: 95% (1745/1836), 47.46 MiB | 31.63 MiB/s
Receiving objects: 96% (1763/1836), 47.46 MiB | 31.63 MiB/s
Receiving objects: 97% (1781/1836), 47.46 MiB | 31.63 MiB/s
Receiving objects: 98% (1800/1836), 47.46 MiB | 31.63 MiB/s
Receiving objects: 99% (1818/1836), 47.46 MiB | 31.63 MiB/s
remote: Total 1836 (delta Line truncated
|
|
||||||
Receiving objects: 100% (1836/1836), 47.46 MiB | 31.63 MiB/s␍Receiving objects: 100% (1836/1836), 47.65 MiB | 31.60 MiB/s, done.
|
|
||||||
Resolving deltas: 0% (0/316)␍Resolving deltas: 1% (4/316)␍Resolving deltas: 2% (7/316)␍Resolving deltas: 3% (10/316)␍Resolving deltas: 4% (13/316)␍Resolving deltas: 5% (16/316)␍Resolving deltas: 6% (19/316)␍Resolving deltas: 7% (23/316)␍Resolving deltas: 8% (26/316)␍Resolving deltas: 9% (29/316)␍Resolving deltas: 10% (32/316)␍Resolving deltas: 11% (35/316)␍Resolving deltas: 12% (38/316)␍Resolving deltas: 13% (42/316)␍Resolving deltas: 14% (45/316)␍Resolving deltas: 15% (48/316)␍Resolving deltas: 16% (51/316)␍Resolving deltas: 17% (54/316)␍Resolving deltas: 18% (57/316)␍Resolving deltas: 19% (61/316)␍Resolving deltas: 20% (64/316)␍Resolving deltas: 21% (67/316)␍Resolving deltas: 22% (70/316)␍Resolving deltas: 23% (73/316)␍Resolving deltas: 24% (76/316)␍Resolving deltas: 25% (79/316)␍Resolving deltas: 26% (83/316)␍Resolving deltas: 27% (86/316)␍Resolving deltas: 28% (89/316)␍Resolving deltas: 29% (92/316)␍Resolving deltas: 30% (95/316)␍Resolving deltas: 31% (98/316)␍Resolving deltas: 32% (102/316)␍Resolving deltas: 33% (105/316)␍Resolving deltas: 34% (108/316)␍Resolving deltas: 35% (111/316)␍Resolving deltas: 36% (114/316)␍Resolving deltas: 37% (117/316)␍Resolving deltas: 38% (121/316)␍Resolving deltas: 39% (124/316)␍Resolving deltas: 40% (127/316)␍Resolving deltas: 41% (130/316)␍Resolving deltas: 42% (133/316)␍Resolving deltas: 43% (136/316)␍Resolving deltas: 44% (140/316)␍Resolving deltas: 45% (143/316)␍Resolving deltas: 46% (146/316)␍Resolving deltas: 47% (149/316)␍Resolving deltas: 48% (152/316)␍Resolving deltas: 49% (155/316)␍Resolving deltas: 50% (159/316)␍Resolving deltas: 51% (162/316)␍Resolving deltas: 52% (165/316)␍Resolving deltas: 53% (168/316)␍Resolving deltas: 54% (171/316)␍Resolving deltas: 55% (174/316)␍Resolving deltas: 56% (177/316)␍Resolving deltas: 57% (182/316)␍Resolving deltas: 58% (184/316)␍Resolving deltas: 59% (188/316)␍Resolving deltas: 60% (190/316)␍Resolving deltas: 61% (193/316)␍Resolving deltas: 62% (196/316)␍Resolving deltas: 63% (200/316)␍Resolving deltas: 64% (203/316)␍Resolving deltas: 65% (206/316)␍Resolving deltas: 66% (209/316)␍Resolving deltas: 67% (213/316)␍Resolving deltas: 68% (215/316)␍Resolving deltas: 69% (219/316)␍Resolving deltas: 70% (222/316)␍Resolving deltas: 71% (225/316)␍Resolving deltas: 72% (229/316)␍Resolving deltas: 73% (231/316)␍Resolving deltas: 74% (234/316)␍Resolving deltas: 75% (237/316)␍Resolving deltas: 76% (241/316)␍Resolving deltas: 77% (244/316)␍Resolving deltas: 78% (247/316)␍Resolving deltas: 79% (250/316)␍Resolving deltas: 80% (253/316)␍Resolving deltas: 81% (256/316)␍Resolving deltas: 82% (260/316)␍Resolving deltas: 83% (263/316)␍Resolving deltas: 84% (267/316)␍Resolving deltas: 85% (269/316)␍Resolving deltas: 86% (272/316)␍Resolving deltas: 87% (276/316)␍Resolving deltas: 88% (279/316)␍Resolving deltas: 89% (282/316)␍Resolving deltas: 90% (285/316)␍Resolving deltas: 91% (288/316)␍Resolving deltas: 92% (291/316)␍Resolving deltas: 93% (294/316)␍Resolving deltas: 94% (298/316)␍Resolving deltas: 95% (301/316)␍Resolving deltas: 96% (304/316)␍Resolving deltas: 97% (307/316)␍Resolving deltas: 98% (310/316)␍Resolving deltas: 99% (313/316)␍Resolving deltas: 100% (316/316)␍Resolving deltas: 100% (316/316), done.
|
|
||||||
> Installing railpack, please wait…
|
|
||||||
____ _ _ _
|
|
||||||
| _ \ __ _(_) |_ __ __ _ ___| | __
|
|
||||||
| |_) / _` | | | '_ \ / _` |/ __| |/ /
|
|
||||||
| _ < (_| | | | |_) | (_| | (__| <
|
|
||||||
|_| \_\__,_|_|_| .__/ \__,_|\___|_|\_\
|
|
||||||
|_|
|
|
||||||
Railpack is now installed!
|
|
||||||
Run 'railpack --help' to get started
|
|
||||||
railpack-dfm-aos-lgbcnc-INtHrR
|
|
||||||
Preparing Railpack build plan...
|
|
||||||
╭─────────────────╮
|
|
||||||
│ Railpack 0.15.4 │
|
|
||||||
╰─────────────────╯
|
|
||||||
↳ Detected Node
|
|
||||||
↳ Using bun package manager
|
|
||||||
Packages
|
|
||||||
──────────
|
|
||||||
bun │ 1.4.4 │ railpack default (latest)
|
|
||||||
node │ 26.12.1 │ railpack default (latest)
|
|
||||||
Steps
|
|
||||||
──────────
|
|
||||||
▸ install
|
|
||||||
$ bun install --frozen-lockfile
|
|
||||||
▸ build
|
|
||||||
$ bun run build
|
|
||||||
Deploy
|
|
||||||
──────────
|
|
||||||
$ bun run start
|
|
||||||
✅ Railpack prepare completed.
|
|
||||||
Building with Railpack frontend...
|
|
||||||
#0 building with "railpack-dfm-aos-lgbcnc-INtHrR" instance using docker-container driver
|
|
||||||
#1 [internal] booting buildkit
|
|
||||||
#1 pulling image moby/buildkit:buildx-stable-1
|
|
||||||
#1 pulling image moby/buildkit:buildx-stable-1 1.1s done
|
|
||||||
#1 creating container buildx_buildkit_railpack-dfm-aos-lgbcnc-inthrr0
|
|
||||||
#1 creating container buildx_buildkit_railpack-dfm-aos-lgbcnc-inthrr0 0.6s done
|
|
||||||
#1 DONE 1.7s
|
|
||||||
#2 resolve image config for docker-image://ghcr.io/railwayapp/railpack-frontend:v0.15.4
|
|
||||||
#2 DONE 1.4s
|
|
||||||
#3 docker-image://ghcr.io/railwayapp/railpack-frontend:v0.15.4@sha256:7e0535e519d9d00793d0bb4e652be5d48373ab5e0c7d9b90ef6bc40147290ff7
|
|
||||||
#3 resolve ghcr.io/railwayapp/railpack-frontend:v0.15.4@sha256:7e0535e519d9d00793d0bb4e652be5d48373ab5e0c7d9b90ef6bc40147290ff7 0.0s done
|
|
||||||
#3 sha256:76fdf18f436616aff2234f2d325d888d31af103f333a8f491d539dce0106e849 0B / 7.90MB 0.2s
|
|
||||||
#3 sha256:76fdf18f436616aff2234f2d325d888d31af103f333a8f491d539dce0106e849 2.10MB / 7.90MB 0.3s
|
|
||||||
#3 sha256:1074353eec0db2c1d81d5af2671e56e00cf5738486f5762609ea33d606f88612 0B / 3.86MB 0.2s
|
|
||||||
#3 sha256:76fdf18f436616aff2234f2d325d888d31af103f333a8f491d539dce0106e849 7.90MB / 7.90MB 0.4s done
|
|
||||||
#3 sha256:1074353eec0db2c1d81d5af2671e56e00cf5738486f5762609ea33d606f88612 3.86MB / 3.86MB 0.5s done
|
|
||||||
#3 extracting sha256:1074353eec0db2c1d81d5af2671e56e00cf5738486f5762609ea33d606f88612 0.1s done
|
|
||||||
#3 DONE 0.7s
|
|
||||||
#3 docker-image://ghcr.io/railwayapp/railpack-frontend:v0.15.4@sha256:7e0535e519d9d00793d0bb4e652be5d48373ab5e0c7d9b90ef6bc40147290ff7
|
|
||||||
#3 extracting sha256:76fdf18f436616aff2234f2d325d888d31af103f333a8f491d539dce0106e849 0.1s done
|
|
||||||
#3 DONE 0.8s
|
|
||||||
#4 load build definition from railpack-plan.json
|
|
||||||
#4 transferring dockerfile: 5.11kB done
|
|
||||||
#4 DONE 0.0s
|
|
||||||
#5 [railpack] secrets hash
|
|
||||||
#5 DONE 0.0s
|
|
||||||
#6 loading .
|
|
||||||
#6 DONE 0.0s
|
|
||||||
#7 [railpack] loading secrets
|
|
||||||
#7 resolve docker.io/library/alpine:latest
|
|
||||||
#7 ...
|
|
||||||
#8 docker-image://ghcr.io/railwayapp/railpack-builder:latest
|
|
||||||
#8 resolve ghcr.io/railwayapp/railpack-builder:latest 0.9s done
|
|
||||||
#8 DONE 1.0s
|
|
||||||
#8 docker-image://ghcr.io/railwayapp/railpack-builder:latest
|
|
||||||
#8 sha256:193926ad1d06489b7487e8ac4ae2d0874e6ff05cf65d874d2af508830fc03def 0B / 119B 0.2s
|
|
||||||
#8 sha256:df614908d6aba31e983953b17fd48496d27425529b3947c3d5583c4cc9c15c9a 0B / 868.40kB 0.2s
|
|
||||||
#8 sha256:193926ad1d06489b7487e8ac4ae2d0874e6ff05cf65d874d2af508830fc03def 119B / 119B 0.3s done
|
|
||||||
#8 sha256:df614908d6aba31e983953b17fd48496d27425529b3947c3d5583c4cc9c15c9a 868.40kB / 868.40kB 0.3s done
|
|
||||||
#8 sha256:604add184d03d4cf6e2ff1c4b9013b265eb9c11570afe28ce8f9dc417b98ea3f 0B / 237.08MB 0.2s
|
|
||||||
#8 sha256:08a1e03b3da5bb4a1059032dca3216f33ddfc4a48a45db88921f5bb2e9a8fa2d 0B / 53.72MB 0.2s
|
|
||||||
#8 sha256:4f4fb700ef54461cfa02571ae0db9a0dc1e0cdb5577484a6d75e68dc38e8acc1 0B / 32B 0.2s
|
|
||||||
#8 ...
|
|
||||||
#5 [railpack] secrets hash
|
|
||||||
#5 DONE 0.0s
|
|
||||||
#8 docker-image://ghcr.io/railwayapp/railpack-builder:latest
|
|
||||||
#8 sha256:4f4fb700ef54461cfa02571ae0db9a0dc1e0cdb5577484a6d75e68dc38e8acc1 32B / 32B 0.2s done
|
|
||||||
#8 sha256:4dc3950125ebc9ed195e1101fc6c02e2fce113ba0f53bfb05b2cdf58747df9af 0B / 67.81MB 0.2s
|
|
||||||
#8 sha256:08a1e03b3da5bb4a1059032dca3216f33ddfc4a48a45db88921f5bb2e9a8fa2d 7.34MB / 53.72MB 0.5s
|
|
||||||
#8 sha256:62fe2e747f69f2f414c7e9eb1553155cf0a658398f0462557f458821dce2b29d 0B / 25.64MB 0.2s
|
|
||||||
#8 sha256:604add184d03d4cf6e2ff1c4b9013b265eb9c11570afe28ce8f9dc417b98ea3f 17.83MB / 237.08MB 0.6s
|
|
||||||
#8 sha256:4dc3950125ebc9ed195e1101fc6c02e2fce113ba0f53bfb05b2cdf58747df9af 7.34MB / 67.81MB 0.5s
|
|
||||||
#8 sha256:08a1e03b3da5bb4a1059032dca3216f33ddfc4a48a45db88921f5bb2e9a8fa2d 14.68MB / 53.72MB 0.8s
|
|
||||||
#8 sha256:62fe2e747f69f2f414c7e9eb1553155cf0a658398f0462557f458821dce2b29d 6.29MB / 25.64MB 0.5s
|
|
||||||
#8 sha256:604add184d03d4cf6e2ff1c4b9013b265eb9c11570afe28ce8f9dc417b98ea3f 30.41MB / 237.08MB 0.9s
|
|
||||||
#8 sha256:4dc3950125ebc9ed195e1101fc6c02e2fce113ba0f53bfb05b2cdf58747df9af 14.68MB / 67.81MB 0.8s
|
|
||||||
#8 sha256:62fe2e747f69f2f414c7e9eb1553155cf0a658398f0462557f458821dce2b29d 10.49MB / 25.64MB 0.6s
|
|
||||||
#8 sha256:08a1e03b3da5bb4a1059032dca3216f33ddfc4a48a45db88921f5bb2e9a8fa2d 18.87MB / 53.72MB 1.1s
|
|
||||||
#8 sha256:62fe2e747f69f2f414c7e9eb1553155cf0a658398f0462557f458821dce2b29d 14.68MB / 25.64MB 0.8s
|
|
||||||
#8 sha256:62fe2e747f69f2f414c7e9eb1553155cf0a658398f0462557f458821dce2b29d 17.83MB / 25.64MB 0.9s
|
|
||||||
#8 sha256:604add184d03d4cf6e2ff1c4b9013b265eb9c11570afe28ce8f9dc417b98ea3f 48.23MB / 237.08MB 1.4s
|
|
||||||
#8 sha256:08a1e03b3da5bb4a1059032dca3216f33ddfc4a48a45db88921f5bb2e9a8fa2d 23.07MB / 53.72MB 1.4s
|
|
||||||
#8 sha256:4dc3950125ebc9ed195e1101fc6c02e2fce113ba0f53bfb05b2cdf58747df9af 22.02MB / 67.81MB 1.1s
|
|
||||||
#8 sha256:62fe2e747f69f2f414c7e9eb1553155cf0a658398f0462557f458821dce2b29d 23.07MB / 25.64MB 1.1s
|
|
||||||
#8 sha256:08a1e03b3da5bb4a1059032dca3216f33ddfc4a48a45db88921f5bb2e9a8fa2d 26.21MB / 53.72MB 1.5s
|
|
||||||
#8 sha256:4dc3950125ebc9ed195e1101fc6c02e2fce113ba0f53bfb05b2cdf58747df9af 29.36MB / 67.81MB 1.4s
|
|
||||||
#8 sha256:62fe2e747f69f2f414c7e9eb1553155cf0a658398f0462557f458821dce2b29d 25.64MB / 25.64MB 1.3s done
|
|
||||||
#8 ...
|
|
||||||
#7 [railpack] loading secrets
|
|
||||||
#7 resolve docker.io/library/alpine:latest 1.5s done
|
|
||||||
#7 sha256:7b229517ed222597277036d94892173207d01a731ab3a88eeb1de2e963a2c788 3.85MB / 3.85MB 0.9s done
|
|
||||||
#7 extracting sha256:7b229517ed222597277036d94892173207d01a731ab3a88eeb1de2e963a2c788 0.5s done
|
|
||||||
#7 DONE 2.9s
|
|
||||||
#8 docker-image://ghcr.io/railwayapp/railpack-builder:latest
|
|
||||||
#8 sha256:08a1e03b3da5bb4a1059032dca3216f33ddfc4a48a45db88921f5bb2e9a8fa2d 30.15MB / 53.72MB 1.7s
|
|
||||||
#8 sha256:604add184d03d4cf6e2ff1c4b9013b265eb9c11570afe28ce8f9dc417b98ea3f 69.21MB / 237.08MB 1.8s
|
|
||||||
#8 sha256:4dc3950125ebc9ed195e1101fc6c02e2fce113ba0f53bfb05b2cdf58747df9af 35.65MB / 67.81MB 1.5s
|
|
||||||
#8 sha256:4846f29007305297af653c57bf9b60ba8f676a38695c68d98460063442581671 0B / 49.39MB 0.2s
|
|
||||||
#8 sha256:08a1e03b3da5bb4a1059032dca3216f33ddfc4a48a45db88921f5bb2e9a8fa2d 35.65MB / 53.72MB 2.0s
|
|
||||||
#8 sha256:4dc3950125ebc9ed195e1101fc6c02e2fce113ba0f53bfb05b2cdf58747df9af 40.89MB / 67.81MB 1.7s
|
|
||||||
#8 sha256:4846f29007305297af653c57bf9b60ba8f676a38695c68d98460063442581671 6.29MB / 49.39MB 0.5s
|
|
||||||
#8 sha256:604add184d03d4cf6e2ff1c4b9013b265eb9c11570afe28ce8f9dc417b98ea3f 83.89MB / 237.08MB 2.1s
|
|
||||||
#8 sha256:08a1e03b3da5bb4a1059032dca3216f33ddfc4a48a45db88921f5bb2e9a8fa2d 40.89MB / 53.72MB 2.3s
|
|
||||||
#8 sha256:4dc3950125ebc9ed195e1101fc6c02e2fce113ba0f53bfb05b2cdf58747df9af 48.23MB / 67.81MB 2.0s
|
|
||||||
#8 sha256:4846f29007305297af653c57bf9b60ba8f676a38695c68d98460063442581671 10.49MB / 49.39MB 0.6s
|
|
||||||
#8 sha256:604add184d03d4cf6e2ff1c4b9013b265eb9c11570afe28ce8f9dc417b98ea3f 97.52MB / 237.08MB 2.4s
|
|
||||||
#8 sha256:4dc3950125ebc9ed195e1101fc6c02e2fce113ba0f53bfb05b2cdf58747df9af 52.43MB / 67.81MB 2.1s
|
|
||||||
#8 sha256:4846f29007305297af653c57bf9b60ba8f676a38695c68d98460063442581671 14.68MB / 49.39MB 0.8s
|
|
||||||
#8 ...
|
|
||||||
#9 [railpack] copy secrets hash
|
|
||||||
#9 DONE 0.7s
|
|
||||||
#8 docker-image://ghcr.io/railwayapp/railpack-builder:latest
|
|
||||||
#8 sha256:4846f29007305297af653c57bf9b60ba8f676a38695c68d98460063442581671 18.87MB / 49.39MB 0.9s
|
|
||||||
#8 sha256:08a1e03b3da5bb4a1059032dca3216f33ddfc4a48a45db88921f5bb2e9a8fa2d 46.14MB / 53.72MB 2.6s
|
|
||||||
#8 sha256:4846f29007305297af653c57bf9b60ba8f676a38695c68d98460063442581671 23.07MB / 49.39MB 1.1s
|
|
||||||
#8 sha256:604add184d03d4cf6e2ff1c4b9013b265eb9c11570afe28ce8f9dc417b98ea3f 111.15MB / 237.08MB 2.7s
|
|
||||||
#8 sha256:4dc3950125ebc9ed195e1101fc6c02e2fce113ba0f53bfb05b2cdf58747df9af 59.77MB / 67.81MB 2.4s
|
|
||||||
#8 sha256:08a1e03b3da5bb4a1059032dca3216f33ddfc4a48a45db88921f5bb2e9a8fa2d 51.38MB / 53.72MB 2.9s
|
|
||||||
#8 sha256:4dc3950125ebc9ed195e1101fc6c02e2fce113ba0f53bfb05b2cdf58747df9af 63.96MB / 67.81MB 2.6s
|
|
||||||
#8 sha256:4846f29007305297af653c57bf9b60ba8f676a38695c68d98460063442581671 30.41MB / 49.39MB 1.4s
|
|
||||||
#8 sha256:604add184d03d4cf6e2ff1c4b9013b265eb9c11570afe28ce8f9dc417b98ea3f 126.88MB / 237.08MB 3.0s
|
|
||||||
#8 sha256:4846f29007305297af653c57bf9b60ba8f676a38695c68d98460063442581671 36.70MB / 49.39MB 1.5s
|
|
||||||
#8 ...
|
|
||||||
#10 [railpack] hash used secrets
|
|
||||||
#10 DONE 0.7s
|
|
||||||
#8 docker-image://ghcr.io/railwayapp/railpack-builder:latest
|
|
||||||
#8 sha256:08a1e03b3da5bb4a1059032dca3216f33ddfc4a48a45db88921f5bb2e9a8fa2d 53.72MB / 53.72MB 3.2s done
|
|
||||||
#8 sha256:4dc3950125ebc9ed195e1101fc6c02e2fce113ba0f53bfb05b2cdf58747df9af 67.81MB / 67.81MB 2.9s done
|
|
||||||
#8 ...
|
|
||||||
#11 [railpack] copy used secrets hash
|
|
||||||
#11 DONE 0.0s
|
|
||||||
#8 docker-image://ghcr.io/railwayapp/railpack-builder:latest
|
|
||||||
#8 sha256:604add184d03d4cf6e2ff1c4b9013b265eb9c11570afe28ce8f9dc417b98ea3f 145.75MB / 237.08MB 3.3s
|
|
||||||
#8 sha256:4846f29007305297af653c57bf9b60ba8f676a38695c68d98460063442581671 40.89MB / 49.39MB 1.7s
|
|
||||||
#8 sha256:4846f29007305297af653c57bf9b60ba8f676a38695c68d98460063442581671 46.14MB / 49.39MB 1.8s
|
|
||||||
#8 sha256:604add184d03d4cf6e2ff1c4b9013b265eb9c11570afe28ce8f9dc417b98ea3f 168.15MB / 237.08MB 3.6s
|
|
||||||
#8 sha256:4846f29007305297af653c57bf9b60ba8f676a38695c68d98460063442581671 49.39MB / 49.39MB 2.0s
|
|
||||||
#8 sha256:604add184d03d4cf6e2ff1c4b9013b265eb9c11570afe28ce8f9dc417b98ea3f 181.40MB / 237.08MB 3.8s
|
|
||||||
#8 sha256:4846f29007305297af653c57bf9b60ba8f676a38695c68d98460063442581671 49.39MB / 49.39MB 2.2s done
|
|
||||||
#8 extracting sha256:4846f29007305297af653c57bf9b60ba8f676a38695c68d98460063442581671
|
|
||||||
#8 sha256:604add184d03d4cf6e2ff1c4b9013b265eb9c11570afe28ce8f9dc417b98ea3f 205.52MB / 237.08MB 4.1s
|
|
||||||
#8 ...
|
|
||||||
#6 loading .
|
|
||||||
#6 transferring context: 127.67MB 3.8s done
|
|
||||||
#6 DONE 4.0s
|
|
||||||
#8 docker-image://ghcr.io/railwayapp/railpack-builder:latest
|
|
||||||
#8 sha256:604add184d03d4cf6e2ff1c4b9013b265eb9c11570afe28ce8f9dc417b98ea3f 231.05MB / 237.08MB 4.4s
|
|
||||||
#8 ...
|
|
||||||
#12 docker-image://ghcr.io/railwayapp/railpack-runtime:latest
|
|
||||||
#12 resolve ghcr.io/railwayapp/railpack-runtime:latest 0.9s done
|
|
||||||
#12 sha256:75dc09925ca146a3efecc887098f8f1313da0fb1b0c8d36d628b6cae320665ec 7.39MB / 7.39MB 0.3s done
|
|
||||||
#12 sha256:ecc510c1e359bdc007b39802570bb7e4dec7d6ebccf357c3201a74299113e05e 29.84MB / 29.84MB 0.7s done
|
|
||||||
#12 extracting sha256:ecc510c1e359bdc007b39802570bb7e4dec7d6ebccf357c3201a74299113e05e 3.4s done
|
|
||||||
#12 extracting sha256:75dc09925ca146a3efecc887098f8f1313da0fb1b0c8d36d628b6cae320665ec 0.6s done
|
|
||||||
#12 DONE 5.6s
|
|
||||||
#8 docker-image://ghcr.io/railwayapp/railpack-builder:latest
|
|
||||||
#8 sha256:604add184d03d4cf6e2ff1c4b9013b265eb9c11570afe28ce8f9dc417b98ea3f 237.08MB / 237.08MB 4.7s done
|
|
||||||
#8 extracting sha256:4846f29007305297af653c57bf9b60ba8f676a38695c68d98460063442581671 2.7s done
|
|
||||||
#8 extracting sha256:62fe2e747f69f2f414c7e9eb1553155cf0a658398f0462557f458821dce2b29d
|
|
||||||
#8 extracting sha256:62fe2e747f69f2f414c7e9eb1553155cf0a658398f0462557f458821dce2b29d 1.7s done
|
|
||||||
#8 DONE 9.4s
|
|
||||||
#13 install apt packages: libatomic1
|
|
||||||
#13 0.232 Get:1 http://deb.debian.org/debian trixie InRelease [140 kB]
|
|
||||||
#13 0.314 Get:2 http://deb.debian.org/debian trixie-updates InRelease [47.3 kB]
|
|
||||||
#13 0.345 Get:3 http://deb.debian.org/debian-security trixie-security InRelease [43.4 kB]
|
|
||||||
#13 0.374 Get:4 http://deb.debian.org/debian trixie/main amd64 Packages [9678 kB]
|
|
||||||
#13 0.549 Get:5 http://deb.debian.org/debian trixie-updates/main amd64 Packages [720 B]
|
|
||||||
#13 0.575 Get:6 http://deb.debian.org/debian-security trixie-security/main amd64 Packages [270 kB]
|
|
||||||
#13 2.260 Fetched 10.2 MB in 2s (4830 kB/s)
|
|
||||||
#13 2.260 Reading package lists...
|
|
||||||
#13 4.151 Reading package lists...
|
|
||||||
#13 5.983 Building dependency tree...
|
|
||||||
#13 6.439 Reading state information...
|
|
||||||
#13 6.939 The following NEW packages will be installed:
|
|
||||||
#13 6.941 libatomic1
|
|
||||||
#13 7.101 0 upgraded, 1 newly installed, 0 to remove and 3 not upgraded.
|
|
||||||
#13 7.101 Need to get 9308 B of archives.
|
|
||||||
#13 7.101 After this operation, 46.1 kB of additional disk space will be used.
|
|
||||||
#13 7.101 Get:1 http://deb.debian.org/debian trixie/main amd64 libatomic1 amd64 14.2.0-19 [9308 B]
|
|
||||||
#13 7.542 debconf: unable to initialize frontend: Dialog
|
|
||||||
#13 7.543 debconf: (TERM is not set, so the dialog frontend is not usable.)
|
|
||||||
#13 7.543 debconf: falling back to frontend: Readline
|
|
||||||
#13 7.543 debconf: unable to initialize frontend: Readline
|
|
||||||
#13 7.543 debconf: (Can't locate Term/ReadLine.pm in @INC (you may need to install the Term::ReadLine module) (@INC entries checked: /etc/perl /usr/local/lib/x86_64-linux-gnu/perl/5.40.1 /usr/local/share/perl/5.40.1 /usr/lib/x86_64-linux-gnu/perl5/5.40 /usr/share/perl5 /usr/lib/x86_64-linux-gnu/perl-base /usr/lib/x86_64-linux-gnu/perl/5.40 /usr/share/perl/5.40 /usr/local/lib/site_perl) at /usr/share/perl5/Debconf/FrontEnd/Readline.pm line 8, <STDIN> line 1.)
|
|
||||||
#13 7.543 debconf: falling back to frontend: Teletype
|
|
||||||
#13 7.550 debconf: unable to initialize frontend: Teletype
|
|
||||||
#13 7.550 debconf: (This frontend requires a controlling tty.)
|
|
||||||
#13 7.550 debconf: falling back to frontend: Noninteractive
|
|
||||||
#13 ...
|
|
||||||
#8 docker-image://ghcr.io/railwayapp/railpack-builder:latest
|
|
||||||
#8 extracting sha256:4dc3950125ebc9ed195e1101fc6c02e2fce113ba0f53bfb05b2cdf58747df9af 4.6s done
|
|
||||||
#8 DONE 14.0s
|
|
||||||
#8 docker-image://ghcr.io/railwayapp/railpack-builder:latest
|
|
||||||
#8 extracting sha256:4f4fb700ef54461cfa02571ae0db9a0dc1e0cdb5577484a6d75e68dc38e8acc1 done
|
|
||||||
#8 extracting sha256:08a1e03b3da5bb4a1059032dca3216f33ddfc4a48a45db88921f5bb2e9a8fa2d
|
|
||||||
#8 ...
|
|
||||||
#13 install apt packages: libatomic1
|
|
||||||
#13 8.681 Fetched 9308 B in 0s (65.4 kB/s)
|
|
||||||
#13 8.727 Selecting previously unselected package libatomic1:amd64.
|
|
||||||
#13 8.727 (Reading database ... ␍(Reading database ... 5%␍(Reading database ... 10%␍(Reading database ... 15%␍(Reading database ... 20%␍(Reading database ... 25%␍(Reading database ... 30%␍(Reading database ... 35%␍(Reading database ... 40%␍(Reading database ... 45%␍(Reading database ... 50%␍(Reading database ... 55%␍(Reading database ... 60%␍(Reading database ... 65%␍(Reading database ... 70%␍(Reading database ... 75%␍(Reading database ... 80%␍(Reading database ... 85%␍(Reading database ... 90%␍(Reading database ... 95%␍(Reading database ... 100%␍(Reading database ... 6228 files and directories currently installed.)
|
|
||||||
#13 8.735 Preparing to unpack .../libatomic1_14.2.0-19_amd64.deb ...
|
|
||||||
#13 8.756 Unpacking libatomic1:amd64 (14.2.0-19) ...
|
|
||||||
#13 8.817 Setting up libatomic1:amd64 (14.2.0-19) ...
|
|
||||||
#13 8.823 Processing triggers for libc-bin (2.41-12+deb13u4) ...
|
|
||||||
#13 DONE 9.4s
|
|
||||||
#8 docker-image://ghcr.io/railwayapp/railpack-builder:latest
|
|
||||||
#8 extracting sha256:08a1e03b3da5bb4a1059032dca3216f33ddfc4a48a45db88921f5bb2e9a8fa2d 1.1s done
|
|
||||||
#8 extracting sha256:604add184d03d4cf6e2ff1c4b9013b265eb9c11570afe28ce8f9dc417b98ea3f
|
|
||||||
#8 extracting sha256:604add184d03d4cf6e2ff1c4b9013b265eb9c11570afe28ce8f9dc417b98ea3f 7.1s done
|
|
||||||
#8 DONE 22.2s
|
|
||||||
#8 docker-image://ghcr.io/railwayapp/railpack-builder:latest
|
|
||||||
#8 extracting sha256:df614908d6aba31e983953b17fd48496d27425529b3947c3d5583c4cc9c15c9a 0.0s done
|
|
||||||
#8 extracting sha256:193926ad1d06489b7487e8ac4ae2d0874e6ff05cf65d874d2af508830fc03def done
|
|
||||||
#8 DONE 22.2s
|
|
||||||
#14 mkdir /etc/mise
|
|
||||||
#14 DONE 1.5s
|
|
||||||
#15 create mise config
|
|
||||||
#15 DONE 0.0s
|
|
||||||
#16 install mise packages: bun, node
|
|
||||||
#16 0.142 mise by @jdx – installing 2 tools
|
|
||||||
#16 3.151 mise ███████████░░░░░ 0/2 · 3.0s
|
|
||||||
#16 3.151 bun@1.4.4 downloading 2.7s 51.8/51.8 MB · 22.0 MB/s
|
|
||||||
#16 3.151 node@26.12.1 downloading 2.7s 62.1/62.9 MB · 24.6 MB/s
|
|
||||||
#16 3.856 mise bun@1.4.4 1.4.4
|
|
||||||
#16 3.869 mise ✓ bun@1.4.4 3.4s bun-linux-x64.zip
|
|
||||||
#16 4.708 mise node@26.12.1 v26.12.1
|
|
||||||
#16 4.828 mise node@26.12.1 11.20.0
|
|
||||||
#16 4.861 mise ✓ node@26.12.1 4.4s node-v26.12.1-linux-x64.tar.gz
|
|
||||||
#16 4.861 mise ████████████████ 2/2 · installed 2 tools in 4.7s
|
|
||||||
#16 DONE 5.7s
|
|
||||||
#17 mkdir -p /app/node_modules/.cache
|
|
||||||
#17 DONE 0.2s
|
|
||||||
#18 copy bun.lock
|
|
||||||
#18 DONE 0.0s
|
|
||||||
#19 copy package.json
|
|
||||||
#19 DONE 0.1s
|
|
||||||
#20 copy /mise/shims
|
|
||||||
#20 DONE 0.0s
|
|
||||||
#21 copy skills/podcast-generate/package.json
|
|
||||||
#21 DONE 0.0s
|
|
||||||
#22 copy skills/skill-finder-cn/package.json
|
|
||||||
#22 DONE 0.0s
|
|
||||||
#23 copy skills/stock-analysis-skill/package.json
|
|
||||||
#23 DONE 0.0s
|
|
||||||
#24 copy skills/storyboard-manager/package.json
|
|
||||||
#24 DONE 0.0s
|
|
||||||
#25 copy prisma
|
|
||||||
#25 DONE 0.0s
|
|
||||||
#26 bun install --frozen-lockfile
|
|
||||||
#26 0.115 bun install v1.4.4 (38afee6c8)
|
|
||||||
#26 ...
|
|
||||||
#27 copy /mise/installs
|
|
||||||
#27 ...
|
|
||||||
#26 bun install --frozen-lockfile
|
|
||||||
#26 14.31
|
|
||||||
#26 14.31 + @tailwindcss/postcss@4.1.18
|
|
||||||
#26 14.31 + @types/react@19.2.8
|
|
||||||
#26 14.31 + @types/react-dom@19.2.3
|
|
||||||
#26 14.31 + bun-types@1.3.6
|
|
||||||
#26 14.31 + eslint@9.39.2
|
|
||||||
#26 14.31 + eslint-config-next@16.1.3
|
|
||||||
#26 14.31 + tailwindcss@4.1.18
|
|
||||||
#26 14.31 + tw-animate-css@1.4.0
|
|
||||||
#26 14.31 + typescript@5.9.3
|
|
||||||
#26 14.31 + @dnd-kit/core@6.3.1
|
|
||||||
#26 14.31 + @dnd-kit/sortable@10.0.0
|
|
||||||
#26 14.31 + @dnd-kit/utilities@3.2.2
|
|
||||||
#26 14.31 + @hookform/resolvers@5.2.2
|
|
||||||
#26 14.31 + @hugeicons/core-free-icons@4.3.5
|
|
||||||
#26 14.31 + @hugeicons/react@1.1.10
|
|
||||||
#26 14.31 + @mdxeditor/editor@3.52.3
|
|
||||||
#26 14.31 + @prisma/client@6.19.2
|
|
||||||
#26 14.31 + @radix-ui/react-accordion@1.2.12
|
|
||||||
#26 14.31 + @radix-ui/react-alert-dialog@1.1.15
|
|
||||||
#26 14.31 + @radix-ui/react-aspect-ratio@1.1.8
|
|
||||||
#26 14.31 + @radix-ui/react-avatar@1.1.11
|
|
||||||
#26 14.31 + @radix-ui/react-checkbox@1.3.3
|
|
||||||
#26 14.31 + @radix-ui/react-collapsible@1.1.12
|
|
||||||
#26 14.31 + @radix-ui/react-context-menu@2.2.16
|
|
||||||
#26 14.31 + @radix-ui/react-dialog@1.1.15
|
|
||||||
#26 14.31 + @radix-ui/react-dropdown-menu@2.1.16
|
|
||||||
#26 14.31 + @radix-ui/react-hover-card@1.1.15
|
|
||||||
#26 14.31 + @radix-ui/react-label@2.1.8
|
|
||||||
#26 14.31 + @radix-ui/react-menubar@1.1.16
|
|
||||||
#26 14.31 + @radix-ui/react-navigation-menu@1.2.14
|
|
||||||
#26 14.31 + @radix-ui/react-popover@1.1.15
|
|
||||||
#26 14.31 + @radix-ui/react-progress@1.1.8
|
|
||||||
#26 14.31 + @radix-ui/react-radio-group@1.3.8
|
|
||||||
#26 14.31 + @radix-ui/react-scroll-area@1.2.10
|
|
||||||
#26 14.31 + @radix-ui/react-select@2.2.6
|
|
||||||
#26 14.31 + @radix-ui/react-separator@1.1.8
|
|
||||||
#26 14.31 + @radix-ui/react-slider@1.3.6
|
|
||||||
#26 14.31 + @radix-ui/react-slot@1.2.4
|
|
||||||
#26 14.31 + @radix-ui/react-switch@1.2.6
|
|
||||||
#26 14.31 + @radix-ui/react-tabs@1.1.13
|
|
||||||
#26 14.31 + @radix-ui/react-toast@1.2.15
|
|
||||||
#26 14.31 + @radix-ui/react-toggle@1.1.10
|
|
||||||
#26 14.31 + @radix-ui/react-toggle-group@1.1.11
|
|
||||||
#26 14.31 + @radix-ui/react-tooltip@1.2.8
|
|
||||||
#26 14.31 + @reactuses/core@6.1.9
|
|
||||||
#26 14.31 + @tanstack/react-query@5.90.19
|
|
||||||
#26 14.31 + @tanstack/react-table@8.21.3
|
|
||||||
#26 14.31 + class-variance-authority@0.7.1
|
|
||||||
#26 14.31 + clsx@2.1.1
|
|
||||||
#26 14.31 + cmdk@1.1.1
|
|
||||||
#26 14.31 + date-fns@4.1.0
|
|
||||||
#26 14.31 + embla-carousel-react@8.6.0
|
|
||||||
#26 14.31 + framer-motion@14.7.1
|
|
||||||
#26 14.31 + imapflow@2.9.1
|
|
||||||
#26 14.31 + input-otp@1.4.2
|
|
||||||
#26 14.31 + lucide-react@1.62.0
|
|
||||||
#26 14.31 + motion@12.43.0
|
|
||||||
#26 14.31 + next@16.1.3
|
|
||||||
#26 14.31 + next-auth@4.24.13
|
|
||||||
#26 14.31 + next-intl@4.7.0
|
|
||||||
#26 14.31 + next-themes@0.4.6
|
|
||||||
#26 14.31 + prisma@6.19.2
|
|
||||||
#26 14.31 + react@19.2.3
|
|
||||||
#26 14.31 + react-day-picker@9.13.0
|
|
||||||
#26 14.31 + react-dom@19.2.3
|
|
||||||
#26 14.31 + react-hook-form@7.71.1
|
|
||||||
#26 14.31 + react-markdown@10.1.0
|
|
||||||
#26 14.31 + react-resizable-panels@3.0.6
|
|
||||||
#26 14.31 + react-syntax-highlighter@15.6.6
|
|
||||||
#26 14.31 + recharts@2.15.4
|
|
||||||
#26 14.31 + sharp@0.34.5
|
|
||||||
#26 14.31 + sonner@2.0.7
|
|
||||||
#26 14.31 + tailwind-merge@3.7.0
|
|
||||||
#26 14.31 + tailwindcss-animate@1.0.7
|
|
||||||
#26 14.31 + uuid@11.1.0
|
|
||||||
#26 14.31 + vaul@1.1.2
|
|
||||||
#26 14.31 + z-ai-web-dev-sdk@0.0.18
|
|
||||||
#26 14.31 + zod@4.3.5
|
|
||||||
#26 14.31 + zustand@5.0.10
|
|
||||||
#26 14.31
|
|
||||||
#26 14.31 858 packages installed [14.19s]
|
|
||||||
#26 DONE 16.1s
|
|
||||||
#28 copy / /app
|
|
||||||
#28 ...
|
|
||||||
#27 copy /mise/installs
|
|
||||||
#27 DONE 7.3s
|
|
||||||
#29 copy /usr/local/bin/mise
|
|
||||||
#29 DONE 1.2s
|
|
||||||
#28 copy / /app
|
|
||||||
#28 ...
|
|
||||||
#30 copy /etc/mise/config.toml
|
|
||||||
#30 DONE 0.1s
|
|
||||||
#31 copy /root/.local/state/mise
|
|
||||||
#31 DONE 0.0s
|
|
||||||
#28 copy / /app
|
|
||||||
#28 DONE 2.7s
|
|
||||||
#32 bun run build
|
|
||||||
#32 0.169 $ next build && cp -r .next/static .next/standalone/.next/ && cp -r public .next/standalone/
|
|
||||||
#32 0.359 ⚠ You are using a non-standard "NODE_ENV" value in your environment. This creates inconsistencies in the project and is strongly advised against. Read more: https://nextjs.org/docs/messages/non-standard-node-env
|
|
||||||
#32 1.293 ▲ Next.js 16.1.3 (Turbopack)
|
|
||||||
#32 1.294 - Environments: .env
|
|
||||||
#32 1.294
|
|
||||||
#32 1.340 Creating an optimized production build ...
|
|
||||||
#32 13.17 (node:98) [DEP0205] DeprecationWarning: `module.register()` is deprecated. Use `module.registerHooks()` instead.
|
|
||||||
#32 13.17 (Use `node --trace-deprecation ...` to show where the warning was created)
|
|
||||||
#32 31.57
|
|
||||||
#32 31.57 > Build error occurred
|
|
||||||
#32 31.57 Error: Turbopack build failed with 1 errors:
|
|
||||||
#32 31.57 ./node_modules/@prisma/client/index-browser.js:1:16
|
|
||||||
#32 31.57 Module not found: Can't resolve '.prisma/client/index-browser'
|
|
||||||
#32 31.57 [0m[31m[1m>[22m[39m[90m 1 |[39m [36mconst[39m prisma [33m=[39m require([32m'.prisma/client/index-browser'[39m)
|
|
||||||
#32 31.57 [90m |[39m [31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m
|
|
||||||
#32 31.57 [90m 2 |[39m
|
|
||||||
#32 31.57 [90m 3 |[39m module[33m.[39mexports [33m=[39m prisma
|
|
||||||
#32 31.57 [90m 4 |[39m[0m
|
|
||||||
#32 31.57
|
|
||||||
#32 31.57
|
|
||||||
#32 31.57
|
|
||||||
#32 31.57 Import trace:
|
|
||||||
#32 31.57 Client Component Browser:
|
|
||||||
#32 31.57 ./node_modules/@prisma/client/index-browser.js [Client Component Browser]
|
|
||||||
#32 31.57 ./src/lib/db.ts [Client Component Browser]
|
|
||||||
#32 31.57 ./src/components/aos/portal-shell.tsx [Client Component Browser]
|
|
||||||
#32 31.57 ./src/components/aos/app-shell.tsx [Client Component Browser]
|
|
||||||
#32 31.57 ./src/components/aos/app-shell.tsx [Server Component]
|
|
||||||
#32 31.57 ./src/app/page.tsx [Server Component]
|
|
||||||
#32 31.57
|
|
||||||
#32 31.57 https://nextjs.org/docs/messages/module-not-found
|
|
||||||
#32 31.57
|
|
||||||
#32 31.57
|
|
||||||
#32 31.57 at ./node_modules/ (prisma/client/index-browser.js:1:16)
|
|
||||||
#32 31.57 at <unknown> (https://nextjs.org/docs/messages/module-not-found)
|
|
||||||
#32 31.72 error: script "build" exited with code 1
|
|
||||||
#32 ERROR: process "bun run build" did not complete successfully: exit code: 1
|
|
||||||
------
|
|
||||||
> bun run build:
|
|
||||||
31.57 ./src/components/aos/app-shell.tsx [Client Component Browser]
|
|
||||||
31.57 ./src/components/aos/app-shell.tsx [Server Component]
|
|
||||||
31.57 ./src/app/page.tsx [Server Component]
|
|
||||||
31.57
|
|
||||||
31.57 https://nextjs.org/docs/messages/module-not-found
|
|
||||||
31.57
|
|
||||||
31.57
|
|
||||||
31.57 at ./node_modules/ (prisma/client/index-browser.js:1:16)
|
|
||||||
31.57 at <unknown> (https://nextjs.org/docs/messages/module-not-found)
|
|
||||||
31.72 error: script "build" exited with code 1
|
|
||||||
------
|
|
||||||
ERROR: failed to build: failed to solve: process "bun run build" did not complete successfully: exit code: 1
|
|
||||||
❌ Railpack build failed
|
|
||||||
railpack-dfm-aos-lgbcnc-INtHrR removed
|
|
||||||
Error occurred ❌, check the logs for details.
|
|
||||||
@@ -1,463 +0,0 @@
|
|||||||
Initializing deployment
|
|
||||||
Cloning Repo github.com/cetinmustafa83/aos.git to /etc/dokploy/applications/dfm-aos-lgbcnc/code: ✅
|
|
||||||
Cloning into '/etc/dokploy/applications/dfm-aos-lgbcnc/code'...
|
|
||||||
remote: Enumerating objects: 1876, done.
|
|
||||||
remote: Counting objects: 0% (1/1876)
remote: Counting objects: 1% (19/1876)
remote: Counting objects: 2% (38/1876)
remote: Counting objects: 3% (57/1876)
remote: Counting objects: 4% (76/1876)
remote: Counting objects: 5% (94/1876)
remote: Counting objects: 6% (113/1876)
remote: Counting objects: 7% (132/1876)
remote: Counting objects: 8% (151/1876)
remote: Counting objects: 9% (169/1876)
remote: Counting objects: 10% (188/1876)
remote: Counting objects: 11% (207/1876)
remote: Counting objects: 12% (226/1876)
remote: Counting objects: 13% (244/1876)
remote: Counting objects: 14% (263/1876)
remote: Counting objects: 15% (282/1876)
remote: Counting objects: 16% (301/1876)
remote: Counting objects: 17% (319/1876)
remote: Counting objects: 18% (338/1876)
remote: Counting objects: 19% (357/1876)
remote: Counting objects: 20% (376/1876)
remote: Counting objects: 21% (394/1876)
remote: Counting objects: 22% (413/1876)
remote: Counting objects: 23% (432/1876)
remote: Counting objects: 24% (451/1876)
remote: Counting objects: 25% (469/1876)
remote: Counting objects: 26% (488/1876)
remote: Counting objects: 27% (507/1876)
remote: Counting objects: 28% (526/1876)
remote: Counting objects: 29% (545/1876)
remote: Counting objects: 30% (563/1876)
remote: Counting objects: 31% (582/1876)
remote: Counting objects: 32% (601/1876)
remote: Counting objects: 33% (620/1876)
remote: Counting objects: 34% (638/1876)
remote: Counting objects: 35% (657/1876)
remote: Counting objects: 36% (676/1876)
remote: Counting objects: 37% (695/1876)
remote: Counting objects: 38% (713/1876)
remote: Counting objects: 39% (732/1876)
remote: Counting objects: 40% (751/1876)
remote: Counting objects: 41% (770/1876)
remote: Counting objects: 42% (788/1876)
remote: Counting objects: 43% (807/1876)
remote: Counting objects: 44% (826/1876)
remote: Counting objects: 45% (845/1876)
remote: Counting objects: 46% (863/1876)
remote: Counting objects: 47% (882/1876)
remote: Counting objects: 48% (901/1876)
remote: Counting objects: 49% (920/1876)
remote: Counting objects: 50% (938/1876)
remote: Counting objects: 51% (957/1876)
remote: Counting objects: 52% (976/1876)
remote: Counting objects: 53% (995/1876)
remote: Counting objects: 54% (1014/1876)
remote: Counting objects: 55% (1032/1876)
remote: Counting objects: 56% (1051/1876)
remote: Counting objects: 57% (1070/1876)
remote: Counting objects: 58% (1089/1876)
remote: Counting objects: 59% (1107/1876)
remote: Counting objects: 60% (1126/1876)
remote: Counting objects: 61% (1145/1876)
remote: Counting objects: 62% (1164/1876)
remote: Counting objects: 63% (1182/1876)
remote: Counting objects: 64% (1201/1876)
remote: Counting objects: 65% (1220/1876)
remote: Counting objects: 66% (1239/1876)
remote: Counting objects: 67% (1257/1876)
remote: Counting objects: 68% (1276/1876)
remote: Counting objects: 69% (1295/1876)
remote: Counting objects: 70% (1314/1876)
remote: Counting objects: 71% (1332/1876)
remote: Counting objects: 72% (1351/1876)
remote: Counting objects: 73% (1370/1876)
remote: Counting objects: 74% (1389/1876)
remote: Counting objects: 75% (1407/1876)
remote: Counting objects: 76% (1426/1876)
remote: Counting objects: 77% (1445/1876)
remote: Counting objects: 78% (1464/1876)
remote: Counting objects: 79% (1483/1876)
remote: Counting objects: 80% (1501/1876)
remote: Counting objects: 81% (1520/1876)
remote: Counting objects: 82% (1539/1876)
remote: Counting objects: 83% (1558/1876)
remote: Counting objects: 84% (1576/1876)
remote: Counting objects: 85% (1595/1876)
remote: Counting objects: 86% (1614/1876)
remote: Counting objects: 87% (1633/1876)
remote: Counting objects: 88% (1651/1876)
remote: Counting objects: 89% (1670/1876)
remote: Counting objects: 90% (1689/1876)
remote: Counting objects: 91% (1708/1876)
remote: Counting objects: 92% (1726/1876)
remote: Counting objects: 93% (1745/1876)
remote: Counting objects: 94% (1764/1876)
remote: Counting objects: 95% (1783/1876)
remote: Counting objects: 96% (1801/1876)
remote: Counting objects: 97% (1820/1876)
remote: Counting objects: 98% (1839/1876)
remote: CouLine truncated
|
|
||||||
remote: Compressing objects: 0% (1/1405)
remote: Compressing objects: 1% (15/1405)
remote: Compressing objects: 2% (29/1405)
remote: Compressing objects: 3% (43/1405)
remote: Compressing objects: 4% (57/1405)
remote: Compressing objects: 5% (71/1405)
remote: Compressing objects: 6% (85/1405)
remote: Compressing objects: 7% (99/1405)
remote: Compressing objects: 8% (113/1405)
remote: Compressing objects: 9% (127/1405)
remote: Compressing objects: 10% (141/1405)
remote: Compressing objects: 11% (155/1405)
remote: Compressing objects: 12% (169/1405)
remote: Compressing objects: 13% (183/1405)
remote: Compressing objects: 14% (197/1405)
remote: Compressing objects: 15% (211/1405)
remote: Compressing objects: 16% (225/1405)
remote: Compressing objects: 17% (239/1405)
remote: Compressing objects: 18% (253/1405)
remote: Compressing objects: 19% (267/1405)
remote: Compressing objects: 20% (281/1405)
remote: Compressing objects: 21% (296/1405)
remote: Compressing objects: 22% (310/1405)
remote: Compressing objects: 23% (324/1405)
remote: Compressing objects: 24% (338/1405)
remote: Compressing objects: 25% (352/1405)
remote: Compressing objects: 26% (366/1405)
remote: Compressing objects: 27% (380/1405)
remote: Compressing objects: 28% (394/1405)
remote: Compressing objects: 29% (408/1405)
remote: Compressing objects: 30% (422/1405)
remote: Compressing objects: 31% (436/1405)
remote: Compressing objects: 32% (450/1405)
remote: Compressing objects: 33% (464/1405)
remote: Compressing objects: 34% (478/1405)
remote: Compressing objects: 35% (492/1405)
remote: Compressing objects: 36% (506/1405)
remote: Compressing objects: 37% (520/1405)
remote: Compressing objects: 38% (534/1405)
remote: Compressing objects: 39% (548/1405)
remote: Compressing objects: 40% (562/1405)
remote: Compressing objects: 41% (577/1405)
remote: Compressing objects: 42% (591/1405)
remote: Compressing objects: 43% (605/1405)
remote: Compressing objects: 44% (619/1405)
remote: Compressing objects: 45% (633/1405)
remote: Compressing objects: 46% (647/1405)
remote: Compressing objects: 47% (661/1405)
remote: Compressing objects: 48% (675/1405)
remote: Compressing objects: 49% (689/1405)
remote: Compressing objects: 50% (703/1405)
remote: Compressing objects: 51% (717/1405)
remote: Compressing objects: 52% (731/1405)
remote: Compressing objects: 53% (745/1405)
remote: Compressing objects: 54% (759/1405)
remote: Compressing objects: 55% (773/1405)
remote: Compressing objects: 56% (787/1405)
remote: Compressing objects: 57% (801/1405)
remote: Compressing objects: 58% (815/1405)
remote: Compressing objects: 59% (829/1405)
remote: Compressing objects: 60% (843/1405)
remote: Compressing objects: 61% (858/1405)
remote: Compressing objects: 62% (872/1405)
remote: Compressing objects: 63% (886/1405)
remote: Compressing objects: 64% (900/1405)
remote: Compressing objects: 65% (914/1405)
remote: Compressing objects: 66% (928/1405)
remote: Compressing objects: 67% (942/1405)
remote: Compressing objects: 68% (956/1405)
remote: Compressing objects: 69% (970/1405)
remote: Compressing objects: 70% (984/1405)
remote: Compressing objects: 71% (998/1405)
remote: Compressing objects: 72% (1012/1405)
remote: Compressing objects: 73% (1026/1405)
remote: Compressing objects: 74% (1040/1405)
remote: Compressing objects: 75% (1054/1405)
remote: Compressing objects: 76% (1068/1405)
remote: Compressing objects: 77% (1082/1405)
remote: Compressing objects: 78% (1096/1405)
remote: Compressing objects: 79% (1110/1405)
remote: Compressing objects: 80% (1124/1405)
remote: Compressing objects: 81% (1139/1405)
remote: Compressing objects: 82% (1153/1405)
remote: Compressing objects: 83% (1167/1405)
remote: Compressing objects: 84% (1181/1405)
remote: Compressing objects: 85% (1195/1405)
remote: Compressing objects: 86% (1209/1405)
remote: Compressing objects: 87% (1223/1405)
remote: Compressing objects: 88% (1237/1405)
remote: Compressing objects: 89% (1251/1405)
remote: Compressing objects: 90% (1265/1405)
remote: Compressing objects: 91% (1279/1405)
remote: Compressing objects: 92% (1293/1405)
remote: Compressing objects: 93% (1307/1405)
remoLine truncated
|
|
||||||
Receiving objects: 0% (1/1876)
Receiving objects: 1% (19/1876)
Receiving objects: 2% (38/1876)
Receiving objects: 3% (57/1876)
Receiving objects: 4% (76/1876)
Receiving objects: 5% (94/1876)
Receiving objects: 6% (113/1876)
Receiving objects: 7% (132/1876), 10.20 MiB | 20.26 MiB/s
Receiving objects: 8% (151/1876), 10.20 MiB | 20.26 MiB/s
Receiving objects: 9% (169/1876), 10.20 MiB | 20.26 MiB/s
Receiving objects: 10% (188/1876), 10.20 MiB | 20.26 MiB/s
Receiving objects: 11% (207/1876), 10.20 MiB | 20.26 MiB/s
Receiving objects: 12% (226/1876), 10.20 MiB | 20.26 MiB/s
Receiving objects: 13% (244/1876), 10.20 MiB | 20.26 MiB/s
Receiving objects: 14% (263/1876), 10.20 MiB | 20.26 MiB/s
Receiving objects: 15% (282/1876), 10.20 MiB | 20.26 MiB/s
Receiving objects: 16% (301/1876), 10.20 MiB | 20.26 MiB/s
Receiving objects: 17% (319/1876), 10.20 MiB | 20.26 MiB/s
Receiving objects: 18% (338/1876), 10.20 MiB | 20.26 MiB/s
Receiving objects: 19% (357/1876), 10.20 MiB | 20.26 MiB/s
Receiving objects: 20% (376/1876), 10.20 MiB | 20.26 MiB/s
Receiving objects: 21% (394/1876), 10.20 MiB | 20.26 MiB/s
Receiving objects: 22% (413/1876), 10.20 MiB | 20.26 MiB/s
Receiving objects: 23% (432/1876), 10.20 MiB | 20.26 MiB/s
Receiving objects: 24% (451/1876), 10.20 MiB | 20.26 MiB/s
Receiving objects: 25% (469/1876), 10.20 MiB | 20.26 MiB/s
Receiving objects: 26% (488/1876), 10.20 MiB | 20.26 MiB/s
Receiving objects: 27% (507/1876), 10.20 MiB | 20.26 MiB/s
Receiving objects: 28% (526/1876), 10.20 MiB | 20.26 MiB/s
Receiving objects: 29% (545/1876), 10.20 MiB | 20.26 MiB/s
Receiving objects: 30% (563/1876), 10.20 MiB | 20.26 MiB/s
Receiving objects: 31% (582/1876), 10.20 MiB | 20.26 MiB/s
Receiving objects: 32% (601/1876), 10.20 MiB | 20.26 MiB/s
Receiving objects: 33% (620/1876), 10.20 MiB | 20.26 MiB/s
Receiving objects: 34% (638/1876), 10.20 MiB | 20.26 MiB/s
Receiving objects: 35% (657/1876), 10.20 MiB | 20.26 MiB/s
Receiving objects: 36% (676/1876), 10.20 MiB | 20.26 MiB/s
Receiving objects: 37% (695/1876), 10.20 MiB | 20.26 MiB/s
Receiving objects: 38% (713/1876), 10.20 MiB | 20.26 MiB/s
Receiving objects: 39% (732/1876), 10.20 MiB | 20.26 MiB/s
Receiving objects: 40% (751/1876), 10.20 MiB | 20.26 MiB/s
Receiving objects: 41% (770/1876), 10.20 MiB | 20.26 MiB/s
Receiving objects: 42% (788/1876), 10.20 MiB | 20.26 MiB/s
Receiving objects: 43% (807/1876), 10.20 MiB | 20.26 MiB/s
Receiving objects: 44% (826/1876), 10.20 MiB | 20.26 MiB/s
Receiving objects: 45% (845/1876), 10.20 MiB | 20.26 MiB/s
Receiving objects: 46% (863/1876), 10.20 MiB | 20.26 MiB/s
Receiving objects: 47% (882/1876), 10.20 MiB | 20.26 MiB/s
Receiving objects: 48% (901/1876), 10.20 MiB | 20.26 MiB/s
Receiving objects: 49% (920/1876), 10.20 MiB | 20.26 MiB/s
Receiving objects: 50% (938/1876), 10.20 MiB | 20.26 MiB/s
Receiving objects: 51% (957/1876), 10.20 MiB | 20.26 MiB/s
Receiving objects: 51% (965/1876), 10.20 MiB | 20.26 MiB/s
Receiving objects: 52% (976/1876), 35.39 MiB | 22.45 MiB/s
Receiving objects: 53% (995/1876), 35.39 MiB | 22.45 MiB/s
Receiving objects: 54% (1014/1876), 35.39 MiB | 22.45 MiB/s
Receiving objects: 55% (1032/1876), 35.39 MiB | 22.45 MiB/s
Receiving objects: 56% (1051/1876), 35.39 MiB | 22.45 MiB/s
Receiving objects: 57% (1070/1876), 35.39 MiB | 22.45 MiB/s
Receiving objects: 58% (1089/1876), 35.39 MiB | 22.45 MiB/s
Receiving objects: 59% (1107/1876), 35.39 MiB | 22.45 MiB/s
Receiving objects: 60% (1126/1876), 35.39 MiB | 22.45 MiB/s
Receiving objects: 61% (1145/1876), 35.39 MiB | 22.45 MiB/s
Receiving objects: 62% (1164/1876), 35.39 MiB | 22.45 MiB/s
Receiving objects: 63% (1182/1876), 35.39 MiB | 22.45 MiB/s
Receiving objects: 64% (1201/1876), 35.39 MiB | 22.45 MiB/s
Receiving objects: 65% (1220/1876), 35.39 MiB | 22.45 MiB/s
Receiving objects: 66% (1239/1876), 35.39 MiB | 22.45 MiB/s
Receiving objects: 67% (1257/1876), 35.39 MiB | 22.45 MiB/s
Receiving objects: 68% (1276/1876), 35.39 MiB | 22.45 MiB/s
Receiving objects: 69% (1295/1876), 35.39 MiB | 22.45 MiB/s
Receiving objects: 70% (1314/1876), 35.39 MiB | 22.45 MiB/s
Receiving objects: 71% (1332/1876), 35.39 MiB | 22.45 MiB/s
Receiving objects: 72% (1351/1876), 35.39 MiB | 22.45 MiB/s
Receiving objects: 73% (1370/1876), 35.39 MiB | 22.45 MiB/s
Receiving objects: 74% (1389/1876), 35.39 MiB | 22.45 MiB/s
Receiving objects: 75% (1407/1876), 35.39 MiB | 22.45 MiB/s
Receiving objects: 76% (1426/1876), 35.39 MiB | 22.45 MiB/s
Receiving objects: 77% (1445/1876), 35.39 MiB | 22.45 MiB/s
Receiving objects: 78% (1464/1876), 35.39 MiB | 22.45 MiB/s
Receiving objects: 79% (1483/1876), 35.39 MiB | 22.45 MiB/s
Receiving objects: 80% (1501/1876), 35.39 MiB | 22.45 MiB/s
Receiving objects: 81% (1520/1876), 35.39 MiB | 22.45 MiB/s
Receiving objects: 82% (1539/1876), 35.39 MiB | 22.45 MiB/s
Receiving objects: 83% (1558/1876), 35.39 MiB | 22.45 MiB/s
Receiving objects: 84% (1576/1876), 35.39 MiB | 22Line truncated
|
|
||||||
Receiving objects: 100% (1876/1876), 35.39 MiB | 22.45 MiB/s␍Receiving objects: 100% (1876/1876), 47.76 MiB | 23.69 MiB/s, done.
|
|
||||||
Resolving deltas: 0% (0/320)␍Resolving deltas: 1% (4/320)␍Resolving deltas: 2% (7/320)␍Resolving deltas: 3% (10/320)␍Resolving deltas: 4% (13/320)␍Resolving deltas: 5% (16/320)␍Resolving deltas: 6% (20/320)␍Resolving deltas: 7% (23/320)␍Resolving deltas: 8% (26/320)␍Resolving deltas: 9% (29/320)␍Resolving deltas: 10% (32/320)␍Resolving deltas: 11% (36/320)␍Resolving deltas: 12% (39/320)␍Resolving deltas: 13% (42/320)␍Resolving deltas: 14% (45/320)␍Resolving deltas: 15% (48/320)␍Resolving deltas: 16% (52/320)␍Resolving deltas: 17% (55/320)␍Resolving deltas: 18% (58/320)␍Resolving deltas: 19% (61/320)␍Resolving deltas: 20% (64/320)␍Resolving deltas: 21% (68/320)␍Resolving deltas: 22% (71/320)␍Resolving deltas: 23% (74/320)␍Resolving deltas: 24% (77/320)␍Resolving deltas: 25% (80/320)␍Resolving deltas: 26% (85/320)␍Resolving deltas: 27% (87/320)␍Resolving deltas: 28% (90/320)␍Resolving deltas: 29% (93/320)␍Resolving deltas: 30% (96/320)␍Resolving deltas: 31% (100/320)␍Resolving deltas: 32% (103/320)␍Resolving deltas: 33% (106/320)␍Resolving deltas: 34% (110/320)␍Resolving deltas: 35% (112/320)␍Resolving deltas: 36% (116/320)␍Resolving deltas: 37% (119/320)␍Resolving deltas: 38% (122/320)␍Resolving deltas: 39% (125/320)␍Resolving deltas: 40% (128/320)␍Resolving deltas: 41% (132/320)␍Resolving deltas: 42% (135/320)␍Resolving deltas: 43% (138/320)␍Resolving deltas: 44% (142/320)␍Resolving deltas: 45% (144/320)␍Resolving deltas: 46% (148/320)␍Resolving deltas: 47% (151/320)␍Resolving deltas: 48% (154/320)␍Resolving deltas: 49% (157/320)␍Resolving deltas: 50% (160/320)␍Resolving deltas: 51% (164/320)␍Resolving deltas: 52% (167/320)␍Resolving deltas: 53% (170/320)␍Resolving deltas: 54% (173/320)␍Resolving deltas: 55% (176/320)␍Resolving deltas: 56% (180/320)␍Resolving deltas: 57% (183/320)␍Resolving deltas: 58% (186/320)␍Resolving deltas: 59% (189/320)␍Resolving deltas: 60% (192/320)␍Resolving deltas: 61% (196/320)␍Resolving deltas: 62% (199/320)␍Resolving deltas: 63% (202/320)␍Resolving deltas: 64% (205/320)␍Resolving deltas: 65% (208/320)␍Resolving deltas: 66% (212/320)␍Resolving deltas: 67% (215/320)␍Resolving deltas: 68% (218/320)␍Resolving deltas: 69% (221/320)␍Resolving deltas: 70% (224/320)␍Resolving deltas: 71% (228/320)␍Resolving deltas: 72% (231/320)␍Resolving deltas: 73% (234/320)␍Resolving deltas: 74% (237/320)␍Resolving deltas: 75% (240/320)␍Resolving deltas: 76% (244/320)␍Resolving deltas: 77% (247/320)␍Resolving deltas: 78% (250/320)␍Resolving deltas: 79% (253/320)␍Resolving deltas: 80% (256/320)␍Resolving deltas: 81% (260/320)␍Resolving deltas: 82% (263/320)␍Resolving deltas: 83% (266/320)␍Resolving deltas: 84% (269/320)␍Resolving deltas: 85% (272/320)␍Resolving deltas: 86% (276/320)␍Resolving deltas: 87% (279/320)␍Resolving deltas: 88% (282/320)␍Resolving deltas: 89% (285/320)␍Resolving deltas: 90% (288/320)␍Resolving deltas: 91% (292/320)␍Resolving deltas: 92% (295/320)␍Resolving deltas: 93% (298/320)␍Resolving deltas: 94% (301/320)␍Resolving deltas: 95% (304/320)␍Resolving deltas: 96% (308/320)␍Resolving deltas: 97% (311/320)␍Resolving deltas: 98% (314/320)␍Resolving deltas: 99% (317/320)␍Resolving deltas: 100% (320/320)␍Resolving deltas: 100% (320/320), done.
|
|
||||||
> Installing railpack, please wait…
|
|
||||||
____ _ _ _
|
|
||||||
| _ \ __ _(_) |_ __ __ _ ___| | __
|
|
||||||
| |_) / _` | | | '_ \ / _` |/ __| |/ /
|
|
||||||
| _ < (_| | | | |_) | (_| | (__| <
|
|
||||||
|_| \_\__,_|_|_| .__/ \__,_|\___|_|\_\
|
|
||||||
|_|
|
|
||||||
Railpack is now installed!
|
|
||||||
Run 'railpack --help' to get started
|
|
||||||
railpack-dfm-aos-lgbcnc-t6ahqz
|
|
||||||
Preparing Railpack build plan...
|
|
||||||
╭─────────────────╮
|
|
||||||
│ Railpack 0.15.4 │
|
|
||||||
╰─────────────────╯
|
|
||||||
↳ Found .dockerignore file, applying filters
|
|
||||||
↳ Detected Node
|
|
||||||
↳ Using bun package manager
|
|
||||||
Packages
|
|
||||||
──────────
|
|
||||||
bun │ 1.4.4 │ railpack default (latest)
|
|
||||||
node │ 26.12.1 │ railpack default (latest)
|
|
||||||
Steps
|
|
||||||
──────────
|
|
||||||
▸ install
|
|
||||||
$ bun install --frozen-lockfile
|
|
||||||
▸ build
|
|
||||||
$ bun run build
|
|
||||||
Deploy
|
|
||||||
──────────
|
|
||||||
$ bun run start
|
|
||||||
✅ Railpack prepare completed.
|
|
||||||
Building with Railpack frontend...
|
|
||||||
#0 building with "railpack-dfm-aos-lgbcnc-t6ahqz" instance using docker-container driver
|
|
||||||
#1 [internal] booting buildkit
|
|
||||||
#1 pulling image moby/buildkit:buildx-stable-1
|
|
||||||
#1 pulling image moby/buildkit:buildx-stable-1 1.1s done
|
|
||||||
#1 creating container buildx_buildkit_railpack-dfm-aos-lgbcnc-t6ahqz0
|
|
||||||
#1 creating container buildx_buildkit_railpack-dfm-aos-lgbcnc-t6ahqz0 1.0s done
|
|
||||||
#1 DONE 2.1s
|
|
||||||
#2 resolve image config for docker-image://ghcr.io/railwayapp/railpack-frontend:v0.15.4
|
|
||||||
#2 DONE 1.4s
|
|
||||||
#3 docker-image://ghcr.io/railwayapp/railpack-frontend:v0.15.4@sha256:7e0535e519d9d00793d0bb4e652be5d48373ab5e0c7d9b90ef6bc40147290ff7
|
|
||||||
#3 resolve ghcr.io/railwayapp/railpack-frontend:v0.15.4@sha256:7e0535e519d9d00793d0bb4e652be5d48373ab5e0c7d9b90ef6bc40147290ff7 done
|
|
||||||
#3 sha256:76fdf18f436616aff2234f2d325d888d31af103f333a8f491d539dce0106e849 0B / 7.90MB 0.2s
|
|
||||||
#3 sha256:1074353eec0db2c1d81d5af2671e56e00cf5738486f5762609ea33d606f88612 0B / 3.86MB 0.2s
|
|
||||||
#3 sha256:76fdf18f436616aff2234f2d325d888d31af103f333a8f491d539dce0106e849 7.90MB / 7.90MB 0.5s
|
|
||||||
#3 sha256:76fdf18f436616aff2234f2d325d888d31af103f333a8f491d539dce0106e849 7.90MB / 7.90MB 0.5s done
|
|
||||||
#3 sha256:1074353eec0db2c1d81d5af2671e56e00cf5738486f5762609ea33d606f88612 1.05MB / 3.86MB 0.6s
|
|
||||||
#3 sha256:1074353eec0db2c1d81d5af2671e56e00cf5738486f5762609ea33d606f88612 2.10MB / 3.86MB 0.8s
|
|
||||||
#3 sha256:1074353eec0db2c1d81d5af2671e56e00cf5738486f5762609ea33d606f88612 3.86MB / 3.86MB 0.9s done
|
|
||||||
#3 extracting sha256:1074353eec0db2c1d81d5af2671e56e00cf5738486f5762609ea33d606f88612 0.1s done
|
|
||||||
#3 extracting sha256:76fdf18f436616aff2234f2d325d888d31af103f333a8f491d539dce0106e849 0.1s done
|
|
||||||
#3 DONE 1.2s
|
|
||||||
#4 load build definition from railpack-plan.json
|
|
||||||
#4 transferring dockerfile: 5.06kB done
|
|
||||||
#4 DONE 0.0s
|
|
||||||
#5 loading .
|
|
||||||
#5 DONE 0.0s
|
|
||||||
#6 [railpack] secrets hash
|
|
||||||
#6 DONE 0.0s
|
|
||||||
#7 docker-image://ghcr.io/railwayapp/railpack-builder:latest
|
|
||||||
#7 resolve ghcr.io/railwayapp/railpack-builder:latest
|
|
||||||
#7 resolve ghcr.io/railwayapp/railpack-builder:latest 0.9s done
|
|
||||||
#7 DONE 0.9s
|
|
||||||
#8 docker-image://ghcr.io/railwayapp/railpack-runtime:latest
|
|
||||||
#8 resolve ghcr.io/railwayapp/railpack-runtime:latest
|
|
||||||
#8 ...
|
|
||||||
#6 [railpack] secrets hash
|
|
||||||
#6 DONE 0.0s
|
|
||||||
#7 docker-image://ghcr.io/railwayapp/railpack-builder:latest
|
|
||||||
#7 DONE 1.0s
|
|
||||||
#5 loading .
|
|
||||||
#5 transferring context: 15.35MB 0.2s
|
|
||||||
#5 ...
|
|
||||||
#9 [railpack] loading secrets
|
|
||||||
#9 resolve docker.io/library/alpine:latest 1.6s done
|
|
||||||
#9 sha256:7b229517ed222597277036d94892173207d01a731ab3a88eeb1de2e963a2c788 3.85MB / 3.85MB 0.6s done
|
|
||||||
#9 extracting sha256:7b229517ed222597277036d94892173207d01a731ab3a88eeb1de2e963a2c788 0.3s done
|
|
||||||
#9 DONE 2.5s
|
|
||||||
#5 loading .
|
|
||||||
#5 ...
|
|
||||||
#10 [railpack] copy secrets hash
|
|
||||||
#10 DONE 0.7s
|
|
||||||
#5 loading .
|
|
||||||
#5 transferring context: 128.38MB 2.4s done
|
|
||||||
#5 DONE 2.8s
|
|
||||||
#7 docker-image://ghcr.io/railwayapp/railpack-builder:latest
|
|
||||||
#7 sha256:193926ad1d06489b7487e8ac4ae2d0874e6ff05cf65d874d2af508830fc03def 119B / 119B 0.2s done
|
|
||||||
#7 sha256:df614908d6aba31e983953b17fd48496d27425529b3947c3d5583c4cc9c15c9a 868.40kB / 868.40kB 0.6s done
|
|
||||||
#7 sha256:604add184d03d4cf6e2ff1c4b9013b265eb9c11570afe28ce8f9dc417b98ea3f 78.64MB / 237.08MB 2.6s
|
|
||||||
#7 sha256:08a1e03b3da5bb4a1059032dca3216f33ddfc4a48a45db88921f5bb2e9a8fa2d 41.94MB / 53.72MB 2.6s
|
|
||||||
#7 sha256:4f4fb700ef54461cfa02571ae0db9a0dc1e0cdb5577484a6d75e68dc38e8acc1 32B / 32B 0.3s done
|
|
||||||
#7 sha256:4dc3950125ebc9ed195e1101fc6c02e2fce113ba0f53bfb05b2cdf58747df9af 31.46MB / 67.81MB 2.1s
|
|
||||||
#7 sha256:62fe2e747f69f2f414c7e9eb1553155cf0a658398f0462557f458821dce2b29d 25.64MB / 25.64MB 1.5s done
|
|
||||||
#7 sha256:4846f29007305297af653c57bf9b60ba8f676a38695c68d98460063442581671 5.24MB / 49.39MB 0.5s
|
|
||||||
#7 ...
|
|
||||||
#11 [railpack] hash used secrets
|
|
||||||
#11 DONE 0.5s
|
|
||||||
#12 [railpack] copy used secrets hash
|
|
||||||
#12 DONE 0.0s
|
|
||||||
#7 docker-image://ghcr.io/railwayapp/railpack-builder:latest
|
|
||||||
#7 sha256:604add184d03d4cf6e2ff1c4b9013b265eb9c11570afe28ce8f9dc417b98ea3f 91.23MB / 237.08MB 2.9s
|
|
||||||
#7 sha256:4846f29007305297af653c57bf9b60ba8f676a38695c68d98460063442581671 11.53MB / 49.39MB 0.6s
|
|
||||||
#7 sha256:4846f29007305297af653c57bf9b60ba8f676a38695c68d98460063442581671 16.78MB / 49.39MB 0.8s
|
|
||||||
#7 sha256:4dc3950125ebc9ed195e1101fc6c02e2fce113ba0f53bfb05b2cdf58747df9af 37.75MB / 67.81MB 2.6s
|
|
||||||
#7 sha256:4846f29007305297af653c57bf9b60ba8f676a38695c68d98460063442581671 20.97MB / 49.39MB 0.9s
|
|
||||||
#7 sha256:604add184d03d4cf6e2ff1c4b9013b265eb9c11570afe28ce8f9dc417b98ea3f 112.20MB / 237.08MB 3.3s
|
|
||||||
#7 sha256:4dc3950125ebc9ed195e1101fc6c02e2fce113ba0f53bfb05b2cdf58747df9af 41.94MB / 67.81MB 2.7s
|
|
||||||
#7 sha256:4dc3950125ebc9ed195e1101fc6c02e2fce113ba0f53bfb05b2cdf58747df9af 49.28MB / 67.81MB 3.0s
|
|
||||||
#7 sha256:604add184d03d4cf6e2ff1c4b9013b265eb9c11570afe28ce8f9dc417b98ea3f 128.97MB / 237.08MB 3.8s
|
|
||||||
#7 sha256:4846f29007305297af653c57bf9b60ba8f676a38695c68d98460063442581671 27.26MB / 49.39MB 1.5s
|
|
||||||
#7 sha256:4dc3950125ebc9ed195e1101fc6c02e2fce113ba0f53bfb05b2cdf58747df9af 54.53MB / 67.81MB 3.3s
|
|
||||||
#7 sha256:4846f29007305297af653c57bf9b60ba8f676a38695c68d98460063442581671 31.46MB / 49.39MB 1.7s
|
|
||||||
#7 sha256:4846f29007305297af653c57bf9b60ba8f676a38695c68d98460063442581671 38.80MB / 49.39MB 1.8s
|
|
||||||
#7 sha256:4dc3950125ebc9ed195e1101fc6c02e2fce113ba0f53bfb05b2cdf58747df9af 60.82MB / 67.81MB 3.6s
|
|
||||||
#7 sha256:4846f29007305297af653c57bf9b60ba8f676a38695c68d98460063442581671 46.14MB / 49.39MB 2.0s
|
|
||||||
#7 sha256:604add184d03d4cf6e2ff1c4b9013b265eb9c11570afe28ce8f9dc417b98ea3f 150.99MB / 237.08MB 4.4s
|
|
||||||
#7 sha256:4846f29007305297af653c57bf9b60ba8f676a38695c68d98460063442581671 49.39MB / 49.39MB 2.1s done
|
|
||||||
#7 extracting sha256:4846f29007305297af653c57bf9b60ba8f676a38695c68d98460063442581671
|
|
||||||
#7 sha256:4dc3950125ebc9ed195e1101fc6c02e2fce113ba0f53bfb05b2cdf58747df9af 67.81MB / 67.81MB 4.0s done
|
|
||||||
#7 sha256:604add184d03d4cf6e2ff1c4b9013b265eb9c11570afe28ce8f9dc417b98ea3f 167.77MB / 237.08MB 4.8s
|
|
||||||
#7 sha256:604add184d03d4cf6e2ff1c4b9013b265eb9c11570afe28ce8f9dc417b98ea3f 181.40MB / 237.08MB 5.3s
|
|
||||||
#7 sha256:604add184d03d4cf6e2ff1c4b9013b265eb9c11570afe28ce8f9dc417b98ea3f 197.13MB / 237.08MB 5.7s
|
|
||||||
#7 sha256:604add184d03d4cf6e2ff1c4b9013b265eb9c11570afe28ce8f9dc417b98ea3f 209.72MB / 237.08MB 6.2s
|
|
||||||
#7 sha256:604add184d03d4cf6e2ff1c4b9013b265eb9c11570afe28ce8f9dc417b98ea3f 224.40MB / 237.08MB 6.8s
|
|
||||||
#7 sha256:604add184d03d4cf6e2ff1c4b9013b265eb9c11570afe28ce8f9dc417b98ea3f 237.08MB / 237.08MB 7.2s
|
|
||||||
#7 sha256:604add184d03d4cf6e2ff1c4b9013b265eb9c11570afe28ce8f9dc417b98ea3f 237.08MB / 237.08MB 7.4s done
|
|
||||||
#7 sha256:08a1e03b3da5bb4a1059032dca3216f33ddfc4a48a45db88921f5bb2e9a8fa2d 44.04MB / 53.72MB 7.7s
|
|
||||||
#7 extracting sha256:4846f29007305297af653c57bf9b60ba8f676a38695c68d98460063442581671 4.3s done
|
|
||||||
#7 extracting sha256:62fe2e747f69f2f414c7e9eb1553155cf0a658398f0462557f458821dce2b29d
|
|
||||||
#7 ...
|
|
||||||
#8 docker-image://ghcr.io/railwayapp/railpack-runtime:latest
|
|
||||||
#8 resolve ghcr.io/railwayapp/railpack-runtime:latest 1.6s done
|
|
||||||
#8 sha256:ecc510c1e359bdc007b39802570bb7e4dec7d6ebccf357c3201a74299113e05e 29.84MB / 29.84MB 1.8s done
|
|
||||||
#8 sha256:75dc09925ca146a3efecc887098f8f1313da0fb1b0c8d36d628b6cae320665ec 7.39MB / 7.39MB 0.6s done
|
|
||||||
#8 extracting sha256:ecc510c1e359bdc007b39802570bb7e4dec7d6ebccf357c3201a74299113e05e 2.6s done
|
|
||||||
#8 extracting sha256:75dc09925ca146a3efecc887098f8f1313da0fb1b0c8d36d628b6cae320665ec 0.4s done
|
|
||||||
#8 DONE 10.0s
|
|
||||||
#7 docker-image://ghcr.io/railwayapp/railpack-builder:latest
|
|
||||||
#7 extracting sha256:62fe2e747f69f2f414c7e9eb1553155cf0a658398f0462557f458821dce2b29d 1.4s done
|
|
||||||
#7 extracting sha256:4dc3950125ebc9ed195e1101fc6c02e2fce113ba0f53bfb05b2cdf58747df9af
|
|
||||||
#7 sha256:08a1e03b3da5bb4a1059032dca3216f33ddfc4a48a45db88921f5bb2e9a8fa2d 46.14MB / 53.72MB 12.8s
|
|
||||||
#7 extracting sha256:4dc3950125ebc9ed195e1101fc6c02e2fce113ba0f53bfb05b2cdf58747df9af 2.9s done
|
|
||||||
#7 extracting sha256:4f4fb700ef54461cfa02571ae0db9a0dc1e0cdb5577484a6d75e68dc38e8acc1 done
|
|
||||||
#7 ...
|
|
||||||
#13 install apt packages: libatomic1
|
|
||||||
#13 0.328 Get:1 http://deb.debian.org/debian trixie InRelease [140 kB]
|
|
||||||
#13 0.416 Get:2 http://deb.debian.org/debian trixie-updates InRelease [47.3 kB]
|
|
||||||
#13 0.439 Get:3 http://deb.debian.org/debian-security trixie-security InRelease [43.4 kB]
|
|
||||||
#13 0.516 Get:4 http://deb.debian.org/debian trixie/main amd64 Packages [9678 kB]
|
|
||||||
#13 0.927 Get:5 http://deb.debian.org/debian trixie-updates/main amd64 Packages [720 B]
|
|
||||||
#13 0.930 Get:6 http://deb.debian.org/debian-security trixie-security/main amd64 Packages [270 kB]
|
|
||||||
#13 2.381 Fetched 10.2 MB in 2s (4712 kB/s)
|
|
||||||
#13 2.381 Reading package lists...
|
|
||||||
#13 3.392 Reading package lists...
|
|
||||||
#13 4.175 Building dependency tree...
|
|
||||||
#13 4.330 Reading state information...
|
|
||||||
#13 4.627 The following NEW packages will be installed:
|
|
||||||
#13 4.629 libatomic1
|
|
||||||
#13 4.743 0 upgraded, 1 newly installed, 0 to remove and 3 not upgraded.
|
|
||||||
#13 4.743 Need to get 9308 B of archives.
|
|
||||||
#13 4.743 After this operation, 46.1 kB of additional disk space will be used.
|
|
||||||
#13 4.743 Get:1 http://deb.debian.org/debian trixie/main amd64 libatomic1 amd64 14.2.0-19 [9308 B]
|
|
||||||
#13 4.917 debconf: unable to initialize frontend: Dialog
|
|
||||||
#13 4.917 debconf: (TERM is not set, so the dialog frontend is not usable.)
|
|
||||||
#13 4.917 debconf: falling back to frontend: Readline
|
|
||||||
#13 4.917 debconf: unable to initialize frontend: Readline
|
|
||||||
#13 4.917 debconf: (Can't locate Term/ReadLine.pm in @INC (you may need to install the Term::ReadLine module) (@INC entries checked: /etc/perl /usr/local/lib/x86_64-linux-gnu/perl/5.40.1 /usr/local/share/perl/5.40.1 /usr/lib/x86_64-linux-gnu/perl5/5.40 /usr/share/perl5 /usr/lib/x86_64-linux-gnu/perl-base /usr/lib/x86_64-linux-gnu/perl/5.40 /usr/share/perl/5.40 /usr/local/lib/site_perl) at /usr/share/perl5/Debconf/FrontEnd/Readline.pm line 8, <STDIN> line 1.)
|
|
||||||
#13 4.917 debconf: falling back to frontend: Teletype
|
|
||||||
#13 4.922 debconf: unable to initialize frontend: Teletype
|
|
||||||
#13 4.922 debconf: (This frontend requires a controlling tty.)
|
|
||||||
#13 4.922 debconf: falling back to frontend: Noninteractive
|
|
||||||
#13 5.640 Fetched 9308 B in 0s (95.7 kB/s)
|
|
||||||
#13 5.670 Selecting previously unselected package libatomic1:amd64.
|
|
||||||
#13 5.670 (Reading database ... ␍(Reading database ... 5%␍(Reading database ... 10%␍(Reading database ... 15%␍(Reading database ... 20%␍(Reading database ... 25%␍(Reading database ... 30%␍(Reading database ... 35%␍(Reading database ... 40%␍(Reading database ... 45%␍(Reading database ... 50%␍(Reading database ... 55%␍(Reading database ... 60%␍(Reading database ... 65%␍(Reading database ... 70%␍(Reading database ... 75%␍(Reading database ... 80%␍(Reading database ... 85%␍(Reading database ... 90%␍(Reading database ... 95%␍(Reading database ... 100%␍(Reading database ... 6228 files and directories currently installed.)
|
|
||||||
#13 5.686 Preparing to unpack .../libatomic1_14.2.0-19_amd64.deb ...
|
|
||||||
#13 5.692 Unpacking libatomic1:amd64 (14.2.0-19) ...
|
|
||||||
#13 5.730 Setting up libatomic1:amd64 (14.2.0-19) ...
|
|
||||||
#13 5.739 Processing triggers for libc-bin (2.41-12+deb13u4) ...
|
|
||||||
#13 DONE 6.4s
|
|
||||||
#7 docker-image://ghcr.io/railwayapp/railpack-builder:latest
|
|
||||||
#7 sha256:08a1e03b3da5bb4a1059032dca3216f33ddfc4a48a45db88921f5bb2e9a8fa2d 48.23MB / 53.72MB 17.9s
|
|
||||||
#7 sha256:08a1e03b3da5bb4a1059032dca3216f33ddfc4a48a45db88921f5bb2e9a8fa2d 49.28MB / 53.72MB 23.0s
|
|
||||||
#7 sha256:08a1e03b3da5bb4a1059032dca3216f33ddfc4a48a45db88921f5bb2e9a8fa2d 51.38MB / 53.72MB 28.1s
|
|
||||||
#7 sha256:08a1e03b3da5bb4a1059032dca3216f33ddfc4a48a45db88921f5bb2e9a8fa2d 52.43MB / 53.72MB 33.2s
|
|
||||||
#7 sha256:08a1e03b3da5bb4a1059032dca3216f33ddfc4a48a45db88921f5bb2e9a8fa2d 53.72MB / 53.72MB 34.6s done
|
|
||||||
#7 extracting sha256:08a1e03b3da5bb4a1059032dca3216f33ddfc4a48a45db88921f5bb2e9a8fa2d
|
|
||||||
#7 extracting sha256:08a1e03b3da5bb4a1059032dca3216f33ddfc4a48a45db88921f5bb2e9a8fa2d 1.0s done
|
|
||||||
#7 DONE 36.7s
|
|
||||||
#7 docker-image://ghcr.io/railwayapp/railpack-builder:latest
|
|
||||||
#7 extracting sha256:604add184d03d4cf6e2ff1c4b9013b265eb9c11570afe28ce8f9dc417b98ea3f
|
|
||||||
#7 extracting sha256:604add184d03d4cf6e2ff1c4b9013b265eb9c11570afe28ce8f9dc417b98ea3f 7.1s done
|
|
||||||
#7 DONE 43.7s
|
|
||||||
#7 docker-image://ghcr.io/railwayapp/railpack-builder:latest
|
|
||||||
#7 extracting sha256:df614908d6aba31e983953b17fd48496d27425529b3947c3d5583c4cc9c15c9a 0.0s done
|
|
||||||
#7 extracting sha256:193926ad1d06489b7487e8ac4ae2d0874e6ff05cf65d874d2af508830fc03def done
|
|
||||||
#7 DONE 43.8s
|
|
||||||
#14 mkdir /etc/mise
|
|
||||||
#14 DONE 0.4s
|
|
||||||
#15 create mise config
|
|
||||||
#15 DONE 0.0s
|
|
||||||
#16 install mise packages: bun, node
|
|
||||||
#16 0.083 mise by @jdx – installing 2 tools
|
|
||||||
#16 3.083 mise ███████░░░░░░░░░ 0/2 · 3.0s
|
|
||||||
#16 3.083 bun@1.4.4 downloading 2.7s 6.1/51.8 MB · 2.8 MB/s
|
|
||||||
#16 3.083 node@26.12.1 extracting 2.7s
|
|
||||||
#16 4.769 mise node@26.12.1 v26.12.1
|
|
||||||
#16 4.884 mise node@26.12.1 11.20.0
|
|
||||||
#16 4.916 mise ✓ node@26.12.1 4.5s node-v26.12.1-linux-x64.tar.gz
|
|
||||||
#16 6.083 mise ██████████░░░░░░ 1/2 · 6.0s
|
|
||||||
#16 6.083 bun@1.4.4 downloading 5.7s 25.2/51.8 MB · 4.9 MB/s
|
|
||||||
#16 8.951 mise bun@1.4.4 1.4.4
|
|
||||||
#16 8.963 mise ✓ bun@1.4.4 8.6s bun-linux-x64.zip
|
|
||||||
#16 8.963 mise ████████████████ 2/2 · installed 2 tools in 8.9s
|
|
||||||
#16 DONE 9.7s
|
|
||||||
#17 copy / /app
|
|
||||||
#17 ...
|
|
||||||
#18 copy /mise/shims
|
|
||||||
#18 DONE 0.0s
|
|
||||||
#17 copy / /app
|
|
||||||
#17 DONE 0.7s
|
|
||||||
#19 mkdir -p /app/node_modules/.cache
|
|
||||||
#19 DONE 0.1s
|
|
||||||
#20 bun install --frozen-lockfile
|
|
||||||
#20 0.115 bun install v1.4.4 (38afee6c8)
|
|
||||||
#20 ...
|
|
||||||
#21 copy /mise/installs
|
|
||||||
#21 DONE 6.6s
|
|
||||||
#20 bun install --frozen-lockfile
|
|
||||||
#20 ...
|
|
||||||
#22 copy /usr/local/bin/mise
|
|
||||||
#22 DONE 0.6s
|
|
||||||
#20 bun install --frozen-lockfile
|
|
||||||
#20 ...
|
|
||||||
#23 copy /etc/mise/config.toml
|
|
||||||
#23 DONE 0.0s
|
|
||||||
#24 copy /root/.local/state/mise
|
|
||||||
#24 DONE 0.0s
|
|
||||||
#20 bun install --frozen-lockfile
|
|
||||||
#20 16.44
|
|
||||||
#20 16.44 $ prisma generate || true
|
|
||||||
#20 19.49 Prisma schema loaded from prisma/schema.prisma
|
|
||||||
#20 20.50
|
|
||||||
#20 20.50 ✔ Generated Prisma Client (v6.19.2) to ./node_modules/@prisma/client in 413ms
|
|
||||||
#20 20.50
|
|
||||||
#20 20.50 Start by importing your Prisma Client (See: https://pris.ly/d/importing-client)
|
|
||||||
#20 20.50
|
|
||||||
#20 20.50 Tip: Need your database queries to be 1000x faster? Accelerate offers you that and more: https://pris.ly/tip-2-accelerate
|
|
||||||
#20 20.50
|
|
||||||
#20 20.62
|
|
||||||
#20 20.62 + @tailwindcss/postcss@4.1.18
|
|
||||||
#20 20.62 + @types/react@19.2.8
|
|
||||||
#20 20.62 + @types/react-dom@19.2.3
|
|
||||||
#20 20.62 + bun-types@1.3.6
|
|
||||||
#20 20.62 + eslint@9.39.2
|
|
||||||
#20 20.62 + eslint-config-next@16.1.3
|
|
||||||
#20 20.62 + tailwindcss@4.1.18
|
|
||||||
#20 20.62 + tw-animate-css@1.4.0
|
|
||||||
#20 20.62 + typescript@5.9.3
|
|
||||||
#20 20.62 + @dnd-kit/core@6.3.1
|
|
||||||
#20 20.62 + @dnd-kit/sortable@10.0.0
|
|
||||||
#20 20.62 + @dnd-kit/utilities@3.2.2
|
|
||||||
#20 20.62 + @hookform/resolvers@5.2.2
|
|
||||||
#20 20.62 + @hugeicons/core-free-icons@4.3.5
|
|
||||||
#20 20.62 + @hugeicons/react@1.1.10
|
|
||||||
#20 20.62 + @mdxeditor/editor@3.52.3
|
|
||||||
#20 20.62 + @prisma/client@6.19.2
|
|
||||||
#20 20.62 + @radix-ui/react-accordion@1.2.12
|
|
||||||
#20 20.62 + @radix-ui/react-alert-dialog@1.1.15
|
|
||||||
#20 20.62 + @radix-ui/react-aspect-ratio@1.1.8
|
|
||||||
#20 20.62 + @radix-ui/react-avatar@1.1.11
|
|
||||||
#20 20.62 + @radix-ui/react-checkbox@1.3.3
|
|
||||||
#20 20.62 + @radix-ui/react-collapsible@1.1.12
|
|
||||||
#20 20.62 + @radix-ui/react-context-menu@2.2.16
|
|
||||||
#20 20.62 + @radix-ui/react-dialog@1.1.15
|
|
||||||
#20 20.62 + @radix-ui/react-dropdown-menu@2.1.16
|
|
||||||
#20 20.62 + @radix-ui/react-hover-card@1.1.15
|
|
||||||
#20 20.62 + @radix-ui/react-label@2.1.8
|
|
||||||
#20 20.62 + @radix-ui/react-menubar@1.1.16
|
|
||||||
#20 20.62 + @radix-ui/react-navigation-menu@1.2.14
|
|
||||||
#20 20.62 + @radix-ui/react-popover@1.1.15
|
|
||||||
#20 20.62 + @radix-ui/react-progress@1.1.8
|
|
||||||
#20 20.62 + @radix-ui/react-radio-group@1.3.8
|
|
||||||
#20 20.62 + @radix-ui/react-scroll-area@1.2.10
|
|
||||||
#20 20.62 + @radix-ui/react-select@2.2.6
|
|
||||||
#20 20.62 + @radix-ui/react-separator@1.1.8
|
|
||||||
#20 20.62 + @radix-ui/react-slider@1.3.6
|
|
||||||
#20 20.62 + @radix-ui/react-slot@1.2.4
|
|
||||||
#20 20.62 + @radix-ui/react-switch@1.2.6
|
|
||||||
#20 20.62 + @radix-ui/react-tabs@1.1.13
|
|
||||||
#20 20.62 + @radix-ui/react-toast@1.2.15
|
|
||||||
#20 20.62 + @radix-ui/react-toggle@1.1.10
|
|
||||||
#20 20.62 + @radix-ui/react-toggle-group@1.1.11
|
|
||||||
#20 20.62 + @radix-ui/react-tooltip@1.2.8
|
|
||||||
#20 20.62 + @reactuses/core@6.1.9
|
|
||||||
#20 20.62 + @tanstack/react-query@5.90.19
|
|
||||||
#20 20.62 + @tanstack/react-table@8.21.3
|
|
||||||
#20 20.62 + class-variance-authority@0.7.1
|
|
||||||
#20 20.62 + clsx@2.1.1
|
|
||||||
#20 20.62 + cmdk@1.1.1
|
|
||||||
#20 20.62 + date-fns@4.1.0
|
|
||||||
#20 20.62 + embla-carousel-react@8.6.0
|
|
||||||
#20 20.62 + framer-motion@14.7.1
|
|
||||||
#20 20.62 + imapflow@2.9.1
|
|
||||||
#20 20.62 + input-otp@1.4.2
|
|
||||||
#20 20.62 + lucide-react@1.62.0
|
|
||||||
#20 20.62 + motion@12.43.0
|
|
||||||
#20 20.62 + next@16.1.3
|
|
||||||
#20 20.62 + next-auth@4.24.13
|
|
||||||
#20 20.62 + next-intl@4.7.0
|
|
||||||
#20 20.62 + next-themes@0.4.6
|
|
||||||
#20 20.62 + prisma@6.19.2
|
|
||||||
#20 20.62 + react@19.2.3
|
|
||||||
#20 20.62 + react-day-picker@9.13.0
|
|
||||||
#20 20.62 + react-dom@19.2.3
|
|
||||||
#20 20.62 + react-hook-form@7.71.1
|
|
||||||
#20 20.62 + react-markdown@10.1.0
|
|
||||||
#20 20.62 + react-resizable-panels@3.0.6
|
|
||||||
#20 20.62 + react-syntax-highlighter@15.6.6
|
|
||||||
#20 20.62 + recharts@2.15.4
|
|
||||||
#20 20.62 + sharp@0.34.5
|
|
||||||
#20 20.62 + sonner@2.0.7
|
|
||||||
#20 20.62 + tailwind-merge@3.7.0
|
|
||||||
#20 20.62 + tailwindcss-animate@1.0.7
|
|
||||||
#20 20.62 + uuid@11.1.0
|
|
||||||
#20 20.62 + vaul@1.1.2
|
|
||||||
#20 20.62 + z-ai-web-dev-sdk@0.0.18
|
|
||||||
#20 20.62 + zod@4.3.5
|
|
||||||
#20 20.62 + zustand@5.0.10
|
|
||||||
#20 20.62
|
|
||||||
#20 20.62 858 packages installed [20.50s]
|
|
||||||
#20 DONE 22.7s
|
|
||||||
#25 copy / /app
|
|
||||||
#25 DONE 5.8s
|
|
||||||
#26 bun run build
|
|
||||||
#26 0.191 $ prisma generate && next build && cp -r .next/static .next/standalone/.next/ && cp -r public .next/standalone/
|
|
||||||
#26 1.454 Prisma schema loaded from prisma/schema.prisma
|
|
||||||
#26 2.440 ┌─────────────────────────────────────────────────────────┐
|
|
||||||
#26 2.440 │ Update available 6.19.2 -> 8.0.0-rc.28 │
|
|
||||||
#26 2.440 │ │
|
|
||||||
#26 2.440 │ This is a major update - please follow the guide at │
|
|
||||||
#26 2.440 │ https://pris.ly/d/major-version-upgrade │
|
|
||||||
#26 2.440 │ │
|
|
||||||
#26 2.440 │ Run the following to update │
|
|
||||||
#26 2.440 │ npm i --save-dev prisma@latest │
|
|
||||||
#26 2.440 │ npm i @prisma/client@latest │
|
|
||||||
#26 2.440 └─────────────────────────────────────────────────────────┘
|
|
||||||
#26 2.441
|
|
||||||
#26 2.441 ✔ Generated Prisma Client (v6.19.2) to ./node_modules/@prisma/client in 598ms
|
|
||||||
#26 2.441
|
|
||||||
#26 2.441 Start by importing your Prisma Client (See: https://pris.ly/d/importing-client)
|
|
||||||
#26 2.441
|
|
||||||
#26 2.441 Tip: Interested in query caching in just a few lines of code? Try Accelerate today! https://pris.ly/tip-3-accelerate
|
|
||||||
#26 2.441
|
|
||||||
#26 2.805 ⚠ You are using a non-standard "NODE_ENV" value in your environment. This creates inconsistencies in the project and is strongly advised against. Read more: https://nextjs.org/docs/messages/non-standard-node-env
|
|
||||||
#26 3.933 ▲ Next.js 16.1.3 (Turbopack)
|
|
||||||
#26 3.933
|
|
||||||
#26 3.977 Creating an optimized production build ...
|
|
||||||
#26 11.38 (node:109) [DEP0205] DeprecationWarning: `module.register()` is deprecated. Use `module.registerHooks()` instead.
|
|
||||||
#26 11.38 (Use `node --trace-deprecation ...` to show where the warning was created)
|
|
||||||
#26 28.93
|
|
||||||
#26 28.93 > Build error occurred
|
|
||||||
#26 28.93 Error: Turbopack build failed with 2 errors:
|
|
||||||
#26 28.93 ./src/components/aos/fuse-cta.tsx:3:1
|
|
||||||
#26 28.93 Export default doesn't exist in target module
|
|
||||||
#26 28.93 [0m [90m 1 |[39m [32m'use client'[39m
|
|
||||||
#26 28.93 [90m 2 |[39m
|
|
||||||
#26 28.93 [31m[1m>[22m[39m[90m 3 |[39m [36mimport[39m [33mFuseButton[39m [36mfrom[39m [32m'@/components/FuseButton'[39m
|
|
||||||
#26 28.93 [90m |[39m [31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m
|
|
||||||
#26 28.93 [90m 4 |[39m [36mimport[39m { useState } [36mfrom[39m [32m'react'[39m
|
|
||||||
#26 28.93 [90m 5 |[39m [36mimport[39m { toast } [36mfrom[39m [32m'sonner'[39m
|
|
||||||
#26 28.93 [90m 6 |[39m [36mimport[39m { [33mLoader2[39m } [36mfrom[39m [32m'lucide-react'[39m[0m
|
|
||||||
#26 28.93
|
|
||||||
#26 28.93 The export default was not found in module [project]/src/components/FuseButton.tsx [app-client] (ecmascript).
|
|
||||||
#26 28.93 Did you mean to import FuseButton?
|
|
||||||
#26 28.93 All exports of the module are statically known (It doesn't have dynamic exports). So it's known statically that the requested export doesn't exist.
|
|
||||||
#26 28.93
|
|
||||||
#26 28.93 Import traces:
|
|
||||||
#26 28.93 App Route:
|
|
||||||
#26 28.93 ./src/components/aos/fuse-cta.tsx
|
|
||||||
#26 28.93 ./src/lib/storage.ts
|
|
||||||
#26 28.93 ./src/app/api/aos/belege/upload/route.ts
|
|
||||||
#26 28.93
|
|
||||||
#26 28.93 Client Component Browser:
|
|
||||||
#26 28.93 ./src/components/aos/fuse-cta.tsx [Client Component Browser]
|
|
||||||
#26 28.93 ./src/components/aos/views/recurring.tsx [Client Component Browser]
|
|
||||||
#26 28.93 ./src/components/aos/app-shell.tsx [Client Component Browser]
|
|
||||||
#26 28.93 ./src/components/aos/app-shell.tsx [Server Component]
|
|
||||||
#26 28.93 ./src/app/page.tsx [Server Component]
|
|
||||||
#26 28.93
|
|
||||||
#26 28.93 Client Component SSR:
|
|
||||||
#26 28.93 ./src/components/aos/fuse-cta.tsx [Client Component SSR]
|
|
||||||
#26 28.93 ./src/components/aos/views/recurring.tsx [Client Component SSR]
|
|
||||||
#26 28.93 ./src/components/aos/app-shell.tsx [Client Component SSR]
|
|
||||||
#26 28.93 ./src/components/aos/app-shell.tsx [Server Component]
|
|
||||||
#26 28.93 ./src/app/page.tsx [Server Component]
|
|
||||||
#26 28.93
|
|
||||||
#26 28.93
|
|
||||||
#26 28.93 ./src/components/aos/fuse-cta.tsx:3:1
|
|
||||||
#26 28.93 Export default doesn't exist in target module
|
|
||||||
#26 28.93 [0m [90m 1 |[39m [32m'use client'[39m
|
|
||||||
#26 28.93 [90m 2 |[39m
|
|
||||||
#26 28.93 [31m[1m>[22m[39m[90m 3 |[39m [36mimport[39m [33mFuseButton[39m [36mfrom[39m [32m'@/components/FuseButton'[39m
|
|
||||||
#26 28.93 [90m |[39m [31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m[31m[1m^[22m[39m
|
|
||||||
#26 28.93 [90m 4 |[39m [36mimport[39m { useState } [36mfrom[39m [32m'react'[39m
|
|
||||||
#26 28.93 [90m 5 |[39m [36mimport[39m { toast } [36mfrom[39m [32m'sonner'[39m
|
|
||||||
#26 28.93 [90m 6 |[39m [36mimport[39m { [33mLoader2[39m } [36mfrom[39m [32m'lucide-react'[39m[0m
|
|
||||||
#26 28.93
|
|
||||||
#26 28.93 The export default was not found in module [project]/src/components/FuseButton.tsx [app-ssr] (ecmascript).
|
|
||||||
#26 28.93 Did you mean to import FuseButton?
|
|
||||||
#26 28.93 All exports of the module are statically known (It doesn't have dynamic exports). So it's known statically that the requested export doesn't exist.
|
|
||||||
#26 28.93
|
|
||||||
#26 28.93 Import traces:
|
|
||||||
#26 28.93 App Route:
|
|
||||||
#26 28.93 ./src/components/aos/fuse-cta.tsx
|
|
||||||
#26 28.93 ./src/lib/storage.ts
|
|
||||||
#26 28.93 ./src/app/api/aos/belege/upload/route.ts
|
|
||||||
#26 28.93
|
|
||||||
#26 28.93 Client Component Browser:
|
|
||||||
#26 28.93 ./src/components/aos/fuse-cta.tsx [Client Component Browser]
|
|
||||||
#26 28.93 ./src/components/aos/views/recurring.tsx [Client Component Browser]
|
|
||||||
#26 28.93 ./src/components/aos/app-shell.tsx [Client Component Browser]
|
|
||||||
#26 28.93 ./src/components/aos/app-shell.tsx [Server Component]
|
|
||||||
#26 28.93 ./src/app/page.tsx [Server Component]
|
|
||||||
#26 28.93
|
|
||||||
#26 28.93 Client Component SSR:
|
|
||||||
#26 28.93 ./src/components/aos/fuse-cta.tsx [Client Component SSR]
|
|
||||||
#26 28.93 ./src/components/aos/views/recurring.tsx [Client Component SSR]
|
|
||||||
#26 28.93 ./src/components/aos/app-shell.tsx [Client Component SSR]
|
|
||||||
#26 28.93 ./src/components/aos/app-shell.tsx [Server Component]
|
|
||||||
#26 28.93 ./src/app/page.tsx [Server Component]
|
|
||||||
#26 28.93
|
|
||||||
#26 28.93
|
|
||||||
#26 28.93 at <unknown> (./src/components/aos/fuse-cta.tsx:3:1)
|
|
||||||
#26 28.93 at <unknown> (./src/components/aos/fuse-cta.tsx:3:1)
|
|
||||||
#26 29.12 error: script "build" exited with code 1
|
|
||||||
#26 ERROR: process "bun run build" did not complete successfully: exit code: 1
|
|
||||||
------
|
|
||||||
> bun run build:
|
|
||||||
28.93 ./src/components/aos/fuse-cta.tsx [Client Component SSR]
|
|
||||||
28.93 ./src/components/aos/views/recurring.tsx [Client Component SSR]
|
|
||||||
28.93 ./src/components/aos/app-shell.tsx [Client Component SSR]
|
|
||||||
28.93 ./src/components/aos/app-shell.tsx [Server Component]
|
|
||||||
28.93 ./src/app/page.tsx [Server Component]
|
|
||||||
28.93
|
|
||||||
28.93
|
|
||||||
28.93 at <unknown> (./src/components/aos/fuse-cta.tsx:3:1)
|
|
||||||
28.93 at <unknown> (./src/components/aos/fuse-cta.tsx:3:1)
|
|
||||||
29.12 error: script "build" exited with code 1
|
|
||||||
------
|
|
||||||
ERROR: failed to build: failed to solve: process "bun run build" did not complete successfully: exit code: 1
|
|
||||||
❌ Railpack build failed
|
|
||||||
railpack-dfm-aos-lgbcnc-t6ahqz removed
|
|
||||||
Error occurred ❌, check the logs for details.
|
|
||||||
@@ -1,483 +0,0 @@
|
|||||||
Initializing deployment
|
|
||||||
Cloning Repo github.com/cetinmustafa83/aos.git to /etc/dokploy/applications/dfm-aos-lgbcnc/code: ✅
|
|
||||||
Cloning into '/etc/dokploy/applications/dfm-aos-lgbcnc/code'...
|
|
||||||
remote: Enumerating objects: 1876, done.
|
|
||||||
remote: Counting objects: 0% (1/1876)
remote: Counting objects: 1% (19/1876)
remote: Counting objects: 2% (38/1876)
remote: Counting objects: 3% (57/1876)
remote: Counting objects: 4% (76/1876)
remote: Counting objects: 5% (94/1876)
remote: Counting objects: 6% (113/1876)
remote: Counting objects: 7% (132/1876)
remote: Counting objects: 8% (151/1876)
remote: Counting objects: 9% (169/1876)
remote: Counting objects: 10% (188/1876)
remote: Counting objects: 11% (207/1876)
remote: Counting objects: 12% (226/1876)
remote: Counting objects: 13% (244/1876)
remote: Counting objects: 14% (263/1876)
remote: Counting objects: 15% (282/1876)
remote: Counting objects: 16% (301/1876)
remote: Counting objects: 17% (319/1876)
remote: Counting objects: 18% (338/1876)
remote: Counting objects: 19% (357/1876)
remote: Counting objects: 20% (376/1876)
remote: Counting objects: 21% (394/1876)
remote: Counting objects: 22% (413/1876)
remote: Counting objects: 23% (432/1876)
remote: Counting objects: 24% (451/1876)
remote: Counting objects: 25% (469/1876)
remote: Counting objects: 26% (488/1876)
remote: Counting objects: 27% (507/1876)
remote: Counting objects: 28% (526/1876)
remote: Counting objects: 29% (545/1876)
remote: Counting objects: 30% (563/1876)
remote: Counting objects: 31% (582/1876)
remote: Counting objects: 32% (601/1876)
remote: Counting objects: 33% (620/1876)
remote: Counting objects: 34% (638/1876)
remote: Counting objects: 35% (657/1876)
remote: Counting objects: 36% (676/1876)
remote: Counting objects: 37% (695/1876)
remote: Counting objects: 38% (713/1876)
remote: Counting objects: 39% (732/1876)
remote: Counting objects: 40% (751/1876)
remote: Counting objects: 41% (770/1876)
remote: Counting objects: 42% (788/1876)
remote: Counting objects: 43% (807/1876)
remote: Counting objects: 44% (826/1876)
remote: Counting objects: 45% (845/1876)
remote: Counting objects: 46% (863/1876)
remote: Counting objects: 47% (882/1876)
remote: Counting objects: 48% (901/1876)
remote: Counting objects: 49% (920/1876)
remote: Counting objects: 50% (938/1876)
remote: Counting objects: 51% (957/1876)
remote: Counting objects: 52% (976/1876)
remote: Counting objects: 53% (995/1876)
remote: Counting objects: 54% (1014/1876)
remote: Counting objects: 55% (1032/1876)
remote: Counting objects: 56% (1051/1876)
remote: Counting objects: 57% (1070/1876)
remote: Counting objects: 58% (1089/1876)
remote: Counting objects: 59% (1107/1876)
remote: Counting objects: 60% (1126/1876)
remote: Counting objects: 61% (1145/1876)
remote: Counting objects: 62% (1164/1876)
remote: Counting objects: 63% (1182/1876)
remote: Counting objects: 64% (1201/1876)
remote: Counting objects: 65% (1220/1876)
remote: Counting objects: 66% (1239/1876)
remote: Counting objects: 67% (1257/1876)
remote: Counting objects: 68% (1276/1876)
remote: Counting objects: 69% (1295/1876)
remote: Counting objects: 70% (1314/1876)
remote: Counting objects: 71% (1332/1876)
remote: Counting objects: 72% (1351/1876)
remote: Counting objects: 73% (1370/1876)
remote: Counting objects: 74% (1389/1876)
remote: Counting objects: 75% (1407/1876)
remote: Counting objects: 76% (1426/1876)
remote: Counting objects: 77% (1445/1876)
remote: Counting objects: 78% (1464/1876)
remote: Counting objects: 79% (1483/1876)
remote: Counting objects: 80% (1501/1876)
remote: Counting objects: 81% (1520/1876)
remote: Counting objects: 82% (1539/1876)
remote: Counting objects: 83% (1558/1876)
remote: Counting objects: 84% (1576/1876)
remote: Counting objects: 85% (1595/1876)
remote: Counting objects: 86% (1614/1876)
remote: Counting objects: 87% (1633/1876)
remote: Counting objects: 88% (1651/1876)
remote: Counting objects: 89% (1670/1876)
remote: Counting objects: 90% (1689/1876)
remote: Counting objects: 91% (1708/1876)
remote: Counting objects: 92% (1726/1876)
remote: Counting objects: 93% (1745/1876)
remote: Counting objects: 94% (1764/1876)
remote: Counting objects: 95% (1783/1876)
remote: Counting objects: 96% (1801/1876)
remote: Counting objects: 97% (1820/1876)
remote: Counting objects: 98% (1839/1876)
remote: CouLine truncated
|
|
||||||
remote: Compressing objects: 0% (1/1405)
remote: Compressing objects: 1% (15/1405)
remote: Compressing objects: 2% (29/1405)
remote: Compressing objects: 3% (43/1405)
remote: Compressing objects: 4% (57/1405)
remote: Compressing objects: 5% (71/1405)
remote: Compressing objects: 6% (85/1405)
remote: Compressing objects: 7% (99/1405)
remote: Compressing objects: 8% (113/1405)
remote: Compressing objects: 9% (127/1405)
remote: Compressing objects: 10% (141/1405)
remote: Compressing objects: 11% (155/1405)
remote: Compressing objects: 12% (169/1405)
remote: Compressing objects: 13% (183/1405)
remote: Compressing objects: 14% (197/1405)
remote: Compressing objects: 15% (211/1405)
remote: Compressing objects: 16% (225/1405)
remote: Compressing objects: 17% (239/1405)
remote: Compressing objects: 18% (253/1405)
remote: Compressing objects: 19% (267/1405)
remote: Compressing objects: 20% (281/1405)
remote: Compressing objects: 21% (296/1405)
remote: Compressing objects: 22% (310/1405)
remote: Compressing objects: 23% (324/1405)
remote: Compressing objects: 24% (338/1405)
remote: Compressing objects: 25% (352/1405)
remote: Compressing objects: 26% (366/1405)
remote: Compressing objects: 27% (380/1405)
remote: Compressing objects: 28% (394/1405)
remote: Compressing objects: 29% (408/1405)
remote: Compressing objects: 30% (422/1405)
remote: Compressing objects: 31% (436/1405)
remote: Compressing objects: 32% (450/1405)
remote: Compressing objects: 33% (464/1405)
remote: Compressing objects: 34% (478/1405)
remote: Compressing objects: 35% (492/1405)
remote: Compressing objects: 36% (506/1405)
remote: Compressing objects: 37% (520/1405)
remote: Compressing objects: 38% (534/1405)
remote: Compressing objects: 39% (548/1405)
remote: Compressing objects: 40% (562/1405)
remote: Compressing objects: 41% (577/1405)
remote: Compressing objects: 42% (591/1405)
remote: Compressing objects: 43% (605/1405)
remote: Compressing objects: 44% (619/1405)
remote: Compressing objects: 45% (633/1405)
remote: Compressing objects: 46% (647/1405)
remote: Compressing objects: 47% (661/1405)
remote: Compressing objects: 48% (675/1405)
remote: Compressing objects: 49% (689/1405)
remote: Compressing objects: 50% (703/1405)
remote: Compressing objects: 51% (717/1405)
remote: Compressing objects: 52% (731/1405)
remote: Compressing objects: 53% (745/1405)
remote: Compressing objects: 54% (759/1405)
remote: Compressing objects: 55% (773/1405)
remote: Compressing objects: 56% (787/1405)
remote: Compressing objects: 57% (801/1405)
remote: Compressing objects: 58% (815/1405)
remote: Compressing objects: 59% (829/1405)
remote: Compressing objects: 60% (843/1405)
remote: Compressing objects: 61% (858/1405)
remote: Compressing objects: 62% (872/1405)
remote: Compressing objects: 63% (886/1405)
remote: Compressing objects: 64% (900/1405)
remote: Compressing objects: 65% (914/1405)
remote: Compressing objects: 66% (928/1405)
remote: Compressing objects: 67% (942/1405)
remote: Compressing objects: 68% (956/1405)
remote: Compressing objects: 69% (970/1405)
remote: Compressing objects: 70% (984/1405)
remote: Compressing objects: 71% (998/1405)
remote: Compressing objects: 72% (1012/1405)
remote: Compressing objects: 73% (1026/1405)
remote: Compressing objects: 74% (1040/1405)
remote: Compressing objects: 75% (1054/1405)
remote: Compressing objects: 76% (1068/1405)
remote: Compressing objects: 77% (1082/1405)
remote: Compressing objects: 78% (1096/1405)
remote: Compressing objects: 79% (1110/1405)
remote: Compressing objects: 80% (1124/1405)
remote: Compressing objects: 81% (1139/1405)
remote: Compressing objects: 82% (1153/1405)
remote: Compressing objects: 83% (1167/1405)
remote: Compressing objects: 84% (1181/1405)
remote: Compressing objects: 85% (1195/1405)
remote: Compressing objects: 86% (1209/1405)
remote: Compressing objects: 87% (1223/1405)
remote: Compressing objects: 88% (1237/1405)
remote: Compressing objects: 89% (1251/1405)
remote: Compressing objects: 90% (1265/1405)
remote: Compressing objects: 91% (1279/1405)
remote: Compressing objects: 92% (1293/1405)
remote: Compressing objects: 93% (1307/1405)
remoLine truncated
|
|
||||||
Receiving objects: 0% (1/1876)
Receiving objects: 1% (19/1876)
Receiving objects: 2% (38/1876)
Receiving objects: 3% (57/1876)
Receiving objects: 4% (76/1876)
Receiving objects: 5% (94/1876)
Receiving objects: 6% (113/1876), 9.43 MiB | 18.84 MiB/s
Receiving objects: 7% (132/1876), 9.43 MiB | 18.84 MiB/s
Receiving objects: 8% (151/1876), 9.43 MiB | 18.84 MiB/s
Receiving objects: 9% (169/1876), 9.43 MiB | 18.84 MiB/s
Receiving objects: 10% (188/1876), 9.43 MiB | 18.84 MiB/s
Receiving objects: 11% (207/1876), 9.43 MiB | 18.84 MiB/s
Receiving objects: 12% (226/1876), 9.43 MiB | 18.84 MiB/s
Receiving objects: 13% (244/1876), 9.43 MiB | 18.84 MiB/s
Receiving objects: 14% (263/1876), 9.43 MiB | 18.84 MiB/s
Receiving objects: 15% (282/1876), 9.43 MiB | 18.84 MiB/s
Receiving objects: 16% (301/1876), 9.43 MiB | 18.84 MiB/s
Receiving objects: 17% (319/1876), 9.43 MiB | 18.84 MiB/s
Receiving objects: 18% (338/1876), 9.43 MiB | 18.84 MiB/s
Receiving objects: 19% (357/1876), 9.43 MiB | 18.84 MiB/s
Receiving objects: 20% (376/1876), 9.43 MiB | 18.84 MiB/s
Receiving objects: 21% (394/1876), 9.43 MiB | 18.84 MiB/s
Receiving objects: 22% (413/1876), 9.43 MiB | 18.84 MiB/s
Receiving objects: 23% (432/1876), 9.43 MiB | 18.84 MiB/s
Receiving objects: 24% (451/1876), 9.43 MiB | 18.84 MiB/s
Receiving objects: 25% (469/1876), 9.43 MiB | 18.84 MiB/s
Receiving objects: 26% (488/1876), 9.43 MiB | 18.84 MiB/s
Receiving objects: 27% (507/1876), 9.43 MiB | 18.84 MiB/s
Receiving objects: 28% (526/1876), 9.43 MiB | 18.84 MiB/s
Receiving objects: 29% (545/1876), 9.43 MiB | 18.84 MiB/s
Receiving objects: 30% (563/1876), 9.43 MiB | 18.84 MiB/s
Receiving objects: 31% (582/1876), 9.43 MiB | 18.84 MiB/s
Receiving objects: 32% (601/1876), 9.43 MiB | 18.84 MiB/s
Receiving objects: 33% (620/1876), 9.43 MiB | 18.84 MiB/s
Receiving objects: 34% (638/1876), 9.43 MiB | 18.84 MiB/s
Receiving objects: 35% (657/1876), 9.43 MiB | 18.84 MiB/s
Receiving objects: 36% (676/1876), 9.43 MiB | 18.84 MiB/s
Receiving objects: 37% (695/1876), 9.43 MiB | 18.84 MiB/s
Receiving objects: 38% (713/1876), 9.43 MiB | 18.84 MiB/s
Receiving objects: 39% (732/1876), 9.43 MiB | 18.84 MiB/s
Receiving objects: 40% (751/1876), 9.43 MiB | 18.84 MiB/s
Receiving objects: 41% (770/1876), 9.43 MiB | 18.84 MiB/s
Receiving objects: 42% (788/1876), 9.43 MiB | 18.84 MiB/s
Receiving objects: 43% (807/1876), 9.43 MiB | 18.84 MiB/s
Receiving objects: 44% (826/1876), 9.43 MiB | 18.84 MiB/s
Receiving objects: 45% (845/1876), 9.43 MiB | 18.84 MiB/s
Receiving objects: 46% (863/1876), 9.43 MiB | 18.84 MiB/s
Receiving objects: 47% (882/1876), 9.43 MiB | 18.84 MiB/s
Receiving objects: 48% (901/1876), 9.43 MiB | 18.84 MiB/s
Receiving objects: 49% (920/1876), 9.43 MiB | 18.84 MiB/s
Receiving objects: 50% (938/1876), 9.43 MiB | 18.84 MiB/s
Receiving objects: 51% (957/1876), 9.43 MiB | 18.84 MiB/s
Receiving objects: 51% (974/1876), 26.50 MiB | 26.42 MiB/s
Receiving objects: 52% (976/1876), 26.50 MiB | 26.42 MiB/s
Receiving objects: 53% (995/1876), 41.91 MiB | 27.88 MiB/s
Receiving objects: 54% (1014/1876), 41.91 MiB | 27.88 MiB/s
Receiving objects: 55% (1032/1876), 41.91 MiB | 27.88 MiB/s
Receiving objects: 56% (1051/1876), 41.91 MiB | 27.88 MiB/s
Receiving objects: 57% (1070/1876), 41.91 MiB | 27.88 MiB/s
Receiving objects: 58% (1089/1876), 41.91 MiB | 27.88 MiB/s
Receiving objects: 59% (1107/1876), 41.91 MiB | 27.88 MiB/s
Receiving objects: 60% (1126/1876), 41.91 MiB | 27.88 MiB/s
Receiving objects: 61% (1145/1876), 41.91 MiB | 27.88 MiB/s
Receiving objects: 62% (1164/1876), 41.91 MiB | 27.88 MiB/s
Receiving objects: 63% (1182/1876), 41.91 MiB | 27.88 MiB/s
Receiving objects: 64% (1201/1876), 41.91 MiB | 27.88 MiB/s
Receiving objects: 65% (1220/1876), 41.91 MiB | 27.88 MiB/s
Receiving objects: 66% (1239/1876), 41.91 MiB | 27.88 MiB/s
Receiving objects: 67% (1257/1876), 41.91 MiB | 27.88 MiB/s
Receiving objects: 68% (1276/1876), 41.91 MiB | 27.88 MiB/s
Receiving objects: 69% (1295/1876), 41.91 MiB | 27.88 MiB/s
Receiving objects: 70% (1314/1876), 41.91 MiB | 27.88 MiB/s
Receiving objects: 71% (1332/1876), 41.91 MiB | 27.88 MiB/s
Receiving objects: 72% (1351/1876), 41.91 MiB | 27.88 MiB/s
Receiving objects: 73% (1370/1876), 41.91 MiB | 27.88 MiB/s
Receiving objects: 74% (1389/1876), 41.91 MiB | 27.88 MiB/s
Receiving objects: 75% (1407/1876), 41.91 MiB | 27.88 MiB/s
Receiving objects: 76% (1426/1876), 41.91 MiB | 27.88 MiB/s
Receiving objects: 77% (1445/1876), 41.91 MiB | 27.88 MiB/s
Receiving objects: 78% (1464/1876), 41.91 MiB | 27.88 MiB/s
Receiving objects: 79% (1483/1876), 41.91 MiB | 27.88 MiB/s
Receiving objects: 80% (1501/1876), 41.91 MiB | 27.88 MiB/s
Receiving objects: 81% (1520/1876), 41.91 MiB | 27.88 MiB/s
Receiving objects: 82% (1539/1876), 41.91 MiB | 27.88 MiB/s
Receiving objects: 83% (1558/1876), 41.91 MiB | 27.88 MiB/s
Receiving objects: 84% (1576/1876), 41.91 MiB | 27.88 MiB/s
Receiving oLine truncated
|
|
||||||
Receiving objects: 100% (1876/1876), 41.91 MiB | 27.88 MiB/s␍Receiving objects: 100% (1876/1876), 47.76 MiB | 27.79 MiB/s, done.
|
|
||||||
Resolving deltas: 0% (0/320)␍Resolving deltas: 1% (4/320)␍Resolving deltas: 2% (7/320)␍Resolving deltas: 3% (10/320)␍Resolving deltas: 4% (13/320)␍Resolving deltas: 5% (16/320)␍Resolving deltas: 6% (20/320)␍Resolving deltas: 7% (23/320)␍Resolving deltas: 8% (26/320)␍Resolving deltas: 9% (29/320)␍Resolving deltas: 10% (32/320)␍Resolving deltas: 11% (36/320)␍Resolving deltas: 12% (39/320)␍Resolving deltas: 13% (42/320)␍Resolving deltas: 14% (45/320)␍Resolving deltas: 15% (48/320)␍Resolving deltas: 16% (52/320)␍Resolving deltas: 17% (55/320)␍Resolving deltas: 18% (58/320)␍Resolving deltas: 19% (61/320)␍Resolving deltas: 20% (64/320)␍Resolving deltas: 21% (68/320)␍Resolving deltas: 22% (71/320)␍Resolving deltas: 23% (74/320)␍Resolving deltas: 24% (77/320)␍Resolving deltas: 25% (80/320)␍Resolving deltas: 26% (84/320)␍Resolving deltas: 27% (87/320)␍Resolving deltas: 28% (90/320)␍Resolving deltas: 29% (93/320)␍Resolving deltas: 30% (96/320)␍Resolving deltas: 31% (100/320)␍Resolving deltas: 32% (103/320)␍Resolving deltas: 33% (106/320)␍Resolving deltas: 34% (109/320)␍Resolving deltas: 35% (112/320)␍Resolving deltas: 36% (116/320)␍Resolving deltas: 37% (119/320)␍Resolving deltas: 38% (122/320)␍Resolving deltas: 39% (125/320)␍Resolving deltas: 40% (128/320)␍Resolving deltas: 41% (132/320)␍Resolving deltas: 42% (135/320)␍Resolving deltas: 43% (138/320)␍Resolving deltas: 44% (141/320)␍Resolving deltas: 45% (144/320)␍Resolving deltas: 46% (149/320)␍Resolving deltas: 47% (151/320)␍Resolving deltas: 48% (154/320)␍Resolving deltas: 49% (158/320)␍Resolving deltas: 50% (160/320)␍Resolving deltas: 51% (164/320)␍Resolving deltas: 52% (167/320)␍Resolving deltas: 53% (170/320)␍Resolving deltas: 54% (173/320)␍Resolving deltas: 55% (176/320)␍Resolving deltas: 56% (180/320)␍Resolving deltas: 57% (183/320)␍Resolving deltas: 58% (187/320)␍Resolving deltas: 59% (189/320)␍Resolving deltas: 60% (192/320)␍Resolving deltas: 61% (196/320)␍Resolving deltas: 62% (199/320)␍Resolving deltas: 63% (202/320)␍Resolving deltas: 64% (206/320)␍Resolving deltas: 65% (208/320)␍Resolving deltas: 66% (212/320)␍Resolving deltas: 67% (215/320)␍Resolving deltas: 68% (218/320)␍Resolving deltas: 69% (221/320)␍Resolving deltas: 70% (224/320)␍Resolving deltas: 71% (229/320)␍Resolving deltas: 72% (231/320)␍Resolving deltas: 73% (234/320)␍Resolving deltas: 74% (237/320)␍Resolving deltas: 75% (241/320)␍Resolving deltas: 76% (244/320)␍Resolving deltas: 77% (247/320)␍Resolving deltas: 78% (250/320)␍Resolving deltas: 79% (253/320)␍Resolving deltas: 80% (256/320)␍Resolving deltas: 81% (260/320)␍Resolving deltas: 82% (263/320)␍Resolving deltas: 83% (266/320)␍Resolving deltas: 84% (269/320)␍Resolving deltas: 85% (272/320)␍Resolving deltas: 86% (276/320)␍Resolving deltas: 87% (279/320)␍Resolving deltas: 88% (282/320)␍Resolving deltas: 89% (285/320)␍Resolving deltas: 90% (288/320)␍Resolving deltas: 91% (292/320)␍Resolving deltas: 92% (295/320)␍Resolving deltas: 93% (298/320)␍Resolving deltas: 94% (302/320)␍Resolving deltas: 95% (304/320)␍Resolving deltas: 96% (308/320)␍Resolving deltas: 97% (311/320)␍Resolving deltas: 98% (314/320)␍Resolving deltas: 99% (317/320)␍Resolving deltas: 100% (320/320)␍Resolving deltas: 100% (320/320), done.
|
|
||||||
> Installing railpack, please wait…
|
|
||||||
____ _ _ _
|
|
||||||
| _ \ __ _(_) |_ __ __ _ ___| | __
|
|
||||||
| |_) / _` | | | '_ \ / _` |/ __| |/ /
|
|
||||||
| _ < (_| | | | |_) | (_| | (__| <
|
|
||||||
|_| \_\__,_|_|_| .__/ \__,_|\___|_|\_\
|
|
||||||
|_|
|
|
||||||
Railpack is now installed!
|
|
||||||
Run 'railpack --help' to get started
|
|
||||||
railpack-dfm-aos-lgbcnc-fk4Q2Q
|
|
||||||
Preparing Railpack build plan...
|
|
||||||
╭─────────────────╮
|
|
||||||
│ Railpack 0.15.4 │
|
|
||||||
╰─────────────────╯
|
|
||||||
↳ Found .dockerignore file, applying filters
|
|
||||||
↳ Detected Node
|
|
||||||
↳ Using bun package manager
|
|
||||||
Packages
|
|
||||||
──────────
|
|
||||||
bun │ 1.4.4 │ railpack default (latest)
|
|
||||||
node │ 26.12.1 │ railpack default (latest)
|
|
||||||
Steps
|
|
||||||
──────────
|
|
||||||
▸ install
|
|
||||||
$ bun install --frozen-lockfile
|
|
||||||
▸ build
|
|
||||||
$ bun run build
|
|
||||||
Deploy
|
|
||||||
──────────
|
|
||||||
$ bun run start
|
|
||||||
✅ Railpack prepare completed.
|
|
||||||
Building with Railpack frontend...
|
|
||||||
#0 building with "railpack-dfm-aos-lgbcnc-fk4Q2Q" instance using docker-container driver
|
|
||||||
#1 [internal] booting buildkit
|
|
||||||
#1 pulling image moby/buildkit:buildx-stable-1
|
|
||||||
#1 pulling image moby/buildkit:buildx-stable-1 1.1s done
|
|
||||||
#1 creating container buildx_buildkit_railpack-dfm-aos-lgbcnc-fk4q2q0
|
|
||||||
#1 creating container buildx_buildkit_railpack-dfm-aos-lgbcnc-fk4q2q0 0.8s done
|
|
||||||
#1 DONE 1.9s
|
|
||||||
#2 resolve image config for docker-image://ghcr.io/railwayapp/railpack-frontend:v0.15.4
|
|
||||||
#2 DONE 1.3s
|
|
||||||
#3 docker-image://ghcr.io/railwayapp/railpack-frontend:v0.15.4@sha256:7e0535e519d9d00793d0bb4e652be5d48373ab5e0c7d9b90ef6bc40147290ff7
|
|
||||||
#3 resolve ghcr.io/railwayapp/railpack-frontend:v0.15.4@sha256:7e0535e519d9d00793d0bb4e652be5d48373ab5e0c7d9b90ef6bc40147290ff7 0.0s done
|
|
||||||
#3 sha256:76fdf18f436616aff2234f2d325d888d31af103f333a8f491d539dce0106e849 0B / 7.90MB 0.2s
|
|
||||||
#3 sha256:1074353eec0db2c1d81d5af2671e56e00cf5738486f5762609ea33d606f88612 0B / 3.86MB 0.2s
|
|
||||||
#3 sha256:76fdf18f436616aff2234f2d325d888d31af103f333a8f491d539dce0106e849 7.90MB / 7.90MB 0.5s
|
|
||||||
#3 sha256:76fdf18f436616aff2234f2d325d888d31af103f333a8f491d539dce0106e849 7.90MB / 7.90MB 0.5s done
|
|
||||||
#3 sha256:1074353eec0db2c1d81d5af2671e56e00cf5738486f5762609ea33d606f88612 3.86MB / 3.86MB 0.7s done
|
|
||||||
#3 extracting sha256:1074353eec0db2c1d81d5af2671e56e00cf5738486f5762609ea33d606f88612 0.1s done
|
|
||||||
#3 DONE 0.9s
|
|
||||||
#3 docker-image://ghcr.io/railwayapp/railpack-frontend:v0.15.4@sha256:7e0535e519d9d00793d0bb4e652be5d48373ab5e0c7d9b90ef6bc40147290ff7
|
|
||||||
#3 extracting sha256:76fdf18f436616aff2234f2d325d888d31af103f333a8f491d539dce0106e849
|
|
||||||
#3 extracting sha256:76fdf18f436616aff2234f2d325d888d31af103f333a8f491d539dce0106e849 0.2s done
|
|
||||||
#3 DONE 1.1s
|
|
||||||
#4 load build definition from railpack-plan.json
|
|
||||||
#4 transferring dockerfile: 5.06kB done
|
|
||||||
#4 DONE 0.0s
|
|
||||||
#5 [railpack] secrets hash
|
|
||||||
#5 DONE 0.0s
|
|
||||||
#6 loading .
|
|
||||||
#6 DONE 0.0s
|
|
||||||
#7 docker-image://ghcr.io/railwayapp/railpack-builder:latest
|
|
||||||
#7 resolve ghcr.io/railwayapp/railpack-builder:latest
|
|
||||||
#7 resolve ghcr.io/railwayapp/railpack-builder:latest 1.0s done
|
|
||||||
#7 DONE 1.0s
|
|
||||||
#8 docker-image://ghcr.io/railwayapp/railpack-runtime:latest
|
|
||||||
#8 resolve ghcr.io/railwayapp/railpack-runtime:latest
|
|
||||||
#8 ...
|
|
||||||
#5 [railpack] secrets hash
|
|
||||||
#5 DONE 0.0s
|
|
||||||
#8 docker-image://ghcr.io/railwayapp/railpack-runtime:latest
|
|
||||||
#8 resolve ghcr.io/railwayapp/railpack-runtime:latest 1.1s done
|
|
||||||
#8 sha256:75dc09925ca146a3efecc887098f8f1313da0fb1b0c8d36d628b6cae320665ec 0B / 7.39MB 0.2s
|
|
||||||
#8 sha256:ecc510c1e359bdc007b39802570bb7e4dec7d6ebccf357c3201a74299113e05e 0B / 29.84MB 0.2s
|
|
||||||
#8 sha256:ecc510c1e359bdc007b39802570bb7e4dec7d6ebccf357c3201a74299113e05e 4.19MB / 29.84MB 0.3s
|
|
||||||
#8 sha256:75dc09925ca146a3efecc887098f8f1313da0fb1b0c8d36d628b6cae320665ec 1.05MB / 7.39MB 0.5s
|
|
||||||
#8 sha256:ecc510c1e359bdc007b39802570bb7e4dec7d6ebccf357c3201a74299113e05e 10.49MB / 29.84MB 0.5s
|
|
||||||
#8 sha256:75dc09925ca146a3efecc887098f8f1313da0fb1b0c8d36d628b6cae320665ec 3.15MB / 7.39MB 0.6s
|
|
||||||
#8 sha256:ecc510c1e359bdc007b39802570bb7e4dec7d6ebccf357c3201a74299113e05e 13.63MB / 29.84MB 0.6s
|
|
||||||
#8 sha256:75dc09925ca146a3efecc887098f8f1313da0fb1b0c8d36d628b6cae320665ec 7.39MB / 7.39MB 0.8s
|
|
||||||
#8 sha256:75dc09925ca146a3efecc887098f8f1313da0fb1b0c8d36d628b6cae320665ec 7.39MB / 7.39MB 0.8s done
|
|
||||||
#8 sha256:ecc510c1e359bdc007b39802570bb7e4dec7d6ebccf357c3201a74299113e05e 18.87MB / 29.84MB 0.8s
|
|
||||||
#8 sha256:ecc510c1e359bdc007b39802570bb7e4dec7d6ebccf357c3201a74299113e05e 20.97MB / 29.84MB 0.9s
|
|
||||||
#8 ...
|
|
||||||
#9 [railpack] loading secrets
|
|
||||||
#9 resolve docker.io/library/alpine:latest 1.4s done
|
|
||||||
#9 sha256:7b229517ed222597277036d94892173207d01a731ab3a88eeb1de2e963a2c788 3.85MB / 3.85MB 0.4s done
|
|
||||||
#9 extracting sha256:7b229517ed222597277036d94892173207d01a731ab3a88eeb1de2e963a2c788 0.3s done
|
|
||||||
#9 DONE 2.2s
|
|
||||||
#8 docker-image://ghcr.io/railwayapp/railpack-runtime:latest
|
|
||||||
#8 sha256:ecc510c1e359bdc007b39802570bb7e4dec7d6ebccf357c3201a74299113e05e 29.84MB / 29.84MB 1.1s
|
|
||||||
#8 ...
|
|
||||||
#10 [railpack] copy secrets hash
|
|
||||||
#10 DONE 0.3s
|
|
||||||
#8 docker-image://ghcr.io/railwayapp/railpack-runtime:latest
|
|
||||||
#8 sha256:ecc510c1e359bdc007b39802570bb7e4dec7d6ebccf357c3201a74299113e05e 29.84MB / 29.84MB 1.3s done
|
|
||||||
#8 extracting sha256:ecc510c1e359bdc007b39802570bb7e4dec7d6ebccf357c3201a74299113e05e
|
|
||||||
#8 ...
|
|
||||||
#11 [railpack] hash used secrets
|
|
||||||
#11 DONE 0.4s
|
|
||||||
#12 [railpack] copy used secrets hash
|
|
||||||
#12 DONE 0.0s
|
|
||||||
#7 docker-image://ghcr.io/railwayapp/railpack-builder:latest
|
|
||||||
#7 sha256:193926ad1d06489b7487e8ac4ae2d0874e6ff05cf65d874d2af508830fc03def 119B / 119B 0.5s done
|
|
||||||
#7 sha256:df614908d6aba31e983953b17fd48496d27425529b3947c3d5583c4cc9c15c9a 868.40kB / 868.40kB 0.5s done
|
|
||||||
#7 sha256:604add184d03d4cf6e2ff1c4b9013b265eb9c11570afe28ce8f9dc417b98ea3f 6.29MB / 237.08MB 1.4s
|
|
||||||
#7 sha256:08a1e03b3da5bb4a1059032dca3216f33ddfc4a48a45db88921f5bb2e9a8fa2d 41.94MB / 53.72MB 1.4s
|
|
||||||
#7 sha256:4f4fb700ef54461cfa02571ae0db9a0dc1e0cdb5577484a6d75e68dc38e8acc1 32B / 32B 0.2s done
|
|
||||||
#7 sha256:4dc3950125ebc9ed195e1101fc6c02e2fce113ba0f53bfb05b2cdf58747df9af 28.51MB / 67.81MB 1.1s
|
|
||||||
#7 sha256:62fe2e747f69f2f414c7e9eb1553155cf0a658398f0462557f458821dce2b29d 1.05MB / 25.64MB 0.6s
|
|
||||||
#7 sha256:08a1e03b3da5bb4a1059032dca3216f33ddfc4a48a45db88921f5bb2e9a8fa2d 45.63MB / 53.72MB 1.5s
|
|
||||||
#7 sha256:4dc3950125ebc9ed195e1101fc6c02e2fce113ba0f53bfb05b2cdf58747df9af 32.51MB / 67.81MB 1.2s
|
|
||||||
#7 sha256:08a1e03b3da5bb4a1059032dca3216f33ddfc4a48a45db88921f5bb2e9a8fa2d 52.43MB / 53.72MB 1.7s
|
|
||||||
#7 sha256:62fe2e747f69f2f414c7e9eb1553155cf0a658398f0462557f458821dce2b29d 4.19MB / 25.64MB 0.9s
|
|
||||||
#7 sha256:08a1e03b3da5bb4a1059032dca3216f33ddfc4a48a45db88921f5bb2e9a8fa2d 53.72MB / 53.72MB 1.8s done
|
|
||||||
#7 sha256:4dc3950125ebc9ed195e1101fc6c02e2fce113ba0f53bfb05b2cdf58747df9af 41.94MB / 67.81MB 1.4s
|
|
||||||
#7 sha256:4dc3950125ebc9ed195e1101fc6c02e2fce113ba0f53bfb05b2cdf58747df9af 47.19MB / 67.81MB 1.5s
|
|
||||||
#7 sha256:62fe2e747f69f2f414c7e9eb1553155cf0a658398f0462557f458821dce2b29d 7.34MB / 25.64MB 1.2s
|
|
||||||
#7 sha256:4dc3950125ebc9ed195e1101fc6c02e2fce113ba0f53bfb05b2cdf58747df9af 52.43MB / 67.81MB 1.7s
|
|
||||||
#7 sha256:4846f29007305297af653c57bf9b60ba8f676a38695c68d98460063442581671 0B / 49.39MB 0.2s
|
|
||||||
#7 sha256:4dc3950125ebc9ed195e1101fc6c02e2fce113ba0f53bfb05b2cdf58747df9af 57.67MB / 67.81MB 1.8s
|
|
||||||
#7 sha256:62fe2e747f69f2f414c7e9eb1553155cf0a658398f0462557f458821dce2b29d 9.44MB / 25.64MB 1.4s
|
|
||||||
#7 sha256:62fe2e747f69f2f414c7e9eb1553155cf0a658398f0462557f458821dce2b29d 11.53MB / 25.64MB 1.5s
|
|
||||||
#7 sha256:4846f29007305297af653c57bf9b60ba8f676a38695c68d98460063442581671 8.39MB / 49.39MB 0.5s
|
|
||||||
#7 sha256:4dc3950125ebc9ed195e1101fc6c02e2fce113ba0f53bfb05b2cdf58747df9af 65.01MB / 67.81MB 2.1s
|
|
||||||
#7 sha256:62fe2e747f69f2f414c7e9eb1553155cf0a658398f0462557f458821dce2b29d 14.68MB / 25.64MB 1.7s
|
|
||||||
#7 sha256:4846f29007305297af653c57bf9b60ba8f676a38695c68d98460063442581671 16.78MB / 49.39MB 0.6s
|
|
||||||
#7 ...
|
|
||||||
#6 loading .
|
|
||||||
#6 transferring context: 128.38MB 3.2s done
|
|
||||||
#6 DONE 3.3s
|
|
||||||
#7 docker-image://ghcr.io/railwayapp/railpack-builder:latest
|
|
||||||
#7 sha256:62fe2e747f69f2f414c7e9eb1553155cf0a658398f0462557f458821dce2b29d 17.83MB / 25.64MB 1.8s
|
|
||||||
#7 sha256:4846f29007305297af653c57bf9b60ba8f676a38695c68d98460063442581671 23.07MB / 49.39MB 0.8s
|
|
||||||
#7 sha256:4dc3950125ebc9ed195e1101fc6c02e2fce113ba0f53bfb05b2cdf58747df9af 67.81MB / 67.81MB 2.4s done
|
|
||||||
#7 sha256:62fe2e747f69f2f414c7e9eb1553155cf0a658398f0462557f458821dce2b29d 22.02MB / 25.64MB 2.0s
|
|
||||||
#7 sha256:4846f29007305297af653c57bf9b60ba8f676a38695c68d98460063442581671 27.26MB / 49.39MB 0.9s
|
|
||||||
#7 sha256:62fe2e747f69f2f414c7e9eb1553155cf0a658398f0462557f458821dce2b29d 25.64MB / 25.64MB 2.1s done
|
|
||||||
#7 sha256:4846f29007305297af653c57bf9b60ba8f676a38695c68d98460063442581671 34.60MB / 49.39MB 1.1s
|
|
||||||
#7 sha256:4846f29007305297af653c57bf9b60ba8f676a38695c68d98460063442581671 41.94MB / 49.39MB 1.2s
|
|
||||||
#7 sha256:4846f29007305297af653c57bf9b60ba8f676a38695c68d98460063442581671 46.14MB / 49.39MB 1.4s
|
|
||||||
#7 ...
|
|
||||||
#8 docker-image://ghcr.io/railwayapp/railpack-runtime:latest
|
|
||||||
#8 extracting sha256:ecc510c1e359bdc007b39802570bb7e4dec7d6ebccf357c3201a74299113e05e 2.3s done
|
|
||||||
#8 extracting sha256:75dc09925ca146a3efecc887098f8f1313da0fb1b0c8d36d628b6cae320665ec 0.3s done
|
|
||||||
#8 DONE 5.1s
|
|
||||||
#7 docker-image://ghcr.io/railwayapp/railpack-builder:latest
|
|
||||||
#7 sha256:4846f29007305297af653c57bf9b60ba8f676a38695c68d98460063442581671 49.39MB / 49.39MB 1.5s done
|
|
||||||
#7 extracting sha256:4846f29007305297af653c57bf9b60ba8f676a38695c68d98460063442581671
|
|
||||||
#7 extracting sha256:4846f29007305297af653c57bf9b60ba8f676a38695c68d98460063442581671 1.5s done
|
|
||||||
#7 extracting sha256:62fe2e747f69f2f414c7e9eb1553155cf0a658398f0462557f458821dce2b29d
|
|
||||||
#7 extracting sha256:62fe2e747f69f2f414c7e9eb1553155cf0a658398f0462557f458821dce2b29d 1.0s done
|
|
||||||
#7 extracting sha256:4dc3950125ebc9ed195e1101fc6c02e2fce113ba0f53bfb05b2cdf58747df9af
|
|
||||||
#7 sha256:604add184d03d4cf6e2ff1c4b9013b265eb9c11570afe28ce8f9dc417b98ea3f 8.39MB / 237.08MB 6.5s
|
|
||||||
#7 extracting sha256:4dc3950125ebc9ed195e1101fc6c02e2fce113ba0f53bfb05b2cdf58747df9af 2.6s done
|
|
||||||
#7 extracting sha256:4f4fb700ef54461cfa02571ae0db9a0dc1e0cdb5577484a6d75e68dc38e8acc1 done
|
|
||||||
#7 extracting sha256:08a1e03b3da5bb4a1059032dca3216f33ddfc4a48a45db88921f5bb2e9a8fa2d
|
|
||||||
#7 extracting sha256:08a1e03b3da5bb4a1059032dca3216f33ddfc4a48a45db88921f5bb2e9a8fa2d 1.3s done
|
|
||||||
#7 sha256:604add184d03d4cf6e2ff1c4b9013b265eb9c11570afe28ce8f9dc417b98ea3f 9.44MB / 237.08MB 11.6s
|
|
||||||
#7 ...
|
|
||||||
#13 install apt packages: libatomic1
|
|
||||||
#13 0.202 Get:1 http://deb.debian.org/debian trixie InRelease [140 kB]
|
|
||||||
#13 0.277 Get:2 http://deb.debian.org/debian trixie-updates InRelease [47.3 kB]
|
|
||||||
#13 0.304 Get:3 http://deb.debian.org/debian-security trixie-security InRelease [43.4 kB]
|
|
||||||
#13 0.332 Get:4 http://deb.debian.org/debian trixie/main amd64 Packages [9678 kB]
|
|
||||||
#13 0.502 Get:5 http://deb.debian.org/debian trixie-updates/main amd64 Packages [720 B]
|
|
||||||
#13 0.530 Get:6 http://deb.debian.org/debian-security trixie-security/main amd64 Packages [270 kB]
|
|
||||||
#13 1.907 Fetched 10.2 MB in 2s (5691 kB/s)
|
|
||||||
#13 1.907 Reading package lists...
|
|
||||||
#13 2.959 Reading package lists...
|
|
||||||
#13 4.052 Building dependency tree...
|
|
||||||
#13 4.297 Reading state information...
|
|
||||||
#13 4.774 The following NEW packages will be installed:
|
|
||||||
#13 4.776 libatomic1
|
|
||||||
#13 4.901 0 upgraded, 1 newly installed, 0 to remove and 3 not upgraded.
|
|
||||||
#13 4.901 Need to get 9308 B of archives.
|
|
||||||
#13 4.901 After this operation, 46.1 kB of additional disk space will be used.
|
|
||||||
#13 4.901 Get:1 http://deb.debian.org/debian trixie/main amd64 libatomic1 amd64 14.2.0-19 [9308 B]
|
|
||||||
#13 5.095 debconf: unable to initialize frontend: Dialog
|
|
||||||
#13 5.095 debconf: (TERM is not set, so the dialog frontend is not usable.)
|
|
||||||
#13 5.095 debconf: falling back to frontend: Readline
|
|
||||||
#13 5.095 debconf: unable to initialize frontend: Readline
|
|
||||||
#13 5.095 debconf: (Can't locate Term/ReadLine.pm in @INC (you may need to install the Term::ReadLine module) (@INC entries checked: /etc/perl /usr/local/lib/x86_64-linux-gnu/perl/5.40.1 /usr/local/share/perl/5.40.1 /usr/lib/x86_64-linux-gnu/perl5/5.40 /usr/share/perl5 /usr/lib/x86_64-linux-gnu/perl-base /usr/lib/x86_64-linux-gnu/perl/5.40 /usr/share/perl/5.40 /usr/local/lib/site_perl) at /usr/share/perl5/Debconf/FrontEnd/Readline.pm line 8, <STDIN> line 1.)
|
|
||||||
#13 5.095 debconf: falling back to frontend: Teletype
|
|
||||||
#13 5.101 debconf: unable to initialize frontend: Teletype
|
|
||||||
#13 5.101 debconf: (This frontend requires a controlling tty.)
|
|
||||||
#13 5.101 debconf: falling back to frontend: Noninteractive
|
|
||||||
#13 6.113 Fetched 9308 B in 0s (91.1 kB/s)
|
|
||||||
#13 6.163 Selecting previously unselected package libatomic1:amd64.
|
|
||||||
#13 6.163 (Reading database ... ␍(Reading database ... 5%␍(Reading database ... 10%␍(Reading database ... 15%␍(Reading database ... 20%␍(Reading database ... 25%␍(Reading database ... 30%␍(Reading database ... 35%␍(Reading database ... 40%␍(Reading database ... 45%␍(Reading database ... 50%␍(Reading database ... 55%␍(Reading database ... 60%␍(Reading database ... 65%␍(Reading database ... 70%␍(Reading database ... 75%␍(Reading database ... 80%␍(Reading database ... 85%␍(Reading database ... 90%␍(Reading database ... 95%␍(Reading database ... 100%␍(Reading database ... 6228 files and directories currently installed.)
|
|
||||||
#13 6.171 Preparing to unpack .../libatomic1_14.2.0-19_amd64.deb ...
|
|
||||||
#13 6.174 Unpacking libatomic1:amd64 (14.2.0-19) ...
|
|
||||||
#13 6.211 Setting up libatomic1:amd64 (14.2.0-19) ...
|
|
||||||
#13 6.217 Processing triggers for libc-bin (2.41-12+deb13u4) ...
|
|
||||||
#13 DONE 8.2s
|
|
||||||
#7 docker-image://ghcr.io/railwayapp/railpack-builder:latest
|
|
||||||
#7 sha256:604add184d03d4cf6e2ff1c4b9013b265eb9c11570afe28ce8f9dc417b98ea3f 28.31MB / 237.08MB 16.2s
|
|
||||||
#7 sha256:604add184d03d4cf6e2ff1c4b9013b265eb9c11570afe28ce8f9dc417b98ea3f 41.94MB / 237.08MB 16.5s
|
|
||||||
#7 sha256:604add184d03d4cf6e2ff1c4b9013b265eb9c11570afe28ce8f9dc417b98ea3f 55.57MB / 237.08MB 17.1s
|
|
||||||
#7 sha256:604add184d03d4cf6e2ff1c4b9013b265eb9c11570afe28ce8f9dc417b98ea3f 65.01MB / 237.08MB 22.2s
|
|
||||||
#7 sha256:604add184d03d4cf6e2ff1c4b9013b265eb9c11570afe28ce8f9dc417b98ea3f 66.06MB / 237.08MB 27.3s
|
|
||||||
#7 sha256:604add184d03d4cf6e2ff1c4b9013b265eb9c11570afe28ce8f9dc417b98ea3f 68.16MB / 237.08MB 32.4s
|
|
||||||
#7 sha256:604add184d03d4cf6e2ff1c4b9013b265eb9c11570afe28ce8f9dc417b98ea3f 69.21MB / 237.08MB 37.5s
|
|
||||||
#7 sha256:604add184d03d4cf6e2ff1c4b9013b265eb9c11570afe28ce8f9dc417b98ea3f 71.30MB / 237.08MB 42.6s
|
|
||||||
#7 sha256:604add184d03d4cf6e2ff1c4b9013b265eb9c11570afe28ce8f9dc417b98ea3f 72.35MB / 237.08MB 47.7s
|
|
||||||
#7 sha256:604add184d03d4cf6e2ff1c4b9013b265eb9c11570afe28ce8f9dc417b98ea3f 85.98MB / 237.08MB 50.4s
|
|
||||||
#7 sha256:604add184d03d4cf6e2ff1c4b9013b265eb9c11570afe28ce8f9dc417b98ea3f 94.37MB / 237.08MB 55.5s
|
|
||||||
#7 sha256:604add184d03d4cf6e2ff1c4b9013b265eb9c11570afe28ce8f9dc417b98ea3f 96.47MB / 237.08MB 60.6s
|
|
||||||
#7 sha256:604add184d03d4cf6e2ff1c4b9013b265eb9c11570afe28ce8f9dc417b98ea3f 97.52MB / 237.08MB 65.7s
|
|
||||||
#7 sha256:604add184d03d4cf6e2ff1c4b9013b265eb9c11570afe28ce8f9dc417b98ea3f 99.61MB / 237.08MB 70.8s
|
|
||||||
#7 sha256:604add184d03d4cf6e2ff1c4b9013b265eb9c11570afe28ce8f9dc417b98ea3f 100.66MB / 237.08MB 75.9s
|
|
||||||
#7 sha256:604add184d03d4cf6e2ff1c4b9013b265eb9c11570afe28ce8f9dc417b98ea3f 101.71MB / 237.08MB 81.0s
|
|
||||||
#7 sha256:604add184d03d4cf6e2ff1c4b9013b265eb9c11570afe28ce8f9dc417b98ea3f 103.81MB / 237.08MB 86.1s
|
|
||||||
#7 sha256:604add184d03d4cf6e2ff1c4b9013b265eb9c11570afe28ce8f9dc417b98ea3f 124.78MB / 237.08MB 87.0s
|
|
||||||
#7 sha256:604add184d03d4cf6e2ff1c4b9013b265eb9c11570afe28ce8f9dc417b98ea3f 137.36MB / 237.08MB 90.6s
|
|
||||||
#7 sha256:604add184d03d4cf6e2ff1c4b9013b265eb9c11570afe28ce8f9dc417b98ea3f 137.36MB / 237.08MB 95.7s
|
|
||||||
#7 sha256:604add184d03d4cf6e2ff1c4b9013b265eb9c11570afe28ce8f9dc417b98ea3f 139.46MB / 237.08MB 100.8s
|
|
||||||
#7 sha256:604add184d03d4cf6e2ff1c4b9013b265eb9c11570afe28ce8f9dc417b98ea3f 140.51MB / 237.08MB 105.9s
|
|
||||||
#7 sha256:604add184d03d4cf6e2ff1c4b9013b265eb9c11570afe28ce8f9dc417b98ea3f 141.56MB / 237.08MB 111.0s
|
|
||||||
#7 sha256:604add184d03d4cf6e2ff1c4b9013b265eb9c11570afe28ce8f9dc417b98ea3f 143.65MB / 237.08MB 116.1s
|
|
||||||
#7 sha256:604add184d03d4cf6e2ff1c4b9013b265eb9c11570afe28ce8f9dc417b98ea3f 145.75MB / 237.08MB 121.2s
|
|
||||||
#7 sha256:604add184d03d4cf6e2ff1c4b9013b265eb9c11570afe28ce8f9dc417b98ea3f 162.53MB / 237.08MB 122.7s
|
|
||||||
#7 sha256:604add184d03d4cf6e2ff1c4b9013b265eb9c11570afe28ce8f9dc417b98ea3f 168.82MB / 237.08MB 127.8s
|
|
||||||
#7 sha256:604add184d03d4cf6e2ff1c4b9013b265eb9c11570afe28ce8f9dc417b98ea3f 169.87MB / 237.08MB 132.9s
|
|
||||||
#7 sha256:604add184d03d4cf6e2ff1c4b9013b265eb9c11570afe28ce8f9dc417b98ea3f 170.92MB / 237.08MB 138.0s
|
|
||||||
#7 sha256:604add184d03d4cf6e2ff1c4b9013b265eb9c11570afe28ce8f9dc417b98ea3f 171.97MB / 237.08MB 143.1s
|
|
||||||
#7 sha256:604add184d03d4cf6e2ff1c4b9013b265eb9c11570afe28ce8f9dc417b98ea3f 174.06MB / 237.08MB 148.2s
|
|
||||||
#7 sha256:604add184d03d4cf6e2ff1c4b9013b265eb9c11570afe28ce8f9dc417b98ea3f 175.11MB / 237.08MB 153.3s
|
|
||||||
#7 sha256:604add184d03d4cf6e2ff1c4b9013b265eb9c11570afe28ce8f9dc417b98ea3f 176.16MB / 237.08MB 158.4s
|
|
||||||
#7 sha256:604add184d03d4cf6e2ff1c4b9013b265eb9c11570afe28ce8f9dc417b98ea3f 177.21MB / 237.08MB 163.5s
|
|
||||||
#7 sha256:604add184d03d4cf6e2ff1c4b9013b265eb9c11570afe28ce8f9dc417b98ea3f 189.79MB / 237.08MB 164.3s
|
|
||||||
#7 sha256:604add184d03d4cf6e2ff1c4b9013b265eb9c11570afe28ce8f9dc417b98ea3f 200.28MB / 237.08MB 169.4s
|
|
||||||
#7 sha256:604add184d03d4cf6e2ff1c4b9013b265eb9c11570afe28ce8f9dc417b98ea3f 202.38MB / 237.08MB 174.5s
|
|
||||||
#7 sha256:604add184d03d4cf6e2ff1c4b9013b265eb9c11570afe28ce8f9dc417b98ea3f 203.42MB / 237.08MB 179.6s
|
|
||||||
#7 sha256:604add184d03d4cf6e2ff1c4b9013b265eb9c11570afe28ce8f9dc417b98ea3f 205.52MB / 237.08MB 184.7s
|
|
||||||
#7 sha256:604add184d03d4cf6e2ff1c4b9013b265eb9c11570afe28ce8f9dc417b98ea3f 207.62MB / 237.08MB 189.8s
|
|
||||||
#7 sha256:604add184d03d4cf6e2ff1c4b9013b265eb9c11570afe28ce8f9dc417b98ea3f 208.67MB / 237.08MB 194.9s
|
|
||||||
#7 sha256:604add184d03d4cf6e2ff1c4b9013b265eb9c11570afe28ce8f9dc417b98ea3f 216.01MB / 237.08MB 200.0s
|
|
||||||
#7 sha256:604add184d03d4cf6e2ff1c4b9013b265eb9c11570afe28ce8f9dc417b98ea3f 219.15MB / 237.08MB 205.1s
|
|
||||||
#7 sha256:604add184d03d4cf6e2ff1c4b9013b265eb9c11570afe28ce8f9dc417b98ea3f 231.74MB / 237.08MB 207.3s
|
|
||||||
#7 sha256:604add184d03d4cf6e2ff1c4b9013b265eb9c11570afe28ce8f9dc417b98ea3f 237.08MB / 237.08MB 207.6s done
|
|
||||||
#7 extracting sha256:604add184d03d4cf6e2ff1c4b9013b265eb9c11570afe28ce8f9dc417b98ea3f
|
|
||||||
#7 extracting sha256:604add184d03d4cf6e2ff1c4b9013b265eb9c11570afe28ce8f9dc417b98ea3f 6.2s done
|
|
||||||
#7 DONE 215.5s
|
|
||||||
#7 docker-image://ghcr.io/railwayapp/railpack-builder:latest
|
|
||||||
#7 extracting sha256:df614908d6aba31e983953b17fd48496d27425529b3947c3d5583c4cc9c15c9a 0.0s done
|
|
||||||
#7 extracting sha256:193926ad1d06489b7487e8ac4ae2d0874e6ff05cf65d874d2af508830fc03def done
|
|
||||||
#7 DONE 215.5s
|
|
||||||
#14 mkdir /etc/mise
|
|
||||||
#14 DONE 1.7s
|
|
||||||
#15 create mise config
|
|
||||||
#15 DONE 0.0s
|
|
||||||
#16 install mise packages: bun, node
|
|
||||||
#16 0.083 mise by @jdx – installing 2 tools
|
|
||||||
#16 3.083 mise ████████░░░░░░░░ 0/2 · 3.0s
|
|
||||||
#16 3.083 bun@1.4.4 downloading 2.7s 28.2/51.8 MB · 11.6 MB/s
|
|
||||||
#16 3.083 node@26.12.1 downloading 2.7s 62.9/62.9 MB · 24.6 MB/s
|
|
||||||
#16 4.964 mise node@26.12.1 v26.12.1
|
|
||||||
#16 5.189 mise node@26.12.1 11.20.0
|
|
||||||
#16 5.226 mise ✓ node@26.12.1 4.8s node-v26.12.1-linux-x64.tar.gz
|
|
||||||
#16 6.083 mise ██████████████░░ 1/2 · 6.0s
|
|
||||||
#16 6.083 bun@1.4.4 extracting 5.7s
|
|
||||||
#16 6.724 mise bun@1.4.4 1.4.4
|
|
||||||
#16 6.751 mise ✓ bun@1.4.4 6.4s bun-linux-x64.zip
|
|
||||||
#16 6.751 mise ████████████████ 2/2 · installed 2 tools in 6.7s
|
|
||||||
#16 DONE 7.5s
|
|
||||||
#17 copy / /app
|
|
||||||
#17 DONE 0.6s
|
|
||||||
#18 mkdir -p /app/node_modules/.cache
|
|
||||||
#18 DONE 0.2s
|
|
||||||
#19 copy /mise/shims
|
|
||||||
#19 DONE 0.0s
|
|
||||||
#20 bun install --frozen-lockfile
|
|
||||||
#20 0.118 bun install v1.4.4 (38afee6c8)
|
|
||||||
#20 11.51
|
|
||||||
#20 11.52 $ prisma generate || true
|
|
||||||
#20 ...
|
|
||||||
#21 copy /mise/installs
|
|
||||||
#21 DONE 10.0s
|
|
||||||
#22 copy /usr/local/bin/mise
|
|
||||||
#22 DONE 0.9s
|
|
||||||
#20 bun install --frozen-lockfile
|
|
||||||
#20 ...
|
|
||||||
#23 copy /etc/mise/config.toml
|
|
||||||
#23 DONE 0.0s
|
|
||||||
#24 copy /root/.local/state/mise
|
|
||||||
#24 DONE 0.0s
|
|
||||||
#20 bun install --frozen-lockfile
|
|
||||||
#20 14.20 Prisma schema loaded from prisma/schema.prisma
|
|
||||||
#20 15.86
|
|
||||||
#20 15.86 ✔ Generated Prisma Client (v6.19.2) to ./node_modules/@prisma/client in 703ms
|
|
||||||
#20 15.86
|
|
||||||
#20 15.86 Start by importing your Prisma Client (See: https://pris.ly/d/importing-client)
|
|
||||||
#20 15.86
|
|
||||||
#20 15.86 Tip: Interested in query caching in just a few lines of code? Try Accelerate today! https://pris.ly/tip-3-accelerate
|
|
||||||
#20 15.86
|
|
||||||
#20 16.19
|
|
||||||
#20 16.19 + @tailwindcss/postcss@4.1.18
|
|
||||||
#20 16.19 + @types/react@19.2.8
|
|
||||||
#20 16.19 + @types/react-dom@19.2.3
|
|
||||||
#20 16.19 + bun-types@1.3.6
|
|
||||||
#20 16.19 + eslint@9.39.2
|
|
||||||
#20 16.19 + eslint-config-next@16.1.3
|
|
||||||
#20 16.19 + tailwindcss@4.1.18
|
|
||||||
#20 16.19 + tw-animate-css@1.4.0
|
|
||||||
#20 16.19 + typescript@5.9.3
|
|
||||||
#20 16.19 + @dnd-kit/core@6.3.1
|
|
||||||
#20 16.19 + @dnd-kit/sortable@10.0.0
|
|
||||||
#20 16.19 + @dnd-kit/utilities@3.2.2
|
|
||||||
#20 16.19 + @hookform/resolvers@5.2.2
|
|
||||||
#20 16.19 + @hugeicons/core-free-icons@4.3.5
|
|
||||||
#20 16.19 + @hugeicons/react@1.1.10
|
|
||||||
#20 16.19 + @mdxeditor/editor@3.52.3
|
|
||||||
#20 16.19 + @prisma/client@6.19.2
|
|
||||||
#20 16.19 + @radix-ui/react-accordion@1.2.12
|
|
||||||
#20 16.19 + @radix-ui/react-alert-dialog@1.1.15
|
|
||||||
#20 16.19 + @radix-ui/react-aspect-ratio@1.1.8
|
|
||||||
#20 16.19 + @radix-ui/react-avatar@1.1.11
|
|
||||||
#20 16.19 + @radix-ui/react-checkbox@1.3.3
|
|
||||||
#20 16.19 + @radix-ui/react-collapsible@1.1.12
|
|
||||||
#20 16.19 + @radix-ui/react-context-menu@2.2.16
|
|
||||||
#20 16.19 + @radix-ui/react-dialog@1.1.15
|
|
||||||
#20 16.19 + @radix-ui/react-dropdown-menu@2.1.16
|
|
||||||
#20 16.19 + @radix-ui/react-hover-card@1.1.15
|
|
||||||
#20 16.19 + @radix-ui/react-label@2.1.8
|
|
||||||
#20 16.19 + @radix-ui/react-menubar@1.1.16
|
|
||||||
#20 16.19 + @radix-ui/react-navigation-menu@1.2.14
|
|
||||||
#20 16.19 + @radix-ui/react-popover@1.1.15
|
|
||||||
#20 16.19 + @radix-ui/react-progress@1.1.8
|
|
||||||
#20 16.19 + @radix-ui/react-radio-group@1.3.8
|
|
||||||
#20 16.19 + @radix-ui/react-scroll-area@1.2.10
|
|
||||||
#20 16.19 + @radix-ui/react-select@2.2.6
|
|
||||||
#20 16.19 + @radix-ui/react-separator@1.1.8
|
|
||||||
#20 16.19 + @radix-ui/react-slider@1.3.6
|
|
||||||
#20 16.19 + @radix-ui/react-slot@1.2.4
|
|
||||||
#20 16.19 + @radix-ui/react-switch@1.2.6
|
|
||||||
#20 16.19 + @radix-ui/react-tabs@1.1.13
|
|
||||||
#20 16.19 + @radix-ui/react-toast@1.2.15
|
|
||||||
#20 16.19 + @radix-ui/react-toggle@1.1.10
|
|
||||||
#20 16.19 + @radix-ui/react-toggle-group@1.1.11
|
|
||||||
#20 16.19 + @radix-ui/react-tooltip@1.2.8
|
|
||||||
#20 16.19 + @reactuses/core@6.1.9
|
|
||||||
#20 16.19 + @tanstack/react-query@5.90.19
|
|
||||||
#20 16.19 + @tanstack/react-table@8.21.3
|
|
||||||
#20 16.19 + class-variance-authority@0.7.1
|
|
||||||
#20 16.19 + clsx@2.1.1
|
|
||||||
#20 16.19 + cmdk@1.1.1
|
|
||||||
#20 16.19 + date-fns@4.1.0
|
|
||||||
#20 16.19 + embla-carousel-react@8.6.0
|
|
||||||
#20 16.19 + framer-motion@14.7.1
|
|
||||||
#20 16.19 + imapflow@2.9.1
|
|
||||||
#20 16.19 + input-otp@1.4.2
|
|
||||||
#20 16.19 + lucide-react@1.62.0
|
|
||||||
#20 16.19 + motion@12.43.0
|
|
||||||
#20 16.19 + next@16.1.3
|
|
||||||
#20 16.19 + next-auth@4.24.13
|
|
||||||
#20 16.19 + next-intl@4.7.0
|
|
||||||
#20 16.19 + next-themes@0.4.6
|
|
||||||
#20 16.19 + prisma@6.19.2
|
|
||||||
#20 16.19 + react@19.2.3
|
|
||||||
#20 16.19 + react-day-picker@9.13.0
|
|
||||||
#20 16.19 + react-dom@19.2.3
|
|
||||||
#20 16.19 + react-hook-form@7.71.1
|
|
||||||
#20 16.19 + react-markdown@10.1.0
|
|
||||||
#20 16.19 + react-resizable-panels@3.0.6
|
|
||||||
#20 16.19 + react-syntax-highlighter@15.6.6
|
|
||||||
#20 16.19 + recharts@2.15.4
|
|
||||||
#20 16.19 + sharp@0.34.5
|
|
||||||
#20 16.19 + sonner@2.0.7
|
|
||||||
#20 16.19 + tailwind-merge@3.7.0
|
|
||||||
#20 16.19 + tailwindcss-animate@1.0.7
|
|
||||||
#20 16.19 + uuid@11.1.0
|
|
||||||
#20 16.19 + vaul@1.1.2
|
|
||||||
#20 16.19 + z-ai-web-dev-sdk@0.0.18
|
|
||||||
#20 16.19 + zod@4.3.5
|
|
||||||
#20 16.19 + zustand@5.0.10
|
|
||||||
#20 16.19
|
|
||||||
#20 16.19 858 packages installed [16.07s]
|
|
||||||
#20 DONE 18.4s
|
|
||||||
#25 copy / /app
|
|
||||||
#25 DONE 6.0s
|
|
||||||
#26 bun run build
|
|
||||||
#26 4.182 $ prisma generate && next build && cp -r .next/static .next/standalone/.next/ && cp -r public .next/standalone/
|
|
||||||
#26 5.561 Prisma schema loaded from prisma/schema.prisma
|
|
||||||
#26 6.699 ┌─────────────────────────────────────────────────────────┐
|
|
||||||
#26 6.699 │ Update available 6.19.2 -> 8.0.0-rc.28 │
|
|
||||||
#26 6.699 │ │
|
|
||||||
#26 6.699 │ This is a major update - please follow the guide at │
|
|
||||||
#26 6.699 │ https://pris.ly/d/major-version-upgrade │
|
|
||||||
#26 6.699 │ │
|
|
||||||
#26 6.699 │ Run the following to update │
|
|
||||||
#26 6.699 │ npm i --save-dev prisma@latest │
|
|
||||||
#26 6.699 │ npm i @prisma/client@latest │
|
|
||||||
#26 6.699 └─────────────────────────────────────────────────────────┘
|
|
||||||
#26 6.699
|
|
||||||
#26 6.699 ✔ Generated Prisma Client (v6.19.2) to ./node_modules/@prisma/client in 642ms
|
|
||||||
#26 6.699
|
|
||||||
#26 6.699 Start by importing your Prisma Client (See: https://pris.ly/d/importing-client)
|
|
||||||
#26 6.699
|
|
||||||
#26 6.699 Tip: Want to turn off tips and other hints? https://pris.ly/tip-4-nohints
|
|
||||||
#26 6.699
|
|
||||||
#26 6.999 ⚠ You are using a non-standard "NODE_ENV" value in your environment. This creates inconsistencies in the project and is strongly advised against. Read more: https://nextjs.org/docs/messages/non-standard-node-env
|
|
||||||
#26 8.173 ▲ Next.js 16.1.3 (Turbopack)
|
|
||||||
#26 8.173
|
|
||||||
#26 8.458 Creating an optimized production build ...
|
|
||||||
#26 14.23 (node:95) [DEP0205] DeprecationWarning: `module.register()` is deprecated. Use `module.registerHooks()` instead.
|
|
||||||
#26 14.23 (Use `node --trace-deprecation ...` to show where the warning was created)
|
|
||||||
#26 32.19 ✓ Compiled successfully in 23.2s
|
|
||||||
#26 32.19 Skipping validation of types
|
|
||||||
#26 32.45 Collecting page data using 3 workers ...
|
|
||||||
#26 35.01 Generating static pages using 3 workers (0/4) ...
|
|
||||||
#26 35.13 Generating static pages using 3 workers (1/4)
|
|
||||||
#26 35.26 Each child in a list should have a unique "key" prop.
|
|
||||||
#26 35.26
|
|
||||||
#26 35.26 Check the top-level render call using <__next_viewport_boundary__>. See https://react.dev/link/warning-keys for more information.
|
|
||||||
#26 35.26 Each child in a list should have a unique "key" prop.
|
|
||||||
#26 35.26
|
|
||||||
#26 35.26 Check the top-level render call using <M>. See https://react.dev/link/warning-keys for more information.
|
|
||||||
#26 35.27 Each child in a list should have a unique "key" prop.
|
|
||||||
#26 35.27
|
|
||||||
#26 35.27 Check the top-level render call using <meta>. See https://react.dev/link/warning-keys for more information.
|
|
||||||
#26 35.28 Each child in a list should have a unique "key" prop.
|
|
||||||
#26 35.28
|
|
||||||
#26 35.28 Check the top-level render call using <head>. See https://react.dev/link/warning-keys for more information.
|
|
||||||
#26 35.30 Each child in a list should have a unique "key" prop.
|
|
||||||
#26 35.30
|
|
||||||
#26 35.30 Check the top-level render call using <meta>. See https://react.dev/link/warning-keys for more information.
|
|
||||||
#26 35.31 Each child in a list should have a unique "key" prop.
|
|
||||||
#26 35.31
|
|
||||||
#26 35.31 Check the top-level render call using <html>. See https://react.dev/link/warning-keys for more information.
|
|
||||||
#26 35.31 Each child in a list should have a unique "key" prop.
|
|
||||||
#26 35.31
|
|
||||||
#26 35.31 Check the top-level render call using <meta>. See https://react.dev/link/warning-keys for more information.
|
|
||||||
#26 35.31 Each child in a list should have a unique "key" prop.
|
|
||||||
#26 35.31
|
|
||||||
#26 35.31 Check the top-level render call using <head>. See https://react.dev/link/warning-keys for more information.
|
|
||||||
#26 35.37 Each child in a list should have a unique "key" prop.
|
|
||||||
#26 35.37
|
|
||||||
#26 35.37 Check the top-level render call using <__next_viewport_boundary__>. See https://react.dev/link/warning-keys for more information.
|
|
||||||
#26 35.37 Each child in a list should have a unique "key" prop.
|
|
||||||
#26 35.37
|
|
||||||
#26 35.37 Check the top-level render call using <html>. See https://react.dev/link/warning-keys for more information.
|
|
||||||
#26 35.37 Each child in a list should have a unique "key" prop.
|
|
||||||
#26 35.37
|
|
||||||
#26 35.37 Check the top-level render call using <meta>. See https://react.dev/link/warning-keys for more information.
|
|
||||||
#26 35.37 Each child in a list should have a unique "key" prop.
|
|
||||||
#26 35.37
|
|
||||||
#26 35.37 Check the top-level render call using <head>. See https://react.dev/link/warning-keys for more information.
|
|
||||||
#26 35.39 Error occurred prerendering page "/_global-error". Read more: https://nextjs.org/docs/messages/prerender-error
|
|
||||||
#26 35.39 TypeError: Cannot read properties of null (reading 'useContext')
|
|
||||||
#26 35.39 at ignore-listed frames {
|
|
||||||
#26 35.39 digest: '1499178773'
|
|
||||||
#26 35.39 }
|
|
||||||
#26 35.39 Export encountered an error on /_global-error/page: /_global-error, exiting the build.
|
|
||||||
#26 35.49 ⨯ Next.js build worker exited with code: 1 and signal: null
|
|
||||||
#26 35.60 error: script "build" exited with code 1
|
|
||||||
#26 ERROR: process "bun run build" did not complete successfully: exit code: 1
|
|
||||||
------
|
|
||||||
> bun run build:
|
|
||||||
35.37
|
|
||||||
35.37 Check the top-level render call using <head>. See https://react.dev/link/warning-keys for more information.
|
|
||||||
35.39 Error occurred prerendering page "/_global-error". Read more: https://nextjs.org/docs/messages/prerender-error
|
|
||||||
35.39 TypeError: Cannot read properties of null (reading 'useContext')
|
|
||||||
35.39 at ignore-listed frames {
|
|
||||||
35.39 digest: '1499178773'
|
|
||||||
35.39 }
|
|
||||||
35.39 Export encountered an error on /_global-error/page: /_global-error, exiting the build.
|
|
||||||
35.49 ⨯ Next.js build worker exited with code: 1 and signal: null
|
|
||||||
35.60 error: script "build" exited with code 1
|
|
||||||
------
|
|
||||||
ERROR: failed to build: failed to solve: process "bun run build" did not complete successfully: exit code: 1
|
|
||||||
❌ Railpack build failed
|
|
||||||
railpack-dfm-aos-lgbcnc-fk4Q2Q removed
|
|
||||||
Error occurred ❌, check the logs for details.
|
|
||||||
@@ -1,444 +0,0 @@
|
|||||||
Initializing deployment
|
|
||||||
Cloning Repo github.com/cetinmustafa83/aos.git to /etc/dokploy/applications/dfm-aos-lgbcnc/code: ✅
|
|
||||||
Cloning into '/etc/dokploy/applications/dfm-aos-lgbcnc/code'...
|
|
||||||
remote: Enumerating objects: 1878, done.
|
|
||||||
remote: Counting objects: 0% (1/1878)
remote: Counting objects: 1% (19/1878)
remote: Counting objects: 2% (38/1878)
remote: Counting objects: 3% (57/1878)
remote: Counting objects: 4% (76/1878)
remote: Counting objects: 5% (94/1878)
remote: Counting objects: 6% (113/1878)
remote: Counting objects: 7% (132/1878)
remote: Counting objects: 8% (151/1878)
remote: Counting objects: 9% (170/1878)
remote: Counting objects: 10% (188/1878)
remote: Counting objects: 11% (207/1878)
remote: Counting objects: 12% (226/1878)
remote: Counting objects: 13% (245/1878)
remote: Counting objects: 14% (263/1878)
remote: Counting objects: 15% (282/1878)
remote: Counting objects: 16% (301/1878)
remote: Counting objects: 17% (320/1878)
remote: Counting objects: 18% (339/1878)
remote: Counting objects: 19% (357/1878)
remote: Counting objects: 20% (376/1878)
remote: Counting objects: 21% (395/1878)
remote: Counting objects: 22% (414/1878)
remote: Counting objects: 23% (432/1878)
remote: Counting objects: 24% (451/1878)
remote: Counting objects: 25% (470/1878)
remote: Counting objects: 26% (489/1878)
remote: Counting objects: 27% (508/1878)
remote: Counting objects: 28% (526/1878)
remote: Counting objects: 29% (545/1878)
remote: Counting objects: 30% (564/1878)
remote: Counting objects: 31% (583/1878)
remote: Counting objects: 32% (601/1878)
remote: Counting objects: 33% (620/1878)
remote: Counting objects: 34% (639/1878)
remote: Counting objects: 35% (658/1878)
remote: Counting objects: 36% (677/1878)
remote: Counting objects: 37% (695/1878)
remote: Counting objects: 38% (714/1878)
remote: Counting objects: 39% (733/1878)
remote: Counting objects: 40% (752/1878)
remote: Counting objects: 41% (770/1878)
remote: Counting objects: 42% (789/1878)
remote: Counting objects: 43% (808/1878)
remote: Counting objects: 44% (827/1878)
remote: Counting objects: 45% (846/1878)
remote: Counting objects: 46% (864/1878)
remote: Counting objects: 47% (883/1878)
remote: Counting objects: 48% (902/1878)
remote: Counting objects: 49% (921/1878)
remote: Counting objects: 50% (939/1878)
remote: Counting objects: 51% (958/1878)
remote: Counting objects: 52% (977/1878)
remote: Counting objects: 53% (996/1878)
remote: Counting objects: 54% (1015/1878)
remote: Counting objects: 55% (1033/1878)
remote: Counting objects: 56% (1052/1878)
remote: Counting objects: 57% (1071/1878)
remote: Counting objects: 58% (1090/1878)
remote: Counting objects: 59% (1109/1878)
remote: Counting objects: 60% (1127/1878)
remote: Counting objects: 61% (1146/1878)
remote: Counting objects: 62% (1165/1878)
remote: Counting objects: 63% (1184/1878)
remote: Counting objects: 64% (1202/1878)
remote: Counting objects: 65% (1221/1878)
remote: Counting objects: 66% (1240/1878)
remote: Counting objects: 67% (1259/1878)
remote: Counting objects: 68% (1278/1878)
remote: Counting objects: 69% (1296/1878)
remote: Counting objects: 70% (1315/1878)
remote: Counting objects: 71% (1334/1878)
remote: Counting objects: 72% (1353/1878)
remote: Counting objects: 73% (1371/1878)
remote: Counting objects: 74% (1390/1878)
remote: Counting objects: 75% (1409/1878)
remote: Counting objects: 76% (1428/1878)
remote: Counting objects: 77% (1447/1878)
remote: Counting objects: 78% (1465/1878)
remote: Counting objects: 79% (1484/1878)
remote: Counting objects: 80% (1503/1878)
remote: Counting objects: 81% (1522/1878)
remote: Counting objects: 82% (1540/1878)
remote: Counting objects: 83% (1559/1878)
remote: Counting objects: 84% (1578/1878)
remote: Counting objects: 85% (1597/1878)
remote: Counting objects: 86% (1616/1878)
remote: Counting objects: 87% (1634/1878)
remote: Counting objects: 88% (1653/1878)
remote: Counting objects: 89% (1672/1878)
remote: Counting objects: 90% (1691/1878)
remote: Counting objects: 91% (1709/1878)
remote: Counting objects: 92% (1728/1878)
remote: Counting objects: 93% (1747/1878)
remote: Counting objects: 94% (1766/1878)
remote: Counting objects: 95% (1785/1878)
remote: Counting objects: 96% (1803/1878)
remote: Counting objects: 97% (1822/1878)
remote: Counting objects: 98% (1841/1878)
remote: CouLine truncated
|
|
||||||
remote: Compressing objects: 0% (1/1407)
remote: Compressing objects: 1% (15/1407)
remote: Compressing objects: 2% (29/1407)
remote: Compressing objects: 3% (43/1407)
remote: Compressing objects: 4% (57/1407)
remote: Compressing objects: 5% (71/1407)
remote: Compressing objects: 6% (85/1407)
remote: Compressing objects: 7% (99/1407)
remote: Compressing objects: 8% (113/1407)
remote: Compressing objects: 9% (127/1407)
remote: Compressing objects: 10% (141/1407)
remote: Compressing objects: 11% (155/1407)
remote: Compressing objects: 12% (169/1407)
remote: Compressing objects: 13% (183/1407)
remote: Compressing objects: 14% (197/1407)
remote: Compressing objects: 15% (212/1407)
remote: Compressing objects: 16% (226/1407)
remote: Compressing objects: 17% (240/1407)
remote: Compressing objects: 18% (254/1407)
remote: Compressing objects: 19% (268/1407)
remote: Compressing objects: 20% (282/1407)
remote: Compressing objects: 21% (296/1407)
remote: Compressing objects: 22% (310/1407)
remote: Compressing objects: 23% (324/1407)
remote: Compressing objects: 24% (338/1407)
remote: Compressing objects: 25% (352/1407)
remote: Compressing objects: 26% (366/1407)
remote: Compressing objects: 27% (380/1407)
remote: Compressing objects: 28% (394/1407)
remote: Compressing objects: 29% (409/1407)
remote: Compressing objects: 30% (423/1407)
remote: Compressing objects: 31% (437/1407)
remote: Compressing objects: 32% (451/1407)
remote: Compressing objects: 33% (465/1407)
remote: Compressing objects: 34% (479/1407)
remote: Compressing objects: 35% (493/1407)
remote: Compressing objects: 36% (507/1407)
remote: Compressing objects: 37% (521/1407)
remote: Compressing objects: 38% (535/1407)
remote: Compressing objects: 39% (549/1407)
remote: Compressing objects: 40% (563/1407)
remote: Compressing objects: 41% (577/1407)
remote: Compressing objects: 42% (591/1407)
remote: Compressing objects: 43% (606/1407)
remote: Compressing objects: 44% (620/1407)
remote: Compressing objects: 45% (634/1407)
remote: Compressing objects: 46% (648/1407)
remote: Compressing objects: 47% (662/1407)
remote: Compressing objects: 48% (676/1407)
remote: Compressing objects: 49% (690/1407)
remote: Compressing objects: 50% (704/1407)
remote: Compressing objects: 51% (718/1407)
remote: Compressing objects: 52% (732/1407)
remote: Compressing objects: 53% (746/1407)
remote: Compressing objects: 54% (760/1407)
remote: Compressing objects: 55% (774/1407)
remote: Compressing objects: 56% (788/1407)
remote: Compressing objects: 57% (802/1407)
remote: Compressing objects: 58% (817/1407)
remote: Compressing objects: 59% (831/1407)
remote: Compressing objects: 60% (845/1407)
remote: Compressing objects: 61% (859/1407)
remote: Compressing objects: 62% (873/1407)
remote: Compressing objects: 63% (887/1407)
remote: Compressing objects: 64% (901/1407)
remote: Compressing objects: 65% (915/1407)
remote: Compressing objects: 66% (929/1407)
remote: Compressing objects: 67% (943/1407)
remote: Compressing objects: 68% (957/1407)
remote: Compressing objects: 69% (971/1407)
remote: Compressing objects: 70% (985/1407)
remote: Compressing objects: 71% (999/1407)
remote: Compressing objects: 72% (1014/1407)
remote: Compressing objects: 73% (1028/1407)
remote: Compressing objects: 74% (1042/1407)
remote: Compressing objects: 75% (1056/1407)
remote: Compressing objects: 76% (1070/1407)
remote: Compressing objects: 77% (1084/1407)
remote: Compressing objects: 78% (1098/1407)
remote: Compressing objects: 79% (1112/1407)
remote: Compressing objects: 80% (1126/1407)
remote: Compressing objects: 81% (1140/1407)
remote: Compressing objects: 82% (1154/1407)
remote: Compressing objects: 83% (1168/1407)
remote: Compressing objects: 84% (1182/1407)
remote: Compressing objects: 85% (1196/1407)
remote: Compressing objects: 86% (1211/1407)
remote: Compressing objects: 87% (1225/1407)
remote: Compressing objects: 88% (1239/1407)
remote: Compressing objects: 89% (1253/1407)
remote: Compressing objects: 90% (1267/1407)
remote: Compressing objects: 91% (1281/1407)
remote: Compressing objects: 92% (1295/1407)
remote: Compressing objects: 93% (1309/1407)
remoLine truncated
|
|
||||||
Receiving objects: 0% (1/1878)
Receiving objects: 1% (19/1878)
Receiving objects: 2% (38/1878)
Receiving objects: 3% (57/1878)
Receiving objects: 4% (76/1878)
Receiving objects: 5% (94/1878)
Receiving objects: 6% (113/1878)
Receiving objects: 7% (132/1878)
Receiving objects: 8% (151/1878)
Receiving objects: 9% (170/1878)
Receiving objects: 10% (188/1878)
Receiving objects: 11% (207/1878)
Receiving objects: 12% (226/1878)
Receiving objects: 13% (245/1878)
Receiving objects: 14% (263/1878)
Receiving objects: 15% (282/1878)
Receiving objects: 16% (301/1878)
Receiving objects: 17% (320/1878)
Receiving objects: 18% (339/1878)
Receiving objects: 19% (357/1878)
Receiving objects: 20% (376/1878)
Receiving objects: 21% (395/1878)
Receiving objects: 22% (414/1878)
Receiving objects: 23% (432/1878)
Receiving objects: 24% (451/1878)
Receiving objects: 25% (470/1878)
Receiving objects: 26% (489/1878)
Receiving objects: 27% (508/1878)
Receiving objects: 28% (526/1878)
Receiving objects: 29% (545/1878)
Receiving objects: 30% (564/1878)
Receiving objects: 31% (583/1878)
Receiving objects: 32% (601/1878)
Receiving objects: 33% (620/1878)
Receiving objects: 34% (639/1878)
Receiving objects: 35% (658/1878)
Receiving objects: 36% (677/1878)
Receiving objects: 37% (695/1878)
Receiving objects: 38% (714/1878)
Receiving objects: 39% (733/1878)
Receiving objects: 40% (752/1878)
Receiving objects: 41% (770/1878)
Receiving objects: 42% (789/1878)
Receiving objects: 43% (808/1878), 11.57 MiB | 23.12 MiB/s
Receiving objects: 44% (827/1878), 11.57 MiB | 23.12 MiB/s
Receiving objects: 45% (846/1878), 11.57 MiB | 23.12 MiB/s
Receiving objects: 46% (864/1878), 11.57 MiB | 23.12 MiB/s
Receiving objects: 47% (883/1878), 11.57 MiB | 23.12 MiB/s
Receiving objects: 48% (902/1878), 11.57 MiB | 23.12 MiB/s
Receiving objects: 49% (921/1878), 11.57 MiB | 23.12 MiB/s
Receiving objects: 50% (939/1878), 11.57 MiB | 23.12 MiB/s
Receiving objects: 51% (958/1878), 11.57 MiB | 23.12 MiB/s
Receiving objects: 51% (974/1878), 26.93 MiB | 26.92 MiB/s
Receiving objects: 52% (977/1878), 26.93 MiB | 26.92 MiB/s
Receiving objects: 53% (996/1878), 42.80 MiB | 28.53 MiB/s
Receiving objects: 54% (1015/1878), 42.80 MiB | 28.53 MiB/s
Receiving objects: 55% (1033/1878), 42.80 MiB | 28.53 MiB/s
Receiving objects: 56% (1052/1878), 42.80 MiB | 28.53 MiB/s
Receiving objects: 57% (1071/1878), 42.80 MiB | 28.53 MiB/s
Receiving objects: 58% (1090/1878), 42.80 MiB | 28.53 MiB/s
Receiving objects: 59% (1109/1878), 42.80 MiB | 28.53 MiB/s
Receiving objects: 60% (1127/1878), 42.80 MiB | 28.53 MiB/s
Receiving objects: 61% (1146/1878), 42.80 MiB | 28.53 MiB/s
Receiving objects: 62% (1165/1878), 42.80 MiB | 28.53 MiB/s
Receiving objects: 63% (1184/1878), 42.80 MiB | 28.53 MiB/s
Receiving objects: 64% (1202/1878), 42.80 MiB | 28.53 MiB/s
Receiving objects: 65% (1221/1878), 42.80 MiB | 28.53 MiB/s
Receiving objects: 66% (1240/1878), 42.80 MiB | 28.53 MiB/s
Receiving objects: 67% (1259/1878), 42.80 MiB | 28.53 MiB/s
Receiving objects: 68% (1278/1878), 42.80 MiB | 28.53 MiB/s
Receiving objects: 69% (1296/1878), 42.80 MiB | 28.53 MiB/s
Receiving objects: 70% (1315/1878), 42.80 MiB | 28.53 MiB/s
Receiving objects: 71% (1334/1878), 42.80 MiB | 28.53 MiB/s
Receiving objects: 72% (1353/1878), 42.80 MiB | 28.53 MiB/s
Receiving objects: 73% (1371/1878), 42.80 MiB | 28.53 MiB/s
Receiving objects: 74% (1390/1878), 42.80 MiB | 28.53 MiB/s
Receiving objects: 75% (1409/1878), 42.80 MiB | 28.53 MiB/s
Receiving objects: 76% (1428/1878), 42.80 MiB | 28.53 MiB/s
Receiving objects: 77% (1447/1878), 42.80 MiB | 28.53 MiB/s
Receiving objects: 78% (1465/1878), 42.80 MiB | 28.53 MiB/s
Receiving objects: 79% (1484/1878), 42.80 MiB | 28.53 MiB/s
Receiving objects: 80% (1503/1878), 42.80 MiB | 28.53 MiB/s
Receiving objects: 81% (1522/1878), 42.80 MiB | 28.53 MiB/s
Receiving objects: 82% (1540/1878), 42.80 MiB | 28.53 MiB/s
Receiving objects: 83% (1559/1878), 42.80 MiB | 28.53 MiB/s
Receiving objects: 84% (1578/1878), 42.80 MiB | 28.53 MiB/s
Receiving objects: 85% (1597/1878), 42.80 MiB | 28.53 MiB/s
Receiving objects: 86% (1616/1878), 42.80 MiB | 28.53 MiB/s
Receiving objects: 87% (1634/1878), 42.80 MiB | 28.53 MiB/s
Receiving objects: 88% (1653/1878), 42.80 MiB | 28.53 MiB/s
Receiving objects: 89% (1672/1878), 42.80 MiB | 28.53 MiB/s
Receiving objects: 90% (1691/1878), 42.80 MiB | 28.53 MiB/s
Receiving objects: 91% (1709/1878), 42.80 MiB | 28.53 MiB/s
Receiving objects: 92% (1728/1878), 42.80 MiB | 28.53 MiB/s
Receiving objects: 93% (1747/1878), 42.80 MiB | 28.53 MiB/s
Receiving objects: 94% (1766/1878), 42.80 MiB | 28.53 MiB/s
Receiving objects: 95% (1785/1878), 42.80 MiB | 28.53 MiB/s
Receiving objects: 96% (1803/1878), 42.80 MiB | 28.53 MiB/s
Receiving objects: 97% (1822/1878), 42.80 MiB | 28.53 MiB/s
Receiving objects: 98% (1841/1878), 42.80 MiB | 28.53 MiB/s
Receiving objects: 99% (1860/1878),Line truncated
|
|
||||||
Receiving objects: 100% (1878/1878), 42.80 MiB | 28.53 MiB/s␍Receiving objects: 100% (1878/1878), 47.77 MiB | 27.51 MiB/s, done.
|
|
||||||
Resolving deltas: 0% (0/320)␍Resolving deltas: 1% (4/320)␍Resolving deltas: 2% (7/320)␍Resolving deltas: 3% (10/320)␍Resolving deltas: 4% (13/320)␍Resolving deltas: 5% (16/320)␍Resolving deltas: 6% (20/320)␍Resolving deltas: 7% (23/320)␍Resolving deltas: 8% (26/320)␍Resolving deltas: 9% (29/320)␍Resolving deltas: 10% (32/320)␍Resolving deltas: 11% (36/320)␍Resolving deltas: 12% (39/320)␍Resolving deltas: 13% (42/320)␍Resolving deltas: 14% (45/320)␍Resolving deltas: 15% (48/320)␍Resolving deltas: 16% (52/320)␍Resolving deltas: 17% (55/320)␍Resolving deltas: 18% (58/320)␍Resolving deltas: 19% (61/320)␍Resolving deltas: 20% (64/320)␍Resolving deltas: 21% (68/320)␍Resolving deltas: 22% (71/320)␍Resolving deltas: 23% (74/320)␍Resolving deltas: 24% (77/320)␍Resolving deltas: 25% (80/320)␍Resolving deltas: 26% (84/320)␍Resolving deltas: 27% (87/320)␍Resolving deltas: 28% (91/320)␍Resolving deltas: 29% (93/320)␍Resolving deltas: 30% (96/320)␍Resolving deltas: 31% (100/320)␍Resolving deltas: 32% (104/320)␍Resolving deltas: 33% (106/320)␍Resolving deltas: 34% (110/320)␍Resolving deltas: 35% (112/320)␍Resolving deltas: 36% (116/320)␍Resolving deltas: 37% (119/320)␍Resolving deltas: 38% (122/320)␍Resolving deltas: 39% (125/320)␍Resolving deltas: 40% (128/320)␍Resolving deltas: 41% (132/320)␍Resolving deltas: 42% (135/320)␍Resolving deltas: 43% (138/320)␍Resolving deltas: 44% (141/320)␍Resolving deltas: 45% (144/320)␍Resolving deltas: 46% (149/320)␍Resolving deltas: 47% (151/320)␍Resolving deltas: 48% (154/320)␍Resolving deltas: 49% (157/320)␍Resolving deltas: 50% (160/320)␍Resolving deltas: 51% (164/320)␍Resolving deltas: 52% (167/320)␍Resolving deltas: 53% (170/320)␍Resolving deltas: 54% (173/320)␍Resolving deltas: 55% (176/320)␍Resolving deltas: 56% (180/320)␍Resolving deltas: 57% (183/320)␍Resolving deltas: 58% (186/320)␍Resolving deltas: 59% (189/320)␍Resolving deltas: 60% (192/320)␍Resolving deltas: 61% (196/320)␍Resolving deltas: 62% (199/320)␍Resolving deltas: 63% (202/320)␍Resolving deltas: 64% (205/320)␍Resolving deltas: 65% (208/320)␍Resolving deltas: 66% (212/320)␍Resolving deltas: 67% (215/320)␍Resolving deltas: 68% (218/320)␍Resolving deltas: 69% (221/320)␍Resolving deltas: 70% (224/320)␍Resolving deltas: 71% (228/320)␍Resolving deltas: 72% (231/320)␍Resolving deltas: 73% (234/320)␍Resolving deltas: 74% (237/320)␍Resolving deltas: 75% (240/320)␍Resolving deltas: 76% (244/320)␍Resolving deltas: 77% (247/320)␍Resolving deltas: 78% (250/320)␍Resolving deltas: 79% (253/320)␍Resolving deltas: 80% (256/320)␍Resolving deltas: 81% (260/320)␍Resolving deltas: 82% (263/320)␍Resolving deltas: 83% (266/320)␍Resolving deltas: 84% (269/320)␍Resolving deltas: 85% (272/320)␍Resolving deltas: 86% (276/320)␍Resolving deltas: 87% (279/320)␍Resolving deltas: 88% (282/320)␍Resolving deltas: 89% (285/320)␍Resolving deltas: 90% (288/320)␍Resolving deltas: 91% (292/320)␍Resolving deltas: 92% (295/320)␍Resolving deltas: 93% (298/320)␍Resolving deltas: 94% (301/320)␍Resolving deltas: 95% (304/320)␍Resolving deltas: 96% (308/320)␍Resolving deltas: 97% (311/320)␍Resolving deltas: 98% (314/320)␍Resolving deltas: 99% (317/320)␍Resolving deltas: 100% (320/320)␍Resolving deltas: 100% (320/320), done.
|
|
||||||
> Installing railpack, please wait…
|
|
||||||
____ _ _ _
|
|
||||||
| _ \ __ _(_) |_ __ __ _ ___| | __
|
|
||||||
| |_) / _` | | | '_ \ / _` |/ __| |/ /
|
|
||||||
| _ < (_| | | | |_) | (_| | (__| <
|
|
||||||
|_| \_\__,_|_|_| .__/ \__,_|\___|_|\_\
|
|
||||||
|_|
|
|
||||||
Railpack is now installed!
|
|
||||||
Run 'railpack --help' to get started
|
|
||||||
railpack-dfm-aos-lgbcnc-VqdRBM
|
|
||||||
Preparing Railpack build plan...
|
|
||||||
╭─────────────────╮
|
|
||||||
│ Railpack 0.15.4 │
|
|
||||||
╰─────────────────╯
|
|
||||||
↳ Found .dockerignore file, applying filters
|
|
||||||
↳ Detected Node
|
|
||||||
↳ Using bun package manager
|
|
||||||
Packages
|
|
||||||
──────────
|
|
||||||
bun │ 1.4.4 │ railpack default (latest)
|
|
||||||
node │ 26.13.0 │ railpack default (latest)
|
|
||||||
Steps
|
|
||||||
──────────
|
|
||||||
▸ install
|
|
||||||
$ bun install --frozen-lockfile
|
|
||||||
▸ build
|
|
||||||
$ bun run build
|
|
||||||
Deploy
|
|
||||||
──────────
|
|
||||||
$ bun run start
|
|
||||||
✅ Railpack prepare completed.
|
|
||||||
Building with Railpack frontend...
|
|
||||||
#0 building with "railpack-dfm-aos-lgbcnc-VqdRBM" instance using docker-container driver
|
|
||||||
#1 [internal] booting buildkit
|
|
||||||
#1 pulling image moby/buildkit:buildx-stable-1
|
|
||||||
#1 pulling image moby/buildkit:buildx-stable-1 1.9s done
|
|
||||||
#1 creating container buildx_buildkit_railpack-dfm-aos-lgbcnc-vqdrbm0
|
|
||||||
#1 creating container buildx_buildkit_railpack-dfm-aos-lgbcnc-vqdrbm0 5.0s done
|
|
||||||
#1 DONE 7.0s
|
|
||||||
#2 resolve image config for docker-image://ghcr.io/railwayapp/railpack-frontend:v0.15.4
|
|
||||||
#2 DONE 5.5s
|
|
||||||
#3 docker-image://ghcr.io/railwayapp/railpack-frontend:v0.15.4@sha256:7e0535e519d9d00793d0bb4e652be5d48373ab5e0c7d9b90ef6bc40147290ff7
|
|
||||||
#3 resolve ghcr.io/railwayapp/railpack-frontend:v0.15.4@sha256:7e0535e519d9d00793d0bb4e652be5d48373ab5e0c7d9b90ef6bc40147290ff7 done
|
|
||||||
#3 sha256:76fdf18f436616aff2234f2d325d888d31af103f333a8f491d539dce0106e849 0B / 7.90MB 0.2s
|
|
||||||
#3 sha256:1074353eec0db2c1d81d5af2671e56e00cf5738486f5762609ea33d606f88612 0B / 3.86MB 0.2s
|
|
||||||
#3 sha256:76fdf18f436616aff2234f2d325d888d31af103f333a8f491d539dce0106e849 1.05MB / 7.90MB 0.5s
|
|
||||||
#3 sha256:76fdf18f436616aff2234f2d325d888d31af103f333a8f491d539dce0106e849 7.90MB / 7.90MB 0.6s done
|
|
||||||
#3 sha256:1074353eec0db2c1d81d5af2671e56e00cf5738486f5762609ea33d606f88612 3.86MB / 3.86MB 0.6s done
|
|
||||||
#3 extracting sha256:1074353eec0db2c1d81d5af2671e56e00cf5738486f5762609ea33d606f88612 0.1s done
|
|
||||||
#3 DONE 0.8s
|
|
||||||
#3 docker-image://ghcr.io/railwayapp/railpack-frontend:v0.15.4@sha256:7e0535e519d9d00793d0bb4e652be5d48373ab5e0c7d9b90ef6bc40147290ff7
|
|
||||||
#3 extracting sha256:76fdf18f436616aff2234f2d325d888d31af103f333a8f491d539dce0106e849
|
|
||||||
#3 extracting sha256:76fdf18f436616aff2234f2d325d888d31af103f333a8f491d539dce0106e849 0.3s done
|
|
||||||
#3 DONE 1.1s
|
|
||||||
#4 load build definition from railpack-plan.json
|
|
||||||
#4 transferring dockerfile:
|
|
||||||
#4 transferring dockerfile: 5.06kB done
|
|
||||||
#4 DONE 0.0s
|
|
||||||
#5 loading .
|
|
||||||
#5 DONE 0.0s
|
|
||||||
#6 [railpack] secrets hash
|
|
||||||
#6 DONE 0.0s
|
|
||||||
#7 docker-image://ghcr.io/railwayapp/railpack-builder:latest
|
|
||||||
#7 resolve ghcr.io/railwayapp/railpack-builder:latest
|
|
||||||
#7 resolve ghcr.io/railwayapp/railpack-builder:latest 1.0s done
|
|
||||||
#7 ...
|
|
||||||
#6 [railpack] secrets hash
|
|
||||||
#6 DONE 0.0s
|
|
||||||
#7 docker-image://ghcr.io/railwayapp/railpack-builder:latest
|
|
||||||
#7 DONE 1.2s
|
|
||||||
#5 loading .
|
|
||||||
#5 transferring context: 3.88MB 0.2s
|
|
||||||
#5 ...
|
|
||||||
#8 [railpack] loading secrets
|
|
||||||
#8 resolve docker.io/library/alpine:latest 1.6s done
|
|
||||||
#8 sha256:7b229517ed222597277036d94892173207d01a731ab3a88eeb1de2e963a2c788 3.85MB / 3.85MB 0.5s done
|
|
||||||
#8 extracting sha256:7b229517ed222597277036d94892173207d01a731ab3a88eeb1de2e963a2c788 1.3s done
|
|
||||||
#8 DONE 3.4s
|
|
||||||
#5 loading .
|
|
||||||
#5 ...
|
|
||||||
#9 [railpack] copy secrets hash
|
|
||||||
#9 DONE 0.2s
|
|
||||||
#7 docker-image://ghcr.io/railwayapp/railpack-builder:latest
|
|
||||||
#7 sha256:193926ad1d06489b7487e8ac4ae2d0874e6ff05cf65d874d2af508830fc03def 119B / 119B 0.4s done
|
|
||||||
#7 sha256:df614908d6aba31e983953b17fd48496d27425529b3947c3d5583c4cc9c15c9a 868.40kB / 868.40kB 0.7s done
|
|
||||||
#7 sha256:604add184d03d4cf6e2ff1c4b9013b265eb9c11570afe28ce8f9dc417b98ea3f 51.38MB / 237.08MB 2.1s
|
|
||||||
#7 sha256:08a1e03b3da5bb4a1059032dca3216f33ddfc4a48a45db88921f5bb2e9a8fa2d 36.70MB / 53.72MB 2.1s
|
|
||||||
#7 sha256:4f4fb700ef54461cfa02571ae0db9a0dc1e0cdb5577484a6d75e68dc38e8acc1 32B / 32B 0.2s done
|
|
||||||
#7 sha256:4dc3950125ebc9ed195e1101fc6c02e2fce113ba0f53bfb05b2cdf58747df9af 8.39MB / 67.81MB 1.4s
|
|
||||||
#7 sha256:62fe2e747f69f2f414c7e9eb1553155cf0a658398f0462557f458821dce2b29d 22.68MB / 25.64MB 0.9s
|
|
||||||
#7 sha256:08a1e03b3da5bb4a1059032dca3216f33ddfc4a48a45db88921f5bb2e9a8fa2d 40.51MB / 53.72MB 2.3s
|
|
||||||
#7 sha256:62fe2e747f69f2f414c7e9eb1553155cf0a658398f0462557f458821dce2b29d 25.17MB / 25.64MB 1.1s
|
|
||||||
#7 sha256:08a1e03b3da5bb4a1059032dca3216f33ddfc4a48a45db88921f5bb2e9a8fa2d 45.09MB / 53.72MB 2.4s
|
|
||||||
#7 sha256:4dc3950125ebc9ed195e1101fc6c02e2fce113ba0f53bfb05b2cdf58747df9af 12.58MB / 67.81MB 1.8s
|
|
||||||
#7 sha256:62fe2e747f69f2f414c7e9eb1553155cf0a658398f0462557f458821dce2b29d 25.64MB / 25.64MB 1.1s done
|
|
||||||
#7 sha256:604add184d03d4cf6e2ff1c4b9013b265eb9c11570afe28ce8f9dc417b98ea3f 70.25MB / 237.08MB 2.6s
|
|
||||||
#7 sha256:08a1e03b3da5bb4a1059032dca3216f33ddfc4a48a45db88921f5bb2e9a8fa2d 49.28MB / 53.72MB 2.6s
|
|
||||||
#7 sha256:4846f29007305297af653c57bf9b60ba8f676a38695c68d98460063442581671 0B / 49.39MB 0.2s
|
|
||||||
#7 sha256:604add184d03d4cf6e2ff1c4b9013b265eb9c11570afe28ce8f9dc417b98ea3f 82.84MB / 237.08MB 2.9s
|
|
||||||
#7 sha256:08a1e03b3da5bb4a1059032dca3216f33ddfc4a48a45db88921f5bb2e9a8fa2d 52.43MB / 53.72MB 2.7s
|
|
||||||
#7 sha256:4846f29007305297af653c57bf9b60ba8f676a38695c68d98460063442581671 3.15MB / 49.39MB 0.3s
|
|
||||||
#7 ...
|
|
||||||
#10 [railpack] hash used secrets
|
|
||||||
#10 DONE 0.9s
|
|
||||||
#11 [railpack] copy used secrets hash
|
|
||||||
#11 DONE 0.0s
|
|
||||||
#7 docker-image://ghcr.io/railwayapp/railpack-builder:latest
|
|
||||||
#7 sha256:08a1e03b3da5bb4a1059032dca3216f33ddfc4a48a45db88921f5bb2e9a8fa2d 53.72MB / 53.72MB 2.9s done
|
|
||||||
#7 sha256:4846f29007305297af653c57bf9b60ba8f676a38695c68d98460063442581671 11.53MB / 49.39MB 0.5s
|
|
||||||
#7 sha256:4dc3950125ebc9ed195e1101fc6c02e2fce113ba0f53bfb05b2cdf58747df9af 16.78MB / 67.81MB 2.4s
|
|
||||||
#7 sha256:4846f29007305297af653c57bf9b60ba8f676a38695c68d98460063442581671 20.97MB / 49.39MB 0.6s
|
|
||||||
#7 sha256:604add184d03d4cf6e2ff1c4b9013b265eb9c11570afe28ce8f9dc417b98ea3f 96.47MB / 237.08MB 3.2s
|
|
||||||
#7 sha256:4846f29007305297af653c57bf9b60ba8f676a38695c68d98460063442581671 31.46MB / 49.39MB 0.8s
|
|
||||||
#7 sha256:4846f29007305297af653c57bf9b60ba8f676a38695c68d98460063442581671 39.85MB / 49.39MB 0.9s
|
|
||||||
#7 sha256:604add184d03d4cf6e2ff1c4b9013b265eb9c11570afe28ce8f9dc417b98ea3f 116.39MB / 237.08MB 3.6s
|
|
||||||
#7 sha256:4846f29007305297af653c57bf9b60ba8f676a38695c68d98460063442581671 44.04MB / 49.39MB 1.1s
|
|
||||||
#7 sha256:4dc3950125ebc9ed195e1101fc6c02e2fce113ba0f53bfb05b2cdf58747df9af 22.02MB / 67.81MB 3.0s
|
|
||||||
#7 sha256:4846f29007305297af653c57bf9b60ba8f676a38695c68d98460063442581671 49.39MB / 49.39MB 1.2s done
|
|
||||||
#7 extracting sha256:4846f29007305297af653c57bf9b60ba8f676a38695c68d98460063442581671
|
|
||||||
#7 sha256:604add184d03d4cf6e2ff1c4b9013b265eb9c11570afe28ce8f9dc417b98ea3f 133.17MB / 237.08MB 3.9s
|
|
||||||
#7 sha256:4dc3950125ebc9ed195e1101fc6c02e2fce113ba0f53bfb05b2cdf58747df9af 26.21MB / 67.81MB 3.5s
|
|
||||||
#7 sha256:604add184d03d4cf6e2ff1c4b9013b265eb9c11570afe28ce8f9dc417b98ea3f 155.19MB / 237.08MB 4.4s
|
|
||||||
#7 sha256:4dc3950125ebc9ed195e1101fc6c02e2fce113ba0f53bfb05b2cdf58747df9af 31.46MB / 67.81MB 3.9s
|
|
||||||
#7 sha256:604add184d03d4cf6e2ff1c4b9013b265eb9c11570afe28ce8f9dc417b98ea3f 171.97MB / 237.08MB 4.7s
|
|
||||||
#7 sha256:604add184d03d4cf6e2ff1c4b9013b265eb9c11570afe28ce8f9dc417b98ea3f 189.79MB / 237.08MB 5.0s
|
|
||||||
#7 sha256:4dc3950125ebc9ed195e1101fc6c02e2fce113ba0f53bfb05b2cdf58747df9af 35.65MB / 67.81MB 4.4s
|
|
||||||
#7 sha256:604add184d03d4cf6e2ff1c4b9013b265eb9c11570afe28ce8f9dc417b98ea3f 205.52MB / 237.08MB 5.3s
|
|
||||||
#7 ...
|
|
||||||
#5 loading .
|
|
||||||
#5 transferring context: 128.44MB 5.9s done
|
|
||||||
#5 DONE 6.0s
|
|
||||||
#7 docker-image://ghcr.io/railwayapp/railpack-builder:latest
|
|
||||||
#7 sha256:604add184d03d4cf6e2ff1c4b9013b265eb9c11570afe28ce8f9dc417b98ea3f 225.44MB / 237.08MB 5.6s
|
|
||||||
#7 sha256:4dc3950125ebc9ed195e1101fc6c02e2fce113ba0f53bfb05b2cdf58747df9af 40.89MB / 67.81MB 4.8s
|
|
||||||
#7 sha256:4dc3950125ebc9ed195e1101fc6c02e2fce113ba0f53bfb05b2cdf58747df9af 46.14MB / 67.81MB 5.3s
|
|
||||||
#7 ...
|
|
||||||
#12 docker-image://ghcr.io/railwayapp/railpack-runtime:latest
|
|
||||||
#12 resolve ghcr.io/railwayapp/railpack-runtime:latest 1.0s done
|
|
||||||
#12 sha256:75dc09925ca146a3efecc887098f8f1313da0fb1b0c8d36d628b6cae320665ec 7.39MB / 7.39MB 0.4s done
|
|
||||||
#12 sha256:ecc510c1e359bdc007b39802570bb7e4dec7d6ebccf357c3201a74299113e05e 29.84MB / 29.84MB 1.6s done
|
|
||||||
#12 extracting sha256:ecc510c1e359bdc007b39802570bb7e4dec7d6ebccf357c3201a74299113e05e 4.2s done
|
|
||||||
#12 extracting sha256:75dc09925ca146a3efecc887098f8f1313da0fb1b0c8d36d628b6cae320665ec 0.7s done
|
|
||||||
#12 DONE 7.6s
|
|
||||||
#7 docker-image://ghcr.io/railwayapp/railpack-builder:latest
|
|
||||||
#7 sha256:604add184d03d4cf6e2ff1c4b9013b265eb9c11570afe28ce8f9dc417b98ea3f 237.08MB / 237.08MB 6.1s done
|
|
||||||
#7 sha256:4dc3950125ebc9ed195e1101fc6c02e2fce113ba0f53bfb05b2cdf58747df9af 50.33MB / 67.81MB 5.6s
|
|
||||||
#7 sha256:4dc3950125ebc9ed195e1101fc6c02e2fce113ba0f53bfb05b2cdf58747df9af 54.53MB / 67.81MB 5.9s
|
|
||||||
#7 sha256:4dc3950125ebc9ed195e1101fc6c02e2fce113ba0f53bfb05b2cdf58747df9af 58.72MB / 67.81MB 6.2s
|
|
||||||
#7 extracting sha256:4846f29007305297af653c57bf9b60ba8f676a38695c68d98460063442581671 3.0s done
|
|
||||||
#7 extracting sha256:62fe2e747f69f2f414c7e9eb1553155cf0a658398f0462557f458821dce2b29d
|
|
||||||
#7 sha256:4dc3950125ebc9ed195e1101fc6c02e2fce113ba0f53bfb05b2cdf58747df9af 62.91MB / 67.81MB 6.5s
|
|
||||||
#7 sha256:4dc3950125ebc9ed195e1101fc6c02e2fce113ba0f53bfb05b2cdf58747df9af 67.81MB / 67.81MB 6.9s
|
|
||||||
#7 sha256:4dc3950125ebc9ed195e1101fc6c02e2fce113ba0f53bfb05b2cdf58747df9af 67.81MB / 67.81MB 6.9s done
|
|
||||||
#7 extracting sha256:62fe2e747f69f2f414c7e9eb1553155cf0a658398f0462557f458821dce2b29d 0.9s done
|
|
||||||
#7 extracting sha256:4dc3950125ebc9ed195e1101fc6c02e2fce113ba0f53bfb05b2cdf58747df9af
|
|
||||||
#7 extracting sha256:4dc3950125ebc9ed195e1101fc6c02e2fce113ba0f53bfb05b2cdf58747df9af 2.8s done
|
|
||||||
#7 extracting sha256:4f4fb700ef54461cfa02571ae0db9a0dc1e0cdb5577484a6d75e68dc38e8acc1 done
|
|
||||||
#7 extracting sha256:08a1e03b3da5bb4a1059032dca3216f33ddfc4a48a45db88921f5bb2e9a8fa2d
|
|
||||||
#7 extracting sha256:08a1e03b3da5bb4a1059032dca3216f33ddfc4a48a45db88921f5bb2e9a8fa2d 1.2s done
|
|
||||||
#7 DONE 13.1s
|
|
||||||
#13 install apt packages: libatomic1
|
|
||||||
#13 0.216 Get:1 http://deb.debian.org/debian trixie InRelease [140 kB]
|
|
||||||
#13 0.284 Get:2 http://deb.debian.org/debian trixie-updates InRelease [47.3 kB]
|
|
||||||
#13 0.312 Get:3 http://deb.debian.org/debian-security trixie-security InRelease [43.4 kB]
|
|
||||||
#13 0.340 Get:4 http://deb.debian.org/debian trixie/main amd64 Packages [9678 kB]
|
|
||||||
#13 0.505 Get:5 http://deb.debian.org/debian trixie-updates/main amd64 Packages [720 B]
|
|
||||||
#13 0.531 Get:6 http://deb.debian.org/debian-security trixie-security/main amd64 Packages [270 kB]
|
|
||||||
#13 1.832 Fetched 10.2 MB in 2s (6017 kB/s)
|
|
||||||
#13 1.832 Reading package lists...
|
|
||||||
#13 2.970 Reading package lists...
|
|
||||||
#13 3.978 Building dependency tree...
|
|
||||||
#13 4.187 Reading state information...
|
|
||||||
#13 4.644 The following NEW packages will be installed:
|
|
||||||
#13 4.646 libatomic1
|
|
||||||
#13 4.771 0 upgraded, 1 newly installed, 0 to remove and 3 not upgraded.
|
|
||||||
#13 4.771 Need to get 9308 B of archives.
|
|
||||||
#13 4.771 After this operation, 46.1 kB of additional disk space will be used.
|
|
||||||
#13 4.771 Get:1 http://deb.debian.org/debian trixie/main amd64 libatomic1 amd64 14.2.0-19 [9308 B]
|
|
||||||
#13 4.966 debconf: unable to initialize frontend: Dialog
|
|
||||||
#13 4.966 debconf: (TERM is not set, so the dialog frontend is not usable.)
|
|
||||||
#13 4.966 debconf: falling back to frontend: Readline
|
|
||||||
#13 4.966 debconf: unable to initialize frontend: Readline
|
|
||||||
#13 4.966 debconf: (Can't locate Term/ReadLine.pm in @INC (you may need to install the Term::ReadLine module) (@INC entries checked: /etc/perl /usr/local/lib/x86_64-linux-gnu/perl/5.40.1 /usr/local/share/perl/5.40.1 /usr/lib/x86_64-linux-gnu/perl5/5.40 /usr/share/perl5 /usr/lib/x86_64-linux-gnu/perl-base /usr/lib/x86_64-linux-gnu/perl/5.40 /usr/share/perl/5.40 /usr/local/lib/site_perl) at /usr/share/perl5/Debconf/FrontEnd/Readline.pm line 8, <STDIN> line 1.)
|
|
||||||
#13 4.966 debconf: falling back to frontend: Teletype
|
|
||||||
#13 4.974 debconf: unable to initialize frontend: Teletype
|
|
||||||
#13 4.974 debconf: (This frontend requires a controlling tty.)
|
|
||||||
#13 4.974 debconf: falling back to frontend: Noninteractive
|
|
||||||
#13 6.030 Fetched 9308 B in 0s (98.1 kB/s)
|
|
||||||
#13 6.065 Selecting previously unselected package libatomic1:amd64.
|
|
||||||
#13 6.065 (Reading database ... ␍(Reading database ... 5%␍(Reading database ... 10%␍(Reading database ... 15%␍(Reading database ... 20%␍(Reading database ... 25%␍(Reading database ... 30%␍(Reading database ... 35%␍(Reading database ... 40%␍(Reading database ... 45%␍(Reading database ... 50%␍(Reading database ... 55%␍(Reading database ... 60%␍(Reading database ... 65%␍(Reading database ... 70%␍(Reading database ... 75%␍(Reading database ... 80%␍(Reading database ... 85%␍(Reading database ... 90%␍(Reading database ... 95%␍(Reading database ... 100%␍(Reading database ... 6228 files and directories currently installed.)
|
|
||||||
#13 6.073 Preparing to unpack .../libatomic1_14.2.0-19_amd64.deb ...
|
|
||||||
#13 6.083 Unpacking libatomic1:amd64 (14.2.0-19) ...
|
|
||||||
#13 6.135 Setting up libatomic1:amd64 (14.2.0-19) ...
|
|
||||||
#13 6.144 Processing triggers for libc-bin (2.41-12+deb13u4) ...
|
|
||||||
#13 DONE 7.8s
|
|
||||||
#7 docker-image://ghcr.io/railwayapp/railpack-builder:latest
|
|
||||||
#7 extracting sha256:604add184d03d4cf6e2ff1c4b9013b265eb9c11570afe28ce8f9dc417b98ea3f
|
|
||||||
#7 extracting sha256:604add184d03d4cf6e2ff1c4b9013b265eb9c11570afe28ce8f9dc417b98ea3f 6.9s done
|
|
||||||
#7 DONE 20.0s
|
|
||||||
#7 docker-image://ghcr.io/railwayapp/railpack-builder:latest
|
|
||||||
#7 extracting sha256:df614908d6aba31e983953b17fd48496d27425529b3947c3d5583c4cc9c15c9a 0.0s done
|
|
||||||
#7 extracting sha256:193926ad1d06489b7487e8ac4ae2d0874e6ff05cf65d874d2af508830fc03def done
|
|
||||||
#7 DONE 20.0s
|
|
||||||
#14 mkdir /etc/mise
|
|
||||||
#14 DONE 1.4s
|
|
||||||
#15 create mise config
|
|
||||||
#15 DONE 0.0s
|
|
||||||
#16 install mise packages: bun, node
|
|
||||||
#16 0.094 mise by @jdx – installing 2 tools
|
|
||||||
#16 3.094 mise ███████░░░░░░░░░ 0/2 · 3.0s
|
|
||||||
#16 3.094 bun@1.4.4 downloading 2.6s 6.8/51.8 MB · 3.0 MB/s
|
|
||||||
#16 3.094 node@26.13.0 extracting 2.6s
|
|
||||||
#16 4.859 mise node@26.13.0 v26.13.0
|
|
||||||
#16 5.016 mise node@26.13.0 11.20.0
|
|
||||||
#16 5.044 mise ✓ node@26.13.0 4.5s node-v26.13.0-linux-x64.tar.gz
|
|
||||||
#16 6.094 mise ██████████░░░░░░ 1/2 · 6.0s
|
|
||||||
#16 6.094 bun@1.4.4 downloading 5.6s 19.8/51.8 MB · 3.7 MB/s
|
|
||||||
#16 9.094 mise ███████████░░░░░ 1/2 · 9.0s
|
|
||||||
#16 9.094 bun@1.4.4 downloading 8.6s 34.9/51.8 MB · 4.2 MB/s
|
|
||||||
#16 12.09 mise ██████████████░░ 1/2 · 12.0s
|
|
||||||
#16 12.09 bun@1.4.4 extracting 11.6s
|
|
||||||
#16 12.48 mise bun@1.4.4 1.4.4
|
|
||||||
#16 12.49 mise ✓ bun@1.4.4 12.0s bun-linux-x64.zip
|
|
||||||
#16 12.49 mise ████████████████ 2/2 · installed 2 tools in 12.4s
|
|
||||||
#16 DONE 12.8s
|
|
||||||
#17 copy / /app
|
|
||||||
#17 DONE 0.6s
|
|
||||||
#18 mkdir -p /app/node_modules/.cache
|
|
||||||
#18 DONE 0.2s
|
|
||||||
#19 bun install --frozen-lockfile
|
|
||||||
#19 0.128 bun install v1.4.4 (38afee6c8)
|
|
||||||
#19 ...
|
|
||||||
#20 copy /mise/shims
|
|
||||||
#20 DONE 0.0s
|
|
||||||
#21 copy /mise/installs
|
|
||||||
#21 DONE 8.7s
|
|
||||||
#19 bun install --frozen-lockfile
|
|
||||||
#19 ...
|
|
||||||
#22 copy /usr/local/bin/mise
|
|
||||||
#22 DONE 0.6s
|
|
||||||
#19 bun install --frozen-lockfile
|
|
||||||
#19 ...
|
|
||||||
#23 copy /etc/mise/config.toml
|
|
||||||
#23 DONE 0.1s
|
|
||||||
#24 copy /root/.local/state/mise
|
|
||||||
#24 DONE 0.1s
|
|
||||||
#19 bun install --frozen-lockfile
|
|
||||||
#19 14.16
|
|
||||||
#19 14.17 $ prisma generate || true
|
|
||||||
#19 16.10 Prisma schema loaded from prisma/schema.prisma
|
|
||||||
#19 16.88
|
|
||||||
#19 16.88 ✔ Generated Prisma Client (v6.19.2) to ./node_modules/@prisma/client in 385ms
|
|
||||||
#19 16.88
|
|
||||||
#19 16.88 Start by importing your Prisma Client (See: https://pris.ly/d/importing-client)
|
|
||||||
#19 16.88
|
|
||||||
#19 16.88 Tip: Interested in query caching in just a few lines of code? Try Accelerate today! https://pris.ly/tip-3-accelerate
|
|
||||||
#19 16.88
|
|
||||||
#19 17.02
|
|
||||||
#19 17.02 + @tailwindcss/postcss@4.1.18
|
|
||||||
#19 17.02 + @types/react@19.2.8
|
|
||||||
#19 17.02 + @types/react-dom@19.2.3
|
|
||||||
#19 17.02 + bun-types@1.3.6
|
|
||||||
#19 17.02 + eslint@9.39.2
|
|
||||||
#19 17.02 + eslint-config-next@16.1.3
|
|
||||||
#19 17.02 + tailwindcss@4.1.18
|
|
||||||
#19 17.02 + tw-animate-css@1.4.0
|
|
||||||
#19 17.02 + typescript@5.9.3
|
|
||||||
#19 17.02 + @dnd-kit/core@6.3.1
|
|
||||||
#19 17.02 + @dnd-kit/sortable@10.0.0
|
|
||||||
#19 17.02 + @dnd-kit/utilities@3.2.2
|
|
||||||
#19 17.02 + @hookform/resolvers@5.2.2
|
|
||||||
#19 17.02 + @hugeicons/core-free-icons@4.3.5
|
|
||||||
#19 17.02 + @hugeicons/react@1.1.10
|
|
||||||
#19 17.02 + @mdxeditor/editor@3.52.3
|
|
||||||
#19 17.02 + @prisma/client@6.19.2
|
|
||||||
#19 17.02 + @radix-ui/react-accordion@1.2.12
|
|
||||||
#19 17.02 + @radix-ui/react-alert-dialog@1.1.15
|
|
||||||
#19 17.02 + @radix-ui/react-aspect-ratio@1.1.8
|
|
||||||
#19 17.02 + @radix-ui/react-avatar@1.1.11
|
|
||||||
#19 17.02 + @radix-ui/react-checkbox@1.3.3
|
|
||||||
#19 17.02 + @radix-ui/react-collapsible@1.1.12
|
|
||||||
#19 17.02 + @radix-ui/react-context-menu@2.2.16
|
|
||||||
#19 17.02 + @radix-ui/react-dialog@1.1.15
|
|
||||||
#19 17.02 + @radix-ui/react-dropdown-menu@2.1.16
|
|
||||||
#19 17.02 + @radix-ui/react-hover-card@1.1.15
|
|
||||||
#19 17.02 + @radix-ui/react-label@2.1.8
|
|
||||||
#19 17.02 + @radix-ui/react-menubar@1.1.16
|
|
||||||
#19 17.02 + @radix-ui/react-navigation-menu@1.2.14
|
|
||||||
#19 17.02 + @radix-ui/react-popover@1.1.15
|
|
||||||
#19 17.02 + @radix-ui/react-progress@1.1.8
|
|
||||||
#19 17.02 + @radix-ui/react-radio-group@1.3.8
|
|
||||||
#19 17.02 + @radix-ui/react-scroll-area@1.2.10
|
|
||||||
#19 17.02 + @radix-ui/react-select@2.2.6
|
|
||||||
#19 17.02 + @radix-ui/react-separator@1.1.8
|
|
||||||
#19 17.02 + @radix-ui/react-slider@1.3.6
|
|
||||||
#19 17.02 + @radix-ui/react-slot@1.2.4
|
|
||||||
#19 17.02 + @radix-ui/react-switch@1.2.6
|
|
||||||
#19 17.02 + @radix-ui/react-tabs@1.1.13
|
|
||||||
#19 17.02 + @radix-ui/react-toast@1.2.15
|
|
||||||
#19 17.02 + @radix-ui/react-toggle@1.1.10
|
|
||||||
#19 17.02 + @radix-ui/react-toggle-group@1.1.11
|
|
||||||
#19 17.02 + @radix-ui/react-tooltip@1.2.8
|
|
||||||
#19 17.02 + @reactuses/core@6.1.9
|
|
||||||
#19 17.02 + @tanstack/react-query@5.90.19
|
|
||||||
#19 17.02 + @tanstack/react-table@8.21.3
|
|
||||||
#19 17.02 + class-variance-authority@0.7.1
|
|
||||||
#19 17.02 + clsx@2.1.1
|
|
||||||
#19 17.02 + cmdk@1.1.1
|
|
||||||
#19 17.02 + date-fns@4.1.0
|
|
||||||
#19 17.02 + embla-carousel-react@8.6.0
|
|
||||||
#19 17.02 + framer-motion@14.7.1
|
|
||||||
#19 17.02 + imapflow@2.9.1
|
|
||||||
#19 17.02 + input-otp@1.4.2
|
|
||||||
#19 17.02 + lucide-react@1.62.0
|
|
||||||
#19 17.02 + motion@12.43.0
|
|
||||||
#19 17.02 + next@16.1.3
|
|
||||||
#19 17.02 + next-auth@4.24.13
|
|
||||||
#19 17.02 + next-intl@4.7.0
|
|
||||||
#19 17.02 + next-themes@0.4.6
|
|
||||||
#19 17.02 + prisma@6.19.2
|
|
||||||
#19 17.02 + react@19.2.3
|
|
||||||
#19 17.02 + react-day-picker@9.13.0
|
|
||||||
#19 17.02 + react-dom@19.2.3
|
|
||||||
#19 17.02 + react-hook-form@7.71.1
|
|
||||||
#19 17.02 + react-markdown@10.1.0
|
|
||||||
#19 17.02 + react-resizable-panels@3.0.6
|
|
||||||
#19 17.02 + react-syntax-highlighter@15.6.6
|
|
||||||
#19 17.02 + recharts@2.15.4
|
|
||||||
#19 17.02 + sharp@0.34.5
|
|
||||||
#19 17.02 + sonner@2.0.7
|
|
||||||
#19 17.02 + tailwind-merge@3.7.0
|
|
||||||
#19 17.02 + tailwindcss-animate@1.0.7
|
|
||||||
#19 17.02 + uuid@11.1.0
|
|
||||||
#19 17.02 + vaul@1.1.2
|
|
||||||
#19 17.02 + z-ai-web-dev-sdk@0.0.18
|
|
||||||
#19 17.02 + zod@4.3.5
|
|
||||||
#19 17.02 + zustand@5.0.10
|
|
||||||
#19 17.02
|
|
||||||
#19 17.02 858 packages installed [16.89s]
|
|
||||||
#19 DONE 18.8s
|
|
||||||
#25 copy / /app
|
|
||||||
#25 DONE 9.1s
|
|
||||||
#26 bun run build
|
|
||||||
#26 0.237 $ prisma generate && next build && cp -r .next/static .next/standalone/.next/ && cp -r public .next/standalone/
|
|
||||||
#26 1.867 Prisma schema loaded from prisma/schema.prisma
|
|
||||||
#26 2.793 ┌─────────────────────────────────────────────────────────┐
|
|
||||||
#26 2.793 │ Update available 6.19.2 -> 8.0.0-rc.28 │
|
|
||||||
#26 2.793 │ │
|
|
||||||
#26 2.793 │ This is a major update - please follow the guide at │
|
|
||||||
#26 2.793 │ https://pris.ly/d/major-version-upgrade │
|
|
||||||
#26 2.793 │ │
|
|
||||||
#26 2.793 │ Run the following to update │
|
|
||||||
#26 2.793 │ npm i --save-dev prisma@latest │
|
|
||||||
#26 2.793 │ npm i @prisma/client@latest │
|
|
||||||
#26 2.793 └─────────────────────────────────────────────────────────┘
|
|
||||||
#26 2.794
|
|
||||||
#26 2.794 ✔ Generated Prisma Client (v6.19.2) to ./node_modules/@prisma/client in 473ms
|
|
||||||
#26 2.794
|
|
||||||
#26 2.794 Start by importing your Prisma Client (See: https://pris.ly/d/importing-client)
|
|
||||||
#26 2.794
|
|
||||||
#26 2.794 Tip: Interested in query caching in just a few lines of code? Try Accelerate today! https://pris.ly/tip-3-accelerate
|
|
||||||
#26 2.794
|
|
||||||
#26 3.028 ⚠ You are using a non-standard "NODE_ENV" value in your environment. This creates inconsistencies in the project and is strongly advised against. Read more: https://nextjs.org/docs/messages/non-standard-node-env
|
|
||||||
#26 5.015 ▲ Next.js 16.1.3 (Turbopack)
|
|
||||||
#26 5.016
|
|
||||||
#26 5.180 Creating an optimized production build ...
|
|
||||||
#26 13.50 (node:123) [DEP0205] DeprecationWarning: `module.register()` is deprecated. Use `module.registerHooks()` instead.
|
|
||||||
#26 13.50 (Use `node --trace-deprecation ...` to show where the warning was created)
|
|
||||||
#26 31.44 ✓ Compiled successfully in 25.1s
|
|
||||||
#26 31.45 Skipping validation of types
|
|
||||||
#26 31.84 Collecting page data using 3 workers ...
|
|
||||||
#26 33.48 Generating static pages using 3 workers (0/4) ...
|
|
||||||
#26 33.60 Generating static pages using 3 workers (1/4)
|
|
||||||
#26 33.71 Each child in a list should have a unique "key" prop.
|
|
||||||
#26 33.71
|
|
||||||
#26 33.71 Check the top-level render call using <__next_viewport_boundary__>. See https://react.dev/link/warning-keys for more information.
|
|
||||||
#26 33.72 Each child in a list should have a unique "key" prop.
|
|
||||||
#26 33.72
|
|
||||||
#26 33.72 Check the top-level render call using <M>. See https://react.dev/link/warning-keys for more information.
|
|
||||||
#26 33.73 Each child in a list should have a unique "key" prop.
|
|
||||||
#26 33.73
|
|
||||||
#26 33.73 Check the top-level render call using <meta>. See https://react.dev/link/warning-keys for more information.
|
|
||||||
#26 33.73 Each child in a list should have a unique "key" prop.
|
|
||||||
#26 33.73
|
|
||||||
#26 33.73 Check the top-level render call using <head>. See https://react.dev/link/warning-keys for more information.
|
|
||||||
#26 33.76 Each child in a list should have a unique "key" prop.
|
|
||||||
#26 33.76
|
|
||||||
#26 33.76 Check the top-level render call using <meta>. See https://react.dev/link/warning-keys for more information.
|
|
||||||
#26 33.76 Each child in a list should have a unique "key" prop.
|
|
||||||
#26 33.76
|
|
||||||
#26 33.76 Check the top-level render call using <html>. See https://react.dev/link/warning-keys for more information.
|
|
||||||
#26 33.77 Each child in a list should have a unique "key" prop.
|
|
||||||
#26 33.77
|
|
||||||
#26 33.77 Check the top-level render call using <meta>. See https://react.dev/link/warning-keys for more information.
|
|
||||||
#26 33.77 Each child in a list should have a unique "key" prop.
|
|
||||||
#26 33.77
|
|
||||||
#26 33.77 Check the top-level render call using <head>. See https://react.dev/link/warning-keys for more information.
|
|
||||||
#26 33.84 Each child in a list should have a unique "key" prop.
|
|
||||||
#26 33.84
|
|
||||||
#26 33.84 Check the top-level render call using <__next_viewport_boundary__>. See https://react.dev/link/warning-keys for more information.
|
|
||||||
#26 33.84 Each child in a list should have a unique "key" prop.
|
|
||||||
#26 33.84
|
|
||||||
#26 33.84 Check the top-level render call using <html>. See https://react.dev/link/warning-keys for more information.
|
|
||||||
#26 33.84 Each child in a list should have a unique "key" prop.
|
|
||||||
#26 33.84
|
|
||||||
#26 33.84 Check the top-level render call using <meta>. See https://react.dev/link/warning-keys for more information.
|
|
||||||
#26 33.84 Each child in a list should have a unique "key" prop.
|
|
||||||
#26 33.84
|
|
||||||
#26 33.84 Check the top-level render call using <head>. See https://react.dev/link/warning-keys for more information.
|
|
||||||
#26 33.86 Error occurred prerendering page "/_global-error". Read more: https://nextjs.org/docs/messages/prerender-error
|
|
||||||
#26 33.86 TypeError: Cannot read properties of null (reading 'useContext')
|
|
||||||
#26 33.86 at ignore-listed frames {
|
|
||||||
#26 33.86 digest: '1499178773'
|
|
||||||
#26 33.86 }
|
|
||||||
#26 33.86 Export encountered an error on /_global-error/page: /_global-error, exiting the build.
|
|
||||||
#26 33.91 ⨯ Next.js build worker exited with code: 1 and signal: null
|
|
||||||
#26 33.98 error: script "build" exited with code 1
|
|
||||||
#26 ERROR: process "bun run build" did not complete successfully: exit code: 1
|
|
||||||
------
|
|
||||||
> bun run build:
|
|
||||||
33.84
|
|
||||||
33.84 Check the top-level render call using <head>. See https://react.dev/link/warning-keys for more information.
|
|
||||||
33.86 Error occurred prerendering page "/_global-error". Read more: https://nextjs.org/docs/messages/prerender-error
|
|
||||||
33.86 TypeError: Cannot read properties of null (reading 'useContext')
|
|
||||||
33.86 at ignore-listed frames {
|
|
||||||
33.86 digest: '1499178773'
|
|
||||||
33.86 }
|
|
||||||
33.86 Export encountered an error on /_global-error/page: /_global-error, exiting the build.
|
|
||||||
33.91 ⨯ Next.js build worker exited with code: 1 and signal: null
|
|
||||||
33.98 error: script "build" exited with code 1
|
|
||||||
------
|
|
||||||
ERROR: failed to build: failed to solve: process "bun run build" did not complete successfully: exit code: 1
|
|
||||||
❌ Railpack build failed
|
|
||||||
railpack-dfm-aos-lgbcnc-VqdRBM removed
|
|
||||||
Error occurred ❌, check the logs for details.
|
|
||||||
Reference in new issue
Block a user