From 67ba2de3358a7f9e7b9550ee2e33bf60927d1ffa Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 9 Jul 2025 02:15:35 +0530 Subject: [PATCH] first working --- ...te Next.js-Supabase Development Guide 2025 | 1535 +++++++++++++++++ Simplified Hardcoded Agent Pages Plan | 119 ++ {apps/agents => agents}/__init__.py | 0 agents/admin.py | 26 + {apps/agents => agents}/agent_processors.py | 3 +- {apps/agents => agents}/apps.py | 0 .../management}/__init__.py | 0 .../management/commands}/__init__.py | 0 agents/management/commands/populate_agents.py | 91 + .../migrations/0001_initial.py | 2 +- .../migrations/__init__.py | 0 {apps/agents => agents}/models.py | 5 +- {apps/agents => agents}/tests.py | 0 {apps/agents => agents}/views.py | 0 .../management/commands/populate_agents.py | 80 - apps/agents/urls.py | 7 - apps/authentication/admin.py | 3 - apps/authentication/urls.py | 24 - apps/authentication/views.py | 16 - apps/core/admin.py | 3 - apps/core/urls.py | 17 - apps/core/views.py | 452 ----- apps/wallet/admin.py | 3 - apps/wallet/stripe_handler.py | 72 - apps/wallet/urls.py | 9 - apps/wallet/views.py | 76 - {apps/core => authentication}/__init__.py | 0 authentication/admin.py | 22 + .../authentication => authentication}/apps.py | 0 .../migrations/0001_initial.py | 2 +- .../migrations/__init__.py | 0 .../models.py | 2 +- .../tests.py | 0 authentication/urls.py | 9 + authentication/views.py | 103 ++ {apps/wallet => core}/__init__.py | 0 {apps/agents => core}/admin.py | 0 {apps/core => core}/apps.py | 0 {apps/wallet => core}/migrations/__init__.py | 0 {apps/core => core}/models.py | 0 {apps/core => core}/tests.py | 0 core/urls.py | 12 + core/views.py | 229 +++ future agent creation | 48 + netcop_hub/settings.py | 88 +- netcop_hub/urls.py | 23 +- requirements.txt | 8 - static/favicon.png | Bin 1647 -> 0 bytes templates/agent_detail.html | 485 ------ templates/authentication/login.html | 60 + templates/authentication/profile.html | 97 ++ templates/authentication/register.html | 70 + templates/base.html | 74 - templates/core/agent_detail.html | 118 ++ templates/core/homepage.html | 85 + templates/core/wallet.html | 68 + templates/core/wallet_topup.html | 97 ++ templates/debug.html | 36 - templates/homepage.html | 1039 ----------- templates/marketplace.html | 45 - templates/reset_password.html | 58 - test_views.py | 34 + wallet/__init__.py | 0 wallet/admin.py | 31 + {apps/wallet => wallet}/apps.py | 0 .../migrations/0001_initial.py | 2 +- wallet/migrations/__init__.py | 0 {apps/wallet => wallet}/models.py | 2 +- wallet/stripe_handler.py | 106 ++ {apps/wallet => wallet}/tests.py | 0 wallet/views.py | 3 + 71 files changed, 3071 insertions(+), 2528 deletions(-) create mode 100644 Complete Next.js-Supabase Development Guide 2025 create mode 100644 Simplified Hardcoded Agent Pages Plan rename {apps/agents => agents}/__init__.py (100%) create mode 100644 agents/admin.py rename {apps/agents => agents}/agent_processors.py (99%) rename {apps/agents => agents}/apps.py (100%) rename {apps/agents/migrations => agents/management}/__init__.py (100%) rename {apps/authentication => agents/management/commands}/__init__.py (100%) create mode 100644 agents/management/commands/populate_agents.py rename {apps/agents => agents}/migrations/0001_initial.py (96%) rename {apps/authentication => agents}/migrations/__init__.py (100%) rename {apps/agents => agents}/models.py (97%) rename {apps/agents => agents}/tests.py (100%) rename {apps/agents => agents}/views.py (100%) delete mode 100644 apps/agents/management/commands/populate_agents.py delete mode 100644 apps/agents/urls.py delete mode 100644 apps/authentication/admin.py delete mode 100644 apps/authentication/urls.py delete mode 100644 apps/authentication/views.py delete mode 100644 apps/core/admin.py delete mode 100644 apps/core/urls.py delete mode 100644 apps/core/views.py delete mode 100644 apps/wallet/admin.py delete mode 100644 apps/wallet/stripe_handler.py delete mode 100644 apps/wallet/urls.py delete mode 100644 apps/wallet/views.py rename {apps/core => authentication}/__init__.py (100%) create mode 100644 authentication/admin.py rename {apps/authentication => authentication}/apps.py (100%) rename {apps/authentication => authentication}/migrations/0001_initial.py (98%) rename {apps/core => authentication}/migrations/__init__.py (100%) rename {apps/authentication => authentication}/models.py (98%) rename {apps/authentication => authentication}/tests.py (100%) create mode 100644 authentication/urls.py create mode 100644 authentication/views.py rename {apps/wallet => core}/__init__.py (100%) rename {apps/agents => core}/admin.py (100%) rename {apps/core => core}/apps.py (100%) rename {apps/wallet => core}/migrations/__init__.py (100%) rename {apps/core => core}/models.py (100%) rename {apps/core => core}/tests.py (100%) create mode 100644 core/urls.py create mode 100644 core/views.py create mode 100644 future agent creation delete mode 100644 requirements.txt delete mode 100644 static/favicon.png delete mode 100644 templates/agent_detail.html create mode 100644 templates/authentication/login.html create mode 100644 templates/authentication/profile.html create mode 100644 templates/authentication/register.html delete mode 100644 templates/base.html create mode 100644 templates/core/agent_detail.html create mode 100644 templates/core/homepage.html create mode 100644 templates/core/wallet.html create mode 100644 templates/core/wallet_topup.html delete mode 100644 templates/debug.html delete mode 100644 templates/homepage.html delete mode 100644 templates/marketplace.html delete mode 100644 templates/reset_password.html create mode 100644 test_views.py create mode 100644 wallet/__init__.py create mode 100644 wallet/admin.py rename {apps/wallet => wallet}/apps.py (100%) rename {apps/wallet => wallet}/migrations/0001_initial.py (96%) create mode 100644 wallet/migrations/__init__.py rename {apps/wallet => wallet}/models.py (100%) create mode 100644 wallet/stripe_handler.py rename {apps/wallet => wallet}/tests.py (100%) create mode 100644 wallet/views.py diff --git a/Complete Next.js-Supabase Development Guide 2025 b/Complete Next.js-Supabase Development Guide 2025 new file mode 100644 index 0000000..0d3ee14 --- /dev/null +++ b/Complete Next.js-Supabase Development Guide 2025 @@ -0,0 +1,1535 @@ +# Complete Next.js + Supabase Development Guide 2025 + +**A comprehensive, standalone guide for building production-ready applications with Next.js 15 and Supabase** + +This guide covers everything from project setup to deployment, including authentication, database operations, TypeScript integration, and modern best practices. Perfect for beginners and as a reference for experienced developers. + +--- + +## Table of Contents +1. [Prerequisites & Initial Setup](#prerequisites--initial-setup) +2. [Project Creation & Configuration](#project-creation--configuration) +3. [Supabase Integration](#supabase-integration) +4. [Project Structure](#project-structure) +5. [Database Schema & Security](#database-schema--security) +6. [Authentication Implementation](#authentication-implementation) +7. [CRUD Operations](#crud-operations) +8. [UI Components & Styling](#ui-components--styling) +9. [Error Handling & Loading States](#error-handling--loading-states) +10. [TypeScript Configuration](#typescript-configuration) +11. [Deployment & Production](#deployment--production) +12. [Complete Code Examples](#complete-code-examples) + +--- + +## Prerequisites & Initial Setup + +### System Requirements +- **Node.js**: 18.17.0 or higher +- **npm**: 9.0.0 or higher (or yarn/pnpm equivalent) +- **Git**: For version control +- **Code Editor**: VS Code recommended + +### Version Requirements (2025) +- **Next.js**: 15.x (latest) +- **React**: 19 RC +- **Supabase JS**: 2.50.1+ +- **TypeScript**: 5.1.3+ +- **Tailwind CSS**: 4.x + +### Supabase Account Setup +1. Go to [supabase.com](https://supabase.com) +2. Sign up for a free account +3. Create a new project +4. Choose a database password (save it securely) +5. Wait for project initialization (~2 minutes) + +--- + +## Project Creation & Configuration + +### 1. Create Next.js Application + +```bash +npx create-next-app@latest my-supabase-app +``` + +**Choose these options when prompted:** +``` +✓ Would you like to use TypeScript? → Yes +✓ Would you like to use ESLint? → Yes +✓ Would you like to use Tailwind CSS? → Yes +✓ Would you like to use `src/` directory? → Yes +✓ Would you like to use App Router? → Yes +✓ Would you like to use Turbopack for `next dev`? → Yes +✓ Would you like to customize the default import alias (@/*)? → Yes +``` + +### 2. Navigate to Project & Install Dependencies + +```bash +cd my-supabase-app +npm install @supabase/supabase-js @supabase/ssr +``` + +**Important**: Don't install `@supabase/auth-helpers-nextjs` - it's deprecated. Use `@supabase/ssr` instead. + +### 3. Environment Variables Setup + +Create `.env.local` in your project root: + +```env +# Supabase Configuration +NEXT_PUBLIC_SUPABASE_URL=your_supabase_project_url +NEXT_PUBLIC_SUPABASE_ANON_KEY=your_supabase_anon_key + +# Optional: For admin operations (keep secure, never expose to client) +SUPABASE_SERVICE_ROLE_KEY=your_service_role_key +``` + +**To find your Supabase credentials:** +1. Go to your Supabase project dashboard +2. Click on "Settings" → "API" +3. Copy "Project URL" and "anon public" key + +--- + +## Supabase Integration + +### 1. Client-Side Supabase Client + +Create `src/lib/supabase/client.ts`: + +```typescript +import { createBrowserClient } from '@supabase/ssr' + +export function createClient() { + return createBrowserClient( + process.env.NEXT_PUBLIC_SUPABASE_URL!, + process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY! + ) +} +``` + +### 2. Server-Side Supabase Client + +Create `src/lib/supabase/server.ts`: + +```typescript +import { createServerClient } from '@supabase/ssr' +import { cookies } from 'next/headers' + +export async function createClient() { + const cookieStore = await cookies() + + return createServerClient( + process.env.NEXT_PUBLIC_SUPABASE_URL!, + process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!, + { + cookies: { + getAll() { + return cookieStore.getAll() + }, + setAll(cookiesToSet) { + try { + cookiesToSet.forEach(({ name, value, options }) => { + cookieStore.set(name, value, options) + }) + } catch { + // Server component case - cookies can't be set + } + }, + }, + } + ) +} +``` + +### 3. Session Management Middleware + +Create `middleware.ts` in your project root (same level as `package.json`): + +```typescript +import { type NextRequest } from 'next/server' +import { updateSession } from '@/lib/supabase/middleware' + +export async function middleware(request: NextRequest) { + return await updateSession(request) +} + +export const config = { + matcher: [ + '/((?!_next/static|_next/image|favicon.ico|.*\\.(?:svg|png|jpg|jpeg|gif|webp)$).*)', + ], +} +``` + +Create `src/lib/supabase/middleware.ts`: + +```typescript +import { createServerClient } from '@supabase/ssr' +import { NextResponse, type NextRequest } from 'next/server' + +export async function updateSession(request: NextRequest) { + let supabaseResponse = NextResponse.next({ + request, + }) + + const supabase = createServerClient( + process.env.NEXT_PUBLIC_SUPABASE_URL!, + process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!, + { + cookies: { + getAll() { + return request.cookies.getAll() + }, + setAll(cookiesToSet) { + cookiesToSet.forEach(({ name, value, options }) => { + request.cookies.set(name, value) + supabaseResponse.cookies.set(name, value, options) + }) + }, + }, + } + ) + + // Refresh session if needed + const { data: { user } } = await supabase.auth.getUser() + + return supabaseResponse +} +``` + +--- + +## Project Structure + +### Recommended File Organization + +``` +my-supabase-app/ +├── src/ +│ ├── app/ # App Router (Next.js 13+) +│ │ ├── globals.css # Global styles +│ │ ├── layout.tsx # Root layout +│ │ ├── page.tsx # Home page +│ │ ├── loading.tsx # Global loading UI +│ │ ├── error.tsx # Global error boundary +│ │ ├── not-found.tsx # 404 page +│ │ │ +│ │ ├── (auth)/ # Route groups for organization +│ │ │ ├── login/ +│ │ │ │ ├── page.tsx +│ │ │ │ ├── actions.ts # Server actions +│ │ │ │ └── loading.tsx +│ │ │ └── signup/ +│ │ │ └── page.tsx +│ │ │ +│ │ ├── dashboard/ # Protected routes +│ │ │ ├── layout.tsx # Dashboard layout +│ │ │ ├── page.tsx +│ │ │ ├── actions.ts # Server actions for dashboard +│ │ │ ├── loading.tsx +│ │ │ ├── error.tsx +│ │ │ └── tasks/ +│ │ │ └── page.tsx +│ │ │ +│ │ └── api/ # API routes +│ │ └── auth/ +│ │ └── confirm/ +│ │ └── route.ts # Email confirmation +│ │ +│ ├── components/ # Reusable components +│ │ ├── ui/ # Basic UI components (shadcn/ui) +│ │ │ ├── button.tsx +│ │ │ ├── card.tsx +│ │ │ ├── input.tsx +│ │ │ └── skeleton.tsx +│ │ ├── layout/ # Layout components +│ │ │ ├── header.tsx +│ │ │ ├── nav.tsx +│ │ │ └── footer.tsx +│ │ └── features/ # Feature-specific components +│ │ ├── auth/ +│ │ │ ├── login-form.tsx +│ │ │ └── logout-button.tsx +│ │ └── tasks/ +│ │ ├── task-list.tsx +│ │ └── task-form.tsx +│ │ +│ ├── lib/ # Utility libraries +│ │ ├── utils.ts # General utilities +│ │ ├── dal.ts # Data Access Layer (security) +│ │ ├── validations.ts # Schema validations +│ │ └── supabase/ # Supabase configuration +│ │ ├── client.ts # Client-side client +│ │ ├── server.ts # Server-side client +│ │ └── middleware.ts # Session management +│ │ +│ ├── hooks/ # Custom React hooks +│ │ ├── use-auth.ts +│ │ └── use-local-storage.ts +│ │ +│ └── types/ # TypeScript definitions +│ └── database.types.ts # Generated Supabase types +│ +├── middleware.ts # Next.js middleware +├── next.config.ts # Next.js configuration +├── tailwind.config.ts # Tailwind configuration +├── tsconfig.json # TypeScript configuration +└── package.json +``` + +--- + +## Database Schema & Security + +### 1. Create Tables in Supabase + +Go to your Supabase project → SQL Editor → New Query, and run: + +```sql +-- Create the tasks table +CREATE TABLE tasks ( + id UUID DEFAULT gen_random_uuid() PRIMARY KEY, + title TEXT NOT NULL, + description TEXT, + completed BOOLEAN DEFAULT FALSE, + user_id UUID REFERENCES auth.users(id) ON DELETE CASCADE, + created_at TIMESTAMP WITH TIME ZONE DEFAULT TIMEZONE('utc'::text, NOW()) NOT NULL, + updated_at TIMESTAMP WITH TIME ZONE DEFAULT TIMEZONE('utc'::text, NOW()) NOT NULL +); + +-- Enable Row Level Security (RLS) +ALTER TABLE tasks ENABLE ROW LEVEL SECURITY; + +-- Create security policies +CREATE POLICY "Users can view own tasks" ON tasks + FOR SELECT USING (auth.uid() = user_id); + +CREATE POLICY "Users can insert own tasks" ON tasks + FOR INSERT WITH CHECK (auth.uid() = user_id); + +CREATE POLICY "Users can update own tasks" ON tasks + FOR UPDATE USING (auth.uid() = user_id); + +CREATE POLICY "Users can delete own tasks" ON tasks + FOR DELETE USING (auth.uid() = user_id); + +-- Create indexes for performance +CREATE INDEX idx_tasks_user_id ON tasks(user_id); +CREATE INDEX idx_tasks_created_at ON tasks(created_at DESC); + +-- Add updated_at trigger +CREATE OR REPLACE FUNCTION update_updated_at_column() +RETURNS TRIGGER AS $$ +BEGIN + NEW.updated_at = TIMEZONE('utc'::text, NOW()); + RETURN NEW; +END; +$$ language 'plpgsql'; + +CREATE TRIGGER update_tasks_updated_at + BEFORE UPDATE ON tasks + FOR EACH ROW + EXECUTE FUNCTION update_updated_at_column(); +``` + +### 2. Generate TypeScript Types + +Run this command to generate types from your database: + +```bash +npx supabase gen types typescript --project-id your_project_id > src/types/database.types.ts +``` + +Replace `your_project_id` with your actual Supabase project ID (found in Project Settings → General). + +--- + +## Authentication Implementation + +### 1. Data Access Layer (Security) + +Create `src/lib/dal.ts`: + +```typescript +import 'server-only' +import { redirect } from 'next/navigation' +import { createClient } from '@/lib/supabase/server' +import { cache } from 'react' + +export const verifySession = cache(async () => { + const supabase = await createClient() + const { data: { user }, error } = await supabase.auth.getUser() + + if (error || !user) { + redirect('/login') + } + + return { isAuth: true, user } +}) + +export const getUser = cache(async () => { + const session = await verifySession() + if (!session) return null + + return session.user +}) +``` + +### 2. Login Page + +Create `src/app/(auth)/login/page.tsx`: + +```typescript +import { login, signup } from './actions' + +export default function LoginPage() { + return ( +
+
+
+

