merge: resolve Dockerfile conflicts between stg and deploy/stg

- Keep optimized multi-stage build from stg
- Add gen:api step from deploy/stg
- Maintain security best practices (non-root user, minimal deps)

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
This commit is contained in:
2026-04-06 14:33:30 +08:00
6 changed files with 82 additions and 27 deletions

47
.dockerignore Normal file
View File

@@ -0,0 +1,47 @@
node_modules
.next
.git
.env
.env.local
.env.development.local
.env.test.local
.env.production.local
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
bun-debug.log*
# Docker files
Dockerfile
.dockerignore
# OS files
.DS_Store
Thumbs.db
# Markdown/Documentation
README.md
GEMINI.md
AGENTS.md
AUDIT_REPORT.md
QWEN.md
NOTE.md
task-project-apbdes.md
MUSIK_CREATE_ANALYSIS.md
darkMode.md
/test-results
/playwright-report
/tmp_assets
/foldergambar
/googleapi
/xx
/xx.ts
/xx.txt
/test.txt
/x.json
/x.sh
/xcoba.ts
/xcoba2.ts
/gambar.ttx
/test-berita-state.ts

View File

@@ -26,6 +26,9 @@ RUN cp .env.example .env || true
ENV PRISMA_CLI_BINARY_TARGETS=debian-openssl-3.0.x
RUN bunx prisma generate
# Generate API types
RUN bun run gen:api || echo "tidak ada gen api"
RUN bun run build
# ==============================
@@ -65,4 +68,4 @@ EXPOSE 3000
ENV PORT=3000
ENV HOSTNAME="0.0.0.0"
CMD ["bun", "start"]
CMD ["bun", "start"]

1
eror.md Normal file

File diff suppressed because one or more lines are too long

View File

@@ -121,7 +121,7 @@
"@types/react-dom": "^19",
"@vitest/ui": "^4.0.18",
"eslint": "^9",
"eslint-config-next": "15.1.6",
"eslint-config-next": "15.5.12",
"jsdom": "^28.0.0",
"msw": "^2.12.9",
"parcel": "^2.6.2",

View File

@@ -6,13 +6,6 @@ import { sendCodeOtp } from "../_lib/sendCodeOtp";
import { cookies } from "next/headers";
export async function POST(req: Request) {
if (req.method !== "POST") {
return NextResponse.json(
{ success: false, message: "Method Not Allowed" },
{ status: 405 }
);
}
try {
const { nomor } = await req.json();
@@ -43,18 +36,26 @@ export async function POST(req: Request) {
});
if (!waResponse.ok) {
console.error(`⚠️ WA Service HTTP Error: ${waResponse.status} ${waResponse.statusText}. Continuing since OTP is logged.`);
console.error(
`⚠️ WA Service HTTP Error: ${waResponse.status} ${waResponse.statusText}. Continuing since OTP is logged.`
);
console.log(`💡 Use this OTP to login: ${codeOtp}`);
} else {
const sendWa = await waResponse.json();
console.log("📱 WA Response:", sendWa);
if (sendWa.status !== "success") {
console.error("⚠️ WA Service Logic Error:", sendWa);
}
}
} catch (waError: unknown) {
const errorMessage = waError instanceof Error ? waError.message : String(waError);
console.error("⚠️ WA Connection Exception. Continuing since OTP is logged.", errorMessage);
const errorMessage =
waError instanceof Error ? waError.message : String(waError);
console.error(
"⚠️ WA Connection Exception. Continuing since OTP is logged.",
errorMessage
);
}
const createOtpId = await prisma.kodeOtp.create({
@@ -62,12 +63,12 @@ export async function POST(req: Request) {
});
const cookieStore = await cookies();
cookieStore.set('auth_flow', 'login', {
cookieStore.set("auth_flow", "login", {
httpOnly: true,
secure: process.env.NODE_ENV === 'production',
sameSite: 'lax',
maxAge: 60 * 5, // 5 menit
path: '/'
secure: process.env.NODE_ENV === "production",
sameSite: "lax",
maxAge: 60 * 5,
path: "/",
});
return NextResponse.json({
@@ -85,6 +86,7 @@ export async function POST(req: Request) {
}
} catch (error) {
console.error("❌ Error Login:", error);
return NextResponse.json(
{ success: false, message: "Terjadi kesalahan saat login" },
{ status: 500 }

View File

@@ -29,16 +29,18 @@ process.on('unhandledRejection', async (error) => {
});
// Handle graceful shutdown
process.on('SIGINT', async () => {
console.log('Received SIGINT signal. Closing database connections...');
await prisma.$disconnect();
process.exit(0);
});
if (process.env.NODE_ENV === 'production' && !process.env.NEXT_PHASE) {
process.on('SIGINT', async () => {
console.log('Received SIGINT signal. Closing database connections...');
await prisma.$disconnect();
// Allow natural exit
});
process.on('SIGTERM', async () => {
console.log('Received SIGTERM signal. Closing database connections...');
await prisma.$disconnect();
process.exit(0);
});
process.on('SIGTERM', async () => {
console.log('Received SIGTERM signal. Closing database connections...');
await prisma.$disconnect();
// Allow natural exit
});
}
export default prisma;