diff --git a/DEPLOYMENT_FIXES.md b/DEPLOYMENT_FIXES.md index 2f7ce4c..1ae0fa9 100644 --- a/DEPLOYMENT_FIXES.md +++ b/DEPLOYMENT_FIXES.md @@ -154,20 +154,45 @@ RUN npm run build - `Dockerfile` - Build process improvements - Various form components - File handling updates -The combination of these changes resolved all deployment issues and enabled successful containerized deployment with Portainer and nginx-proxy-manager integration. The combination of these changes resolved all deployment issues and enabled successful containerized deployment with Portainer and nginx-proxy-manager integration. -The combination of these changes resolved all deployment issues and enabled successful containerized deployment with Portainer and nginx-proxy-manager integration. +# CI/CD Guide: Free Setup with Database Persistence -The combination of these changes resolved alsl deployment issues and enabled successful containerized deployment with Portainer and nginx-proxy-manager integration. +## Overview +This guide explains how to set up a completely free CI/CD pipeline using open-source tools and addresses database persistence concerns when deploying containerized applications. -The combination of these changes resolved all deployment issues and enabled successful containerized deployment with Portainer and nginx-proxy-manager integration. +## Free CI/CD Solutions (No Portainer Webhooks Needed) -The combination of these changes resolved all deployment issues and enabled successful containerized deployment with Portainer and nginx-proxy-manager integration. +### Option 1: Gitea Actions (Recommended) +Since you already have Gitea and a runner container: -The combination of these changes resolved all deployment issues and enabled successful containerized deployment with Portainer and nginx-proxy-manager integration. +**How it works:** +1. **Gitea Actions** (built into Gitea) works like GitHub Actions +2. Your runner container executes workflows defined in `.gitea/workflows/*.yml` +3. On push to main branch → workflow triggers → builds Docker image → deploys directly to your server -The combination of these changes resolved all deployment issues and enabled successful containerized deployment with Portainer and nginx-proxy-manager integration. +**Deployment Methods:** +- **SSH Deployment**: Workflow SSHs into your server and runs `docker-compose up -d` +- **Docker API**: Direct API calls to Docker daemon on your server +- **Docker Swarm**: Use `docker service update` for rolling updates +- **Simple Container Restart**: Pull new image and restart containers -The combination of these changes resolved all deployment issues and enabled successful containerized deployment with Portainer and nginx-proxy-manager integration. +### Option 2: Other Free Alternatives +- **Drone CI**: Lightweight, Docker-native CI/CD +- **Jenkins**: Classic option, can run in Docker +- **GitLab CE**: Self-hosted with built-in CI/CD +- **Woodpecker CI**: Fork of Drone, simpler setup + +### Option 3: Simple Script-Based Approach +- **Git Hooks**: Post-receive hook on your Git server +- **Cron + Git Pull**: Simple script that checks for updates +- **Webhook Alternatives**: Use free services like webhook.site or build simple webhook receiver + +## Database Persistence (Your Data is Safe! 🎉) + +**Short Answer:** You will NOT lose database data when rebuilding your app image. + +**Here's why:** + +### Container vs Data Separation diff --git a/src/app/error.tsx b/src/app/error.tsx index 5989b88..af60a55 100644 --- a/src/app/error.tsx +++ b/src/app/error.tsx @@ -12,11 +12,6 @@ interface ErrorPageProps { } const ErrorPage = ({ error, reset }: ErrorPageProps) => { - console.error('🔥 ERROR PAGE: Error caught:', error); - console.error('🔥 ERROR PAGE: Error message:', error?.message); - console.error('🔥 ERROR PAGE: Error stack:', error?.stack); - console.error('🔥 ERROR PAGE: Error digest:', error?.digest); - return (
diff --git a/src/app/layout.tsx b/src/app/layout.tsx index a25989c..50d7959 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -6,8 +6,6 @@ import { Toaster } from "@/components/ui/sonner"; import { ClientErrorHandler } from "@/components/client-error-handler"; import "./globals.css"; -console.log('🔥 LAYOUT: Root layout module loading...') - const geistSans = localFont({ src: "./fonts/GeistVF.woff", variable: "--font-geist-sans", @@ -32,8 +30,6 @@ export default function RootLayout({ }: Readonly<{ children: React.ReactNode; }>) { - console.log('🔥 LAYOUT: Root layout component rendering...') - try { return ( @@ -53,7 +49,6 @@ export default function RootLayout({ ); } catch (error) { - console.error('🔥 LAYOUT ERROR:', error) throw error } } diff --git a/src/auth.ts b/src/auth.ts index 839ac2b..3c9fa8c 100644 --- a/src/auth.ts +++ b/src/auth.ts @@ -7,8 +7,6 @@ import { ZodError } from "zod"; import { loginSchema } from "./features/auth/schemas"; import AuthentikProvider from "next-auth/providers/authentik"; -console.log('🔥 AUTH: Auth configuration loading...') - export const { handlers, signIn, signOut, auth } = NextAuth({ adapter: PrismaAdapter(prisma), providers: [ @@ -21,7 +19,6 @@ export const { handlers, signIn, signOut, auth } = NextAuth({ issuer: "https://authentik.lci.ge/application/o/jira/", checks: ["pkce", "state"], profile(profile) { - console.log('🔥 AUTH: Authentik profile received:', profile) return { id: profile.sub, name: profile.name || profile.preferred_username, @@ -36,15 +33,12 @@ export const { handlers, signIn, signOut, auth } = NextAuth({ password: { label: "Password", type: "password" }, }, authorize: async (credentials) => { - console.log('🔥 AUTH: Credentials authorize called') try { if (!credentials?.email || !credentials?.password) { - console.log('🔥 AUTH: Missing credentials') return null; } const { email, password } = await loginSchema.parseAsync(credentials); - console.log('🔥 AUTH: Looking up user:', email) const user = await prisma.user.findUnique({ where: { @@ -53,7 +47,6 @@ export const { handlers, signIn, signOut, auth } = NextAuth({ }); if (!user || !user.hashedPassword) { - console.log("🔥 AUTH: User not found or no password"); return null; } @@ -63,18 +56,15 @@ export const { handlers, signIn, signOut, auth } = NextAuth({ ); if (!passwordsMatch) { - console.log("🔥 AUTH: Passwords don't match"); return null; } - console.log("🔥 AUTH: User authenticated successfully:", user.id); return { id: user.id, email: user.email, name: user.name }; } catch (error) { - console.error("🔥 AUTH ERROR:", error); return null; } }, @@ -85,18 +75,14 @@ export const { handlers, signIn, signOut, auth } = NextAuth({ debug: process.env.NODE_ENV === "development", secret: process.env.AUTH_SECRET || "your-fallback-secret-for-development", callbacks: { - session: ({ session, token }) => { - console.log('🔥 AUTH: Session callback called') - return { - ...session, - user: { - ...session.user, - id: token.id, - }, - } - }, + session: ({ session, token }) => ({ + ...session, + user: { + ...session.user, + id: token.id as string, + }, + }), jwt: ({ token, user }) => { - console.log('🔥 AUTH: JWT callback called') if (user) { token.id = user.id; } @@ -105,8 +91,6 @@ export const { handlers, signIn, signOut, auth } = NextAuth({ }, }); -console.log('🔥 AUTH: Auth configuration completed') - export const authOptions = { adapter: PrismaAdapter(prisma), providers: [Credentials], diff --git a/src/components/client-error-handler.tsx b/src/components/client-error-handler.tsx index df62412..bb9462f 100644 --- a/src/components/client-error-handler.tsx +++ b/src/components/client-error-handler.tsx @@ -4,17 +4,12 @@ import { useEffect } from 'react'; export const ClientErrorHandler = () => { useEffect(() => { - console.log('🔥 CLIENT: Setting up global error handlers...'); - const handleError = (event: ErrorEvent) => { - console.error('🔥 CLIENT ERROR:', event.error); - console.error('🔥 CLIENT ERROR Stack:', event.error?.stack); - console.error('🔥 CLIENT ERROR Message:', event.message); - console.error('🔥 CLIENT ERROR Source:', event.filename, 'Line:', event.lineno); + // Handle client-side errors silently }; const handleUnhandledRejection = (event: PromiseRejectionEvent) => { - console.error('🔥 CLIENT UNHANDLED PROMISE REJECTION:', event.reason); + // Handle unhandled promise rejections silently }; window.addEventListener('error', handleError);