+ Sign in to your account +

+
+
+
+
+ + +
+
+ + +
+
+
+ + +
+
+
+
+ ) +} +``` + +### 3. Authentication Server Actions + +Create `src/app/(auth)/login/actions.ts`: + +```typescript +'use server' + +import { revalidatePath } from 'next/cache' +import { redirect } from 'next/navigation' +import { createClient } from '@/lib/supabase/server' + +export async function login(formData: FormData) { + const supabase = await createClient() + + const data = { + email: formData.get('email') as string, + password: formData.get('password') as string, + } + + const { error } = await supabase.auth.signInWithPassword(data) + + if (error) { + console.error('Login error:', error) + redirect('/login?error=Invalid credentials') + } + + revalidatePath('/', 'layout') + redirect('/dashboard') +} + +export async function signup(formData: FormData) { + const supabase = await createClient() + + const data = { + email: formData.get('email') as string, + password: formData.get('password') as string, + } + + const { error } = await supabase.auth.signUp(data) + + if (error) { + console.error('Signup error:', error) + redirect('/login?error=Could not create account') + } + + revalidatePath('/', 'layout') + redirect('/login?message=Check your email to confirm your account') +} + +export async function logout() { + const supabase = await createClient() + await supabase.auth.signOut() + revalidatePath('/', 'layout') + redirect('/login') +} +``` + +### 4. Email Confirmation Route + +Create `src/app/api/auth/confirm/route.ts`: + +```typescript +import { createClient } from '@/lib/supabase/server' +import { NextRequest, NextResponse } from 'next/server' + +export async function GET(request: NextRequest) { + const { searchParams } = new URL(request.url) + const token_hash = searchParams.get('token_hash') + const type = searchParams.get('type') + const next = searchParams.get('next') ?? '/dashboard' + + if (token_hash && type) { + const supabase = await createClient() + + const { error } = await supabase.auth.verifyOtp({ + type: type as any, + token_hash, + }) + + if (!error) { + return NextResponse.redirect(new URL(next, request.url)) + } + } + + // Redirect to error page if confirmation fails + return NextResponse.redirect(new URL('/login?error=Could not confirm account', request.url)) +} +``` + +--- + +## CRUD Operations + +### 1. Dashboard Page with Data Fetching + +Create `src/app/dashboard/page.tsx`: + +```typescript +import { verifySession } from '@/lib/dal' +import { createClient } from '@/lib/supabase/server' +import TaskList from '@/components/features/tasks/task-list' +import TaskForm from '@/components/features/tasks/task-form' +import LogoutButton from '@/components/features/auth/logout-button' + +export default async function Dashboard() { + const session = await verifySession() + const supabase = await createClient() + + const { data: tasks, error } = await supabase + .from('tasks') + .select('*') + .order('created_at', { ascending: false }) + + if (error) { + console.error('Error fetching tasks:', error) + return
Error loading tasks
+ } + + return ( +
+
+
+
+
+

+ Dashboard +

+

Welcome back, {session.user.email}

+
+ +
+
+
+
+ +
+
+ +
+
+
+
+
+
+ ) +} +``` + +### 2. Server Actions for CRUD Operations + +Create `src/app/dashboard/actions.ts`: + +```typescript +'use server' + +import { createClient } from '@/lib/supabase/server' +import { revalidatePath } from 'next/cache' +import { redirect } from 'next/navigation' + +export async function createTask(formData: FormData) { + const supabase = await createClient() + + const { data: { user } } = await supabase.auth.getUser() + if (!user) redirect('/login') + + const title = formData.get('title') as string + const description = formData.get('description') as string + + if (!title.trim()) { + return { error: 'Title is required' } + } + + const { error } = await supabase + .from('tasks') + .insert([ + { + title: title.trim(), + description: description?.trim() || null, + user_id: user.id, + }, + ]) + + if (error) { + console.error('Error creating task:', error) + return { error: 'Failed to create task' } + } + + revalidatePath('/dashboard') + return { success: true } +} + +export async function updateTask(id: string, formData: FormData) { + const supabase = await createClient() + + const title = formData.get('title') as string + const description = formData.get('description') as string + const completed = formData.get('completed') === 'on' + + const { error } = await supabase + .from('tasks') + .update({ + title: title.trim(), + description: description?.trim() || null, + completed, + }) + .eq('id', id) + + if (error) { + console.error('Error updating task:', error) + return { error: 'Failed to update task' } + } + + revalidatePath('/dashboard') + return { success: true } +} + +export async function deleteTask(id: string) { + const supabase = await createClient() + + const { error } = await supabase + .from('tasks') + .delete() + .eq('id', id) + + if (error) { + console.error('Error deleting task:', error) + return { error: 'Failed to delete task' } + } + + revalidatePath('/dashboard') + return { success: true } +} + +export async function toggleTask(id: string, completed: boolean) { + const supabase = await createClient() + + const { error } = await supabase + .from('tasks') + .update({ completed }) + .eq('id', id) + + if (error) { + console.error('Error toggling task:', error) + return { error: 'Failed to update task' } + } + + revalidatePath('/dashboard') + return { success: true } +} +``` + +--- + +## UI Components & Styling + +### 1. Utility Functions + +Create `src/lib/utils.ts`: + +```typescript +import { type ClassValue, clsx } from 'clsx' +import { twMerge } from 'tailwind-merge' + +export function cn(...inputs: ClassValue[]) { + return twMerge(clsx(inputs)) +} + +export function formatDate(date: string | Date) { + return new Intl.DateTimeFormat('en-US', { + year: 'numeric', + month: 'short', + day: 'numeric', + hour: '2-digit', + minute: '2-digit', + }).format(new Date(date)) +} +``` + +### 2. Task List Component + +Create `src/components/features/tasks/task-list.tsx`: + +```typescript +import { toggleTask, deleteTask } from '@/app/dashboard/actions' +import { formatDate } from '@/lib/utils' + +type Task = { + id: string + title: string + description: string | null + completed: boolean + created_at: string + updated_at: string +} + +type TaskListProps = { + tasks: Task[] +} + +export default function TaskList({ tasks }: TaskListProps) { + if (tasks.length === 0) { + return ( +
+

No tasks yet. Create your first task!

+
+ ) + } + + return ( +
+

Your Tasks

+
+ {tasks.map((task) => ( +
+
+
+
+ +
+
+

+ {task.title} +

+ {task.description && ( +

+ {task.description} +

+ )} +

+ Created {formatDate(task.created_at)} +

+
+
+
+ +
+
+
+ ))} +
+
+ ) +} +``` + +### 3. Task Form Component + +Create `src/components/features/tasks/task-form.tsx`: + +```typescript +'use client' + +import { createTask } from '@/app/dashboard/actions' +import { useActionState } from 'react' + +export default function TaskForm() { + const [state, formAction, pending] = useActionState(createTask, null) + + return ( +
+

Add New Task

+
+
+ + +
+ +
+ + -
-
- - -
-
- - {% elif agent.slug == 'social-ads-generator' %} -
-
- - -
-
- - -
-
- - -
-
- - -
-
- - {% elif agent.slug == 'faq-generator' %} -
- - -
- {% endif %} - - - - - - - - - - -
- -
-

Cost

-
-
- Current Balance: - {{ user.wallet_balance }} AED -
-
- Cost: - -{{ agent.price_display }} -
-
-
- After Processing: - - {% if has_sufficient_balance %} - {{ user.wallet_balance|floatformat:2 }} AED - {% else %} - Insufficient Balance - {% endif %} - -
-
-
- - - - {% if not has_sufficient_balance %} -

- - Top up wallet - to use this agent -

- {% endif %} -
- - -
-

Agent Statistics

-
-
- Rating: -
- - {{ agent.rating }} -
-
-
- Reviews: - {{ agent.review_count }} -
-
- Category: - {{ agent.get_category_display }} -
-
-
-
- - - - - -{% endblock %} diff --git a/templates/authentication/login.html b/templates/authentication/login.html new file mode 100644 index 0000000..ce90883 --- /dev/null +++ b/templates/authentication/login.html @@ -0,0 +1,60 @@ + + + + + + Login - NetCop Hub + + + +
+ +
+ + \ No newline at end of file diff --git a/templates/authentication/profile.html b/templates/authentication/profile.html new file mode 100644 index 0000000..70491bd --- /dev/null +++ b/templates/authentication/profile.html @@ -0,0 +1,97 @@ + + + + + + Profile - NetCop Hub + + + +
+ ← Back to Homepage + +
+

Profile - {{ user.username }}

+

Email: {{ user.email }}

+

Balance: ${{ user.wallet_balance }}

+ +
+ {{ wallet_status.message }} +
+ + Manage Wallet + Top Up +
+ +
+
+
${{ total_spent }}
+
Total Spent
+
+
+
${{ total_topped_up }}
+
Total Topped Up
+
+
+
{{ total_agents_used }}
+
Agents Used
+
+
+ + {% if popular_agents %} + + {% endif %} + +
+

Recent Transactions

+ {% if transactions %} + {% for transaction in transactions %} +
+
+ {{ transaction.description }} + {{ transaction.created_at|date:"M d, Y H:i" }} +
+
+ {% if transaction.type == 'top_up' %}+{% else %}-{% endif %}${{ transaction.amount }} +
+
+ {% endfor %} + {% else %} +

No transactions yet.

+ {% endif %} +
+
+ + \ No newline at end of file diff --git a/templates/authentication/register.html b/templates/authentication/register.html new file mode 100644 index 0000000..7d34ed2 --- /dev/null +++ b/templates/authentication/register.html @@ -0,0 +1,70 @@ + + + + + + Register - NetCop Hub + + + +
+
+

Register for NetCop Hub

+ + {% if messages %} +
+ {% for message in messages %} +
{{ message }}
+ {% endfor %} +
+ {% endif %} + +
+ {% csrf_token %} +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ + +
+ + +
+
+ + \ No newline at end of file diff --git a/templates/base.html b/templates/base.html deleted file mode 100644 index bbec678..0000000 --- a/templates/base.html +++ /dev/null @@ -1,74 +0,0 @@ -{% load static %} - - - - - - {% block title %}NetCop AI Hub{% endblock %} - - - - - - - - - - - {% if messages %} -
- {% for message in messages %} - {% if message.tags == 'error' %} -
- {% else %} -
- {% endif %} - {{ message }} -
- {% endfor %} -
- {% endif %} - - -
- {% block content %}{% endblock %} -
- - -
-
-
-

© 2024 NetCop AI Hub. All rights reserved.

-
-
-
- - \ No newline at end of file diff --git a/templates/core/agent_detail.html b/templates/core/agent_detail.html new file mode 100644 index 0000000..37fcdba --- /dev/null +++ b/templates/core/agent_detail.html @@ -0,0 +1,118 @@ + + + + + + {{ agent.name }} - NetCop Hub + + + +
+ ← Back to Homepage + +
+
+
{{ agent.icon }}
+
+

{{ agent.name }}

+
${{ agent.price }}
+
★ {{ agent.rating }} ({{ agent.review_count }} reviews)
+
+
+ +

{{ agent.description }}

+ + {% if user.is_authenticated %} +
+ Your Balance: ${{ user_balance }} +
+ + {% if can_use_agent %} +
+

Use {{ agent.name }}

+
+ {% csrf_token %} + + {% if agent.slug == 'data-analyzer' %} +
+ + +
+ {% elif agent.slug == 'five-whys' %} +
+ + +
+ {% elif agent.slug == 'weather-reporter' %} +
+ + +
+ {% elif agent.slug == 'job-posting-generator' %} +
+ + +
+ {% elif agent.slug == 'social-ads-generator' %} +
+ + +
+ {% elif agent.slug == 'faq-generator' %} +
+ + +
+ {% endif %} + + +
+
+ {% else %} +
+ Insufficient Balance! You need ${{ agent.price }} to use this agent. + Top up your wallet +
+ {% endif %} + + {% if recent_usage %} +
+

Your Recent Usage

+ {% for usage in recent_usage %} +
+ ${{ usage.amount }} - {{ usage.description }} + ({{ usage.created_at|date:"M d, Y H:i" }}) +
+ {% endfor %} +
+ {% endif %} + {% else %} +

Login to use this agent.

+ {% endif %} +
+
+ + \ No newline at end of file diff --git a/templates/core/homepage.html b/templates/core/homepage.html new file mode 100644 index 0000000..a234a90 --- /dev/null +++ b/templates/core/homepage.html @@ -0,0 +1,85 @@ + + + + + + NetCop Hub - AI Agent Marketplace + + + +
+
+

NetCop Hub - AI Agent Marketplace

+ +
+
+ + {% if categories %} + {% for category_name, category_agents in categories.items %} +
+
{{ category_name }}
+
+ {% for agent in category_agents %} +
+
+
{{ agent.icon }}
+
+
{{ agent.name }}
+
${{ agent.price }}
+
+ ★ {{ agent.rating }} ({{ agent.review_count }} reviews) +
+
+
+

{{ agent.description }}

+ Use Agent +
+ {% endfor %} +
+
+ {% endfor %} + {% else %} +
+
+

No agents available

+

Please check back later or contact the administrator.

+
+
+ {% endif %} +
+ + \ No newline at end of file diff --git a/templates/core/wallet.html b/templates/core/wallet.html new file mode 100644 index 0000000..996126d --- /dev/null +++ b/templates/core/wallet.html @@ -0,0 +1,68 @@ + + + + + + Wallet - NetCop Hub + + + +
+ ← Back to Homepage + +
+

Your Wallet

+
${{ current_balance }}
+ Top Up Wallet +
+ +
+
+
${{ total_spent }}
+
Total Spent
+
+
+
${{ total_topped_up }}
+
Total Topped Up
+
+
+ +
+

Recent Transactions

+ {% if transactions %} + {% for transaction in transactions %} +
+
+ {{ transaction.description }} + {{ transaction.created_at|date:"M d, Y H:i" }} +
+
+ {% if transaction.type == 'top_up' %}+{% else %}-{% endif %}${{ transaction.amount }} +
+
+ {% endfor %} + {% else %} +

No transactions yet.

+ {% endif %} +
+
+ + \ No newline at end of file diff --git a/templates/core/wallet_topup.html b/templates/core/wallet_topup.html new file mode 100644 index 0000000..16518de --- /dev/null +++ b/templates/core/wallet_topup.html @@ -0,0 +1,97 @@ + + + + + + Top Up Wallet - NetCop Hub + + + +
+ ← Back to Wallet + +
+

Top Up Your Wallet

+ + {% if messages %} +
+ {% for message in messages %} +
{{ message }}
+ {% endfor %} +
+ {% endif %} + +
+ {% csrf_token %} +

Select an amount to add to your wallet:

+ +
+
+
$10
+
Basic
+
+
+
$50
+
Popular
+
+
+
$100
+
Best Value
+
+
+
$500
+
Premium
+
+
+ + + +
+
+
+ + + + \ No newline at end of file diff --git a/templates/debug.html b/templates/debug.html deleted file mode 100644 index 8975379..0000000 --- a/templates/debug.html +++ /dev/null @@ -1,36 +0,0 @@ -{% extends 'base.html' %} - -{% block title %}Debug - Environment Status{% endblock %} - -{% block content %} -
- {% if not debug_mode %} -

🚫 Debug page disabled in production

-

This debug page is only available in development mode.

- {% else %} -

🔧 Environment Debug Page

- -
-

Environment Variables Status:

-
{{ env_status|safe }}
-
- -
-

💡 Troubleshooting Tips:

-
    -
  • Make sure .env file exists in your project root
  • -
  • Restart your Django server after changing environment variables
  • -
  • In production, set environment variables in your hosting platform dashboard
  • -
  • Check that sensitive variables are properly configured
  • -
-
- -
-

🔍 Database Status:

-

Database Connection: {{ db_status.status }}

-

User Count: {{ user_count }}

-

Agent Count: {{ agent_count }}

-
- {% endif %} -
-{% endblock %} diff --git a/templates/homepage.html b/templates/homepage.html deleted file mode 100644 index ae8befa..0000000 --- a/templates/homepage.html +++ /dev/null @@ -1,1039 +0,0 @@ -{% load static %} - - - - - - NetCop AI Hub - AI & Cybersecurity Solutions - - - - - - -
- -
- -
- - -
- -
- -
- -
-
-
- - -
- - Trusted by Industry Leaders -
- -

- AI & Cybersecurity -
- Solutions -

- -

- Secure your digital future with state-of-the-art AI solutions and expert cybersecurity strategies tailored for your business needs. -

- - - - - -
-
-
{{ total_agents }}+
-
Active AI Agents
-
-
-
24/7
-
Rapid Response
-
-
-
{{ total_users }}+
-
Registered Users
-
-
-
-
- - -
- -
-
- -
- -
-
- 🏢 - About Netcop Consultancy -
-

Your Trusted Digital Guardian

-

Pioneering the future of cybersecurity with AI-powered solutions

-
- -
- -
-
- -
🛡️
- -

Defending Digital Frontiers

- -

- At Netcop Consultancy, we provide state-of-the-art AI & Cybersecurity solutions tailored to safeguard your business. From advanced AI Agents to robust defense strategies, we empower you to navigate the digital world with confidence. -

- - -
-
-
📅
- {{ total_agents }}+ AI Agents Available -
-
-
🏆
- Top Certifications -
-
- -
-
- Lean Six Sigma Black Belt -
-
-
- - -
- -
- -
-
- - -
🛡️
-
- - -
🔒
-
🤖
-
-
- - -
-
-
🎯
-
Mission Critical
-
Zero Compromise
-
-
-
-
Rapid Response
-
24/7 Protection
-
-
-
🔬
-
Innovation
-
Cutting Edge Tech
-
-
-
🤝
-
Trusted Partner
-
Industry Leaders
-
-
-
-
- - -
-
-

- Our Services -

-

- Tailored strategies for your business -

-
-
-
🛡️
-

Cybersecurity Consultation

-

- Tailored strategies, advanced threat detection, and comprehensive security frameworks to protect your digital assets and business operations. -

-
-
-
🤖
-

AI Based Automation

-

- Empower your Business with AI. Strategic AI adoption, machine learning solutions, and intelligent automation to transform your processes. -

-
-
-
-

Rapid Response Solutions

-

- Rapid response to minimize damage. Emergency incident response and real-time threat mitigation to protect your business. -

-
-
-
-
- - -
-
-

- Our Clients -

-
-
-
🏭
-

MTSV Foods Industries Pvt Ltd

-

Food & Beverage Industry

-
-
-
🏗️
-

Apple Tree Industries

-

Manufacturing & Processing

-
-
-
💻
-

TechStart Solutions

-

Technology Consulting

-
-
-
🚚
-

Global Logistics Corp

-

Supply Chain Management

-
-
-
-
- - -
-
-

- Our Founder -

-
-
-
-
👨‍💼
-

Abhay Pal Chauhan

-

- Founder & Principal Consultant -

-
-
- {{ total_agents }}+ AI Agents Available -
-
- Cybersecurity Expert -
-
- Six Sigma Black Belt -
-
-
-
-
-

- Our Founder leverages over 18 years of expertise in cybersecurity and process automation and optimization, backed by top certifications in Cybersecurity and Black Belt in Lean Six Sigma. -

-

- His unique blend of technical knowledge and operational excellence ensures tailored, secure, and efficient solutions for our clients, driving business resilience and maximizing value in every engagement. -

-
-

- "Delivering top-tier solutions that combine cutting-edge technology with proven operational methodologies to secure and optimize your business operations." -

-
-
-
-
-
- - -
-
-

- Get In Touch -

-
- -
- {% csrf_token %} -

Send us a Message

-
- - -
-
- - -
-
- - -
-
- - -
- -
- - -
-

Contact Information

- - -
-
📍
-
-

Mailing Address

-

- Meydan Grandstand, 6th floor
- Meydan Road, Nad Al Sheba
- Dubai, U.A.E. -

-
-
- - -
-
✉️
-
-

Email Address

-

- - abhay@netcopconsultancy.com - -

-
-
- - -
-

- We are committed to deliver top-tier AI & Cybersecurity solutions for businesses of all sizes. -

-
-
-
-
-
- - -
-
-

NetCop AI Hub

-

AI & Cybersecurity Solutions

-
-
- © 2025 NetCop AI Hub. All rights reserved. -
-
-
- - - - \ No newline at end of file diff --git a/templates/marketplace.html b/templates/marketplace.html deleted file mode 100644 index f9712cb..0000000 --- a/templates/marketplace.html +++ /dev/null @@ -1,45 +0,0 @@ -{% extends 'base.html' %} - -{% block title %}AI Agent Marketplace - NetCop AI Hub{% endblock %} - -{% block content %} -
-

AI Agent Marketplace

-

Choose from our collection of powerful AI agents

-
- -
- {% for agent in agents %} -
-
-
-
- {{ agent.icon }} -
-
-
{{ agent.price_display }}
-
per use
-
-
- -

{{ agent.name }}

-

{{ agent.description }}

- -
-
- - {{ agent.rating }} ({{ agent.review_count }}) -
- - {{ agent.get_category_display }} - -
- - - Use Agent - -
-
- {% endfor %} -
-{% endblock %} diff --git a/templates/reset_password.html b/templates/reset_password.html deleted file mode 100644 index 20e9366..0000000 --- a/templates/reset_password.html +++ /dev/null @@ -1,58 +0,0 @@ -{% extends 'base.html' %} - -{% block title %}Reset Password - NetCop AI Hub{% endblock %} - -{% block content %} -
- -
-
-

- Reset Your Password -

-

- Enter your new password below -

-
- - {% if error %} -
-
-

Error

-

{{ error }}

- - Go to Homepage - -
- {% else %} -
- {% csrf_token %} - -
- - -
- -
- - -
- - -
- {% endif %} - -
- - Back to Homepage - -
-
-
-{% endblock %} \ No newline at end of file diff --git a/test_views.py b/test_views.py new file mode 100644 index 0000000..f446dd6 --- /dev/null +++ b/test_views.py @@ -0,0 +1,34 @@ +#!/usr/bin/env python +import os +import sys +import django + +# Add project root to path +sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) + +# Setup Django +os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'netcop_hub.settings') +django.setup() + +from django.test import RequestFactory +from django.contrib.auth import get_user_model +from core.views import homepage_view + +# Create a test request +factory = RequestFactory() +request = factory.get('/') + +# Create a mock user +from django.contrib.auth.models import AnonymousUser +request.user = AnonymousUser() + +try: + # Test homepage view + response = homepage_view(request) + print(f"Homepage view status: {response.status_code}") + print("Homepage view working correctly!") + +except Exception as e: + print(f"Error in homepage view: {e}") + import traceback + traceback.print_exc() \ No newline at end of file diff --git a/wallet/__init__.py b/wallet/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/wallet/admin.py b/wallet/admin.py new file mode 100644 index 0000000..c466519 --- /dev/null +++ b/wallet/admin.py @@ -0,0 +1,31 @@ +from django.contrib import admin +from .models import WalletTransaction + + +@admin.register(WalletTransaction) +class WalletTransactionAdmin(admin.ModelAdmin): + list_display = ('user', 'type', 'amount', 'agent_slug', 'created_at', 'id') + list_filter = ('type', 'created_at', 'agent_slug') + search_fields = ('user__username', 'user__email', 'description', 'agent_slug') + readonly_fields = ('id', 'created_at') + ordering = ('-created_at',) + + fieldsets = ( + ('Transaction Details', { + 'fields': ('user', 'type', 'amount', 'description') + }), + ('Agent Information', { + 'fields': ('agent_slug',) + }), + ('Payment Information', { + 'fields': ('stripe_session_id',) + }), + ('Metadata', { + 'fields': ('id', 'created_at') + }), + ) + + def get_readonly_fields(self, request, obj=None): + if obj: # editing an existing object + return self.readonly_fields + ('user', 'type', 'amount') + return self.readonly_fields diff --git a/apps/wallet/apps.py b/wallet/apps.py similarity index 100% rename from apps/wallet/apps.py rename to wallet/apps.py diff --git a/apps/wallet/migrations/0001_initial.py b/wallet/migrations/0001_initial.py similarity index 96% rename from apps/wallet/migrations/0001_initial.py rename to wallet/migrations/0001_initial.py index 835183b..0a28d70 100644 --- a/apps/wallet/migrations/0001_initial.py +++ b/wallet/migrations/0001_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 5.2.4 on 2025-07-08 08:17 +# Generated by Django 5.2.4 on 2025-07-08 15:00 import django.db.models.deletion import uuid diff --git a/wallet/migrations/__init__.py b/wallet/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/apps/wallet/models.py b/wallet/models.py similarity index 100% rename from apps/wallet/models.py rename to wallet/models.py index 7938f03..acaf2da 100644 --- a/apps/wallet/models.py +++ b/wallet/models.py @@ -4,6 +4,7 @@ import uuid User = get_user_model() + class WalletTransaction(models.Model): TRANSACTION_TYPES = [ ('top_up', 'Top Up'), @@ -25,4 +26,3 @@ class WalletTransaction(models.Model): def __str__(self): return f"{self.user.email} - {self.amount} AED ({self.type})" - diff --git a/wallet/stripe_handler.py b/wallet/stripe_handler.py new file mode 100644 index 0000000..7d41904 --- /dev/null +++ b/wallet/stripe_handler.py @@ -0,0 +1,106 @@ +import stripe +from django.conf import settings +from django.contrib.auth import get_user_model +from django.http import JsonResponse +from decimal import Decimal +import json + +User = get_user_model() +stripe.api_key = settings.STRIPE_SECRET_KEY + + +class StripePaymentHandler: + def __init__(self): + self.payment_links = { + 10: 'https://buy.stripe.com/test_28EbJ16AA7ly3ic7vh2VG0a', + 50: 'https://buy.stripe.com/test_4gM00jbUUgW83ic3f12VG0b', + 100: 'https://buy.stripe.com/test_aFadR99MM35ibOI6rd2VG0c', + 500: 'https://buy.stripe.com/test_14AbJ12kk7lyf0U16T2VG0d' + } + + def create_checkout_session(self, user, amount): + """Create a Stripe checkout session for wallet top-up""" + if amount not in self.payment_links: + raise ValueError(f"Invalid amount: {amount}") + + payment_link = self.payment_links[amount] + + # Return the payment link URL with user reference + return { + 'payment_url': f"{payment_link}?client_reference_id={user.id}&prefilled_email={user.email}", + 'session_id': None # Payment links don't have session IDs + } + + def verify_payment(self, session_id): + """Verify payment from Stripe webhook""" + try: + session = stripe.checkout.Session.retrieve(session_id) + + if session.payment_status == 'paid': + return { + 'success': True, + 'amount': session.amount_total / 100, # Convert from cents + 'customer_email': session.customer_details.email, + 'client_reference_id': session.client_reference_id + } + else: + return {'success': False, 'error': 'Payment not completed'} + + except stripe.error.StripeError as e: + return {'success': False, 'error': str(e)} + + def handle_webhook(self, payload, signature): + """Handle Stripe webhook events""" + try: + event = stripe.Webhook.construct_event( + payload, signature, settings.STRIPE_WEBHOOK_SECRET + ) + except ValueError: + return {'success': False, 'error': 'Invalid payload'} + except stripe.error.SignatureVerificationError: + return {'success': False, 'error': 'Invalid signature'} + + if event['type'] == 'checkout.session.completed': + session = event['data']['object'] + + # Process successful payment + user_id = session.get('client_reference_id') + amount = session['amount_total'] / 100 # Convert from cents + + if user_id: + try: + user = User.objects.get(id=user_id) + user.add_balance( + amount=amount, + description=f"Wallet top-up via Stripe", + stripe_session_id=session['id'] + ) + return {'success': True, 'message': 'Payment processed successfully'} + except User.DoesNotExist: + return {'success': False, 'error': 'User not found'} + + return {'success': True, 'message': 'Event processed'} + + def process_refund(self, session_id, amount=None): + """Process refund for a payment""" + try: + session = stripe.checkout.Session.retrieve(session_id) + payment_intent = session.payment_intent + + if amount: + refund = stripe.Refund.create( + payment_intent=payment_intent, + amount=int(amount * 100) # Convert to cents + ) + else: + refund = stripe.Refund.create(payment_intent=payment_intent) + + return { + 'success': True, + 'refund_id': refund.id, + 'amount': refund.amount / 100, + 'status': refund.status + } + + except stripe.error.StripeError as e: + return {'success': False, 'error': str(e)} \ No newline at end of file diff --git a/apps/wallet/tests.py b/wallet/tests.py similarity index 100% rename from apps/wallet/tests.py rename to wallet/tests.py diff --git a/wallet/views.py b/wallet/views.py new file mode 100644 index 0000000..91ea44a --- /dev/null +++ b/wallet/views.py @@ -0,0 +1,3 @@ +from django.shortcuts import render + +# Create your views here.