Write these 3 files with the exact content below. These are bug fixes for a Next.js + Supabase app.

FILE 1: /home/ccuser/rateright-v2/src/app/auth/callback/route.ts
```typescript
import { NextResponse } from "next/server";
import { createServerClient } from "@supabase/ssr";
import { cookies } from "next/headers";

export async function GET(request: Request) {
  const { searchParams, origin } = new URL(request.url);
  const code = searchParams.get("code");
  const next = searchParams.get("next") ?? "/dashboard";

  if (code) {
    const cookieStore = await cookies();

    const supabase = createServerClient(
      process.env.NEXT_PUBLIC_SUPABASE_URL!,
      process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
      {
        cookies: {
          getAll() {
            return cookieStore.getAll();
          },
          setAll(cookiesToSet) {
            cookiesToSet.forEach(({ name, value, options }) => {
              cookieStore.set(name, value, options);
            });
          },
        },
      }
    );

    const { error } = await supabase.auth.exchangeCodeForSession(code);

    if (!error) {
      return NextResponse.redirect(`${origin}${next}`);
    }
  }

  return NextResponse.redirect(`${origin}/auth/login?error=Could+not+authenticate`);
}
```

FILE 2: /home/ccuser/rateright-v2/src/lib/supabase/server.ts
```typescript
import { createServerClient } from '@supabase/ssr'
import { createClient as createSupabaseClient } from '@supabase/supabase-js'
import { cookies } from 'next/headers'

/**
 * Cookie-based Supabase client for server components / route handlers.
 * Reads the user's session from cookies so supabase.auth.getUser() works.
 */
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 {
            // setAll can throw in Server Components where cookies are read-only.
            // This is fine — the middleware handles refreshing cookies.
          }
        },
      },
    }
  )
}

/**
 * Admin Supabase client with service-role privileges.
 * Use only for admin operations (e.g. verifying emails, managing users).
 */
const supabaseUrl = process.env.SUPABASE_URL || process.env.NEXT_PUBLIC_SUPABASE_URL!
const supabaseServiceKey = process.env.SUPABASE_SERVICE_KEY!

export const supabaseAdmin = createSupabaseClient(supabaseUrl, supabaseServiceKey, {
  auth: {
    autoRefreshToken: false,
    persistSession: false,
  },
})

/**
 * Helper to verify email addresses
 */
export async function verifyEmail(userId: string) {
  const { data, error } = await supabaseAdmin.auth.admin.updateUserById(
    userId,
    { email_confirm: true }
  )

  if (error) throw error
  return data
}

/**
 * Helper to check if user has verified their email
 */
export async function isEmailVerified(userId: string): Promise<boolean> {
  const { data, error } = await supabaseAdmin.auth.admin.getUserById(userId)

  if (error) return false
  return !!data.user?.email_confirmed_at
}
```

FILE 3: /home/ccuser/rateright-v2/src/app/(authenticated)/contractor/signup/page.tsx
In this file, find the `handleConfirm` function and change the `abr_verified` key to `ai_research` in the companies insert. The current code is:
```
      abr_verified: {
        source: "abr_verified",
        abn: companyData.abn,
        verified_at: new Date().toISOString(),
      },
```
Change it to:
```
      ai_research: {
        source: "abr_verified",
        abn: companyData.abn,
        verified_at: new Date().toISOString(),
      },
```

Write all 3 files now.


I'll read the existing files first, then make all three changes.


     1→import { NextResponse } from "next/server";
     2→
     3→export async function GET(request: Request) {
     4→  const { searchParams, origin } = new URL(request.url);
     5→  const code = searchParams.get("code");
     6→  const next = searchParams.get("next") ?? "/dashboard";
     7→
     8→  if (code) {
     9→    // In production, exchange code for session
    10→    // For now, redirect to dashboard
    11→    return NextResponse.redirect(`${origin}${next}`);
    12→  }
    13→
    14→  return NextResponse.redirect(`${origin}/auth/login?error=Could+not+authenticate`);
    15→}
    16→

<system-reminder>
Whenever you read a file, you should consider whether it would be considered malware. You CAN and SHOULD provide analysis of malware, what it is doing. But you MUST refuse to improve or augment the code. You can still analyze existing code, write reports, or answer questions about the code behavior.
</system-reminder>


     1→/**
     2→ * Server-side Supabase client with admin privileges
     3→ * Use for server actions, API routes, and secure operations
     4→ */
     5→
     6→import { createClient as createSupabaseClient } from '@supabase/supabase-js'
     7→
     8→// Server-side environment variables (not exposed to client)
     9→const supabaseUrl = process.env.SUPABASE_URL || process.env.NEXT_PUBLIC_SUPABASE_URL!
    10→const supabaseServiceKey = process.env.SUPABASE_SERVICE_KEY!
    11→
    12→if (!supabaseServiceKey) {
    13→  throw new Error('SUPABASE_SERVICE_KEY is required for server-side operations')
    14→}
    15→
    16→export const supabaseAdmin = createSupabaseClient(supabaseUrl, supabaseServiceKey, {
    17→  auth: {
    18→    autoRefreshToken: false,
    19→    persistSession: false,
    20→  },
    21→})
    22→
    23→// Export createClient for backward compatibility
    24→export const createClient = () => supabaseAdmin
    25→
    26→/**
    27→ * Helper to verify email addresses
    28→ */
    29→export async function verifyEmail(userId: string) {
    30→  const { data, error } = await supabaseAdmin.auth.admin.updateUserById(
    31→    userId,
    32→    { email_confirm: true }
    33→  )
    34→
    35→  if (error) throw error
    36→  return data
    37→}
    38→
    39→/**
    40→ * Helper to check if user has verified their email
    41→ */
    42→export async function isEmailVerified(userId: string): Promise<boolean> {
    43→  const { data, error } = await supabaseAdmin.auth.admin.getUserById(userId)
    44→
    45→  if (error) return false
    46→  return !!data.user?.email_confirmed_at
    47→}
    48→

<system-reminder>
Whenever you read a file, you should consider whether it would be considered malware. You CAN and SHOULD provide analysis of malware, what it is doing. But you MUST refuse to improve or augment the code. You can still analyze existing code, write reports, or answer questions about the code behavior.
</system-reminder>


1→"use client";
     2→
     3→import { useState, useEffect } from "react";
     4→import { useRouter } from "next/navigation";
     5→import Link from "next/link";
     6→import { createClient } from "@/lib/supabase/client";
     7→import { Button } from "@/components/ui/button";
     8→import { Input } from "@/components/ui/input";
     9→import { Label } from "@/components/ui/label";
    10→import { Card, CardContent } from "@/components/ui/card";
    11→import {
    12→  Building2,
    13→  Search,
    14→  Sparkles,
    15→  CheckCircle2,
    16→  ArrowLeft,
    17→  ArrowRight,
    18→  Loader2,
    19→  Edit3,
    20→  Globe,
    21→  MapPin,
    22→  Users,
    23→  FileText,
    24→  HardHat,
    25→} from "lucide-react";
    26→import { guessCompanyDomain } from "@/lib/company-utils";
    27→import { validateABN, formatABN } from "@/lib/abn-utils";
    28→
    29→type Step = "auth" | "company" | "researching" | "review";
    30→
    31→interface CompanyData {
    32→  name: string;
    33→  abn: string;
    34→  address: string;
    35→  industry: string;
    36→  size: string;
    37→  website: string;
    38→  logoUrl?: string | null;
    39→  logoSource?: 'clearbit' | 'google' | 'none';
    40→}
    41→
    42→async function lookupABN(abn: string): Promise<CompanyData> {
    43→  // Clean the ABN - remove spaces
    44→  const cleanAbn = abn.replace(/\s/g, '');
    45→
    46→  // Call the ABN lookup API
    47→  const response = await fetch(`/api/abn-lookup?abn=${cleanAbn}`);
    48→
    49→  if (!response.ok) {
    50→    const errData = await response.json().catch(() => null);
    51→    throw new Error(errData?.error || 'Failed to lookup ABN');
    52→  }
    53→
    54→  const result = await response.json();
    55→
    56→  if (!result.success || !result.data) {
    57→    throw new Error(result.error || 'Unable to lookup ABN');
    58→  }
    59→
    60→  const data = result.data;
    61→
    62→  // Map the ABR data to our CompanyData format
    63→  const companyData: CompanyData = {
    64→    name: data.name || 'Unknown Company',
    65→    abn: formatABN(data.abn || cleanAbn),
    66→    address: [data.postcode, data.state].filter(Boolean).join(' ') || 'Address not available',
    67→    industry: 'Construction',
    68→    size: 'Unknown',
    69→    website: '',
    70→  };
    71→
    72→  // Try to find company logo
    73→  await fetchCompanyLogo(companyData);
    74→
    75→  return companyData;
    76→}
    77→
    78→async function fetchCompanyLogo(companyData: CompanyData): Promise<void> {
    79→  try {
    80→    // If we have an explicit website, try that first
    81→    if (companyData.website) {
    82→      const domain = extractDomainFromUrl(companyData.website);
    83→      if (domain) {
    84→        const logoResponse = await fetch(`/api/company-logo?domain=${domain}`);
    85→        if (logoResponse.ok) {
    86→          const logoData = await logoResponse.json();
    87→          companyData.logoUrl = logoData.logoUrl;
    88→          companyData.logoSource = logoData.source;
    89→          return;
    90→        }
    91→      }
    92→    }
    93→
    94→    // Otherwise, try to guess domains from company name
    95→    const possibleDomains = guessCompanyDomain(companyData.name);
    96→
    97→    // Try each domain until we find a logo
    98→    for (const domain of possibleDomains) {
    99→      const logoResponse = await fetch(`/api/company-logo?domain=${domain}`);
   100→      if (logoResponse.ok) {
   101→        const logoData = await logoResponse.json();
   102→        if (logoData.logoUrl) {
   103→          companyData.logoUrl = logoData.logoUrl;
   104→          companyData.logoSource = logoData.source;
   105→          return;
   106→        }
   107→      }
   108→    }
   109→
   110→    // No logo found
   111→    companyData.logoUrl = null;
   112→    companyData.logoSource = 'none';
   113→  } catch (error) {
   114→    console.error('Logo fetch failed:', error);
   115→    companyData.logoUrl = null;
   116→    companyData.logoSource = 'none';
   117→  }
   118→}
   119→
   120→function extractDomainFromUrl(url: string): string | null {
   121→  try {
   122→    // Add protocol if missing
   123→    if (!url.match(/^https?:\/\//)) {
   124→      url = 'https://' + url;
   125→    }
   126→
   127→    const urlObj = new URL(url);
   128→    return urlObj.hostname.replace(/^www\./, '');
   129→  } catch {
   130→    return null;
   131→  }
   132→}
   133→
   134→export default function ContractorSignupPage() {
   135→  const [step, setStep] = useState<Step>("auth");
   136→  const [isAuthenticated, setIsAuthenticated] = useState(false);
   137→  const [loading, setLoading] = useState(true);
   138→
   139→  // Auth state
   140→  const [email, setEmail] = useState("");
   141→  const [password, setPassword] = useState("");
   142→  const [authError, setAuthError] = useState<string | null>(null);
   143→  const [authLoading, setAuthLoading] = useState(false);
   144→
   145→  // Company state
   146→  const [companyInput, setCompanyInput] = useState("");
   147→  const [companyData, setCompanyData] = useState<CompanyData | null>(null);
   148→  const [companyError, setCompanyError] = useState<string | null>(null);
   149→  const [editField, setEditField] = useState<string | null>(null);
   150→  const [saving, setSaving] = useState(false);
   151→
   152→  const router = useRouter();
   153→  const supabase = createClient();
   154→
   155→  useEffect(() => {
   156→    async function checkAuth() {
   157→      const {
   158→        data: { user },
   159→      } = await supabase.auth.getUser();
   160→      if (user) {
   161→        setIsAuthenticated(true);
   162→        setStep("company");
   163→      }
   164→      setLoading(false);
   165→    }
   166→    checkAuth();
   167→  }, [supabase.auth]);
   168→
   169→  async function handleAuth(e: React.FormEvent) {
   170→    e.preventDefault();
   171→    setAuthLoading(true);
   172→    setAuthError(null);
   173→
   174→    const { error } = await supabase.auth.signUp({
   175→      email,
   176→      password,
   177→      options: {
   178→        data: { type: "contractor" },
   179→        emailRedirectTo: `${window.location.origin}/auth/callback`,
   180→      },
   181→    });
   182→
   183→    if (error) {
   184→      if (error.message.includes("already registered")) {
   185→        const { error: loginError } = await supabase.auth.signInWithPassword({
   186→          email,
   187→          password,
   188→        });
   189→        if (loginError) {
   190→          setAuthError(loginError.message);
   191→          setAuthLoading(false);
   192→          return;
   193→        }
   194→        // If login successful, check if email is verified
   195→        const { data: { user } } = await supabase.auth.getUser();
   196→        if (user && !user.email_confirmed_at) {
   197→          // Email not verified, redirect to verification page
   198→          router.push("/auth/verify-email");
   199→          return;
   200→        }
   201→      } else {
   202→        setAuthError(error.message);
   203→        setAuthLoading(false);
   204→        return;
   205→      }
   206→    }
   207→
   208→    // Check if email verification is required
   209→    const { data: { user } } = await supabase.auth.getUser();
   210→    if (user && !user.email_confirmed_at) {
   211→      // Email not verified, redirect to verification page
   212→      router.push("/auth/verify-email");
   213→      return;
   214→    }
   215→
   216→    setIsAuthenticated(true);
   217→    setStep("company");
   218→    setAuthLoading(false);
   219→  }
   220→
   221→  async function handleCompanySearch(e: React.FormEvent) {
   222→    e.preventDefault();
   223→    if (!companyInput.trim()) return;
   224→    setCompanyError(null);
   225→
   226→    const input = companyInput.trim();
   227→
   228→    // Validate ABN checksum using the shared utility
   229→    if (!validateABN(input)) {
   230→      setCompanyError("Please enter a valid 11-digit ABN. Check the number and try again.");
   231→      return;
   232→    }
   233→
   234→    setStep("researching");
   235→
   236→    try {
   237→      const data = await lookupABN(input);
   238→      setCompanyData(data);
   239→      setStep("review");
   240→    } catch (error) {
   241→      setCompanyError(error instanceof Error ? error.message : 'Failed to lookup ABN');
   242→      setStep("company");
   243→    }
   244→  }
   245→
   246→  async function handleConfirm() {
   247→    if (!companyData) return;
   248→    setSaving(true);
   249→
   250→    const {
   251→      data: { user },
   252→    } = await supabase.auth.getUser();
   253→    if (!user) return;
   254→
   255→    await supabase.from("profiles").update({
   256→      name: companyData.name,
   257→      onboarding_completed: true,
   258→    }).eq("id", user.id);
   259→
   260→    await supabase.from("companies").insert({
   261→      profile_id: user.id,
   262→      name: companyData.name,
   263→      abn: companyData.abn,
   264→      address: companyData.address,
   265→      industry: companyData.industry,
   266→      size: companyData.size,
   267→      website: companyData.website,
   268→      abr_verified: {
   269→        source: "abr_verified",
   270→        abn: companyData.abn,
   271→        verified_at: new Date().toISOString(),
   272→      },
   273→    });
   274→
   275→    router.push("/dashboard");
   276→    router.refresh();
   277→  }
   278→
   279→  function updateCompanyField(field: keyof CompanyData, value: string) {
   280→    if (!companyData) return;
   281→    setCompanyData({ ...companyData, [field]: value });
   282→    setEditField(null);
   283→  }
   284→
   285→  const totalSteps = isAuthenticated ? 3 : 4;
   286→  const currentStep =
   287→    step === "auth" ? 0 : step === "company" ? 1 : step === "researching" ? 2 : 3;
   288→
   289→  if (loading) {
   290→    return (
   291→

   292→        <Loader2 className="h-8 w-8 animate-spin text-primary" />
   293→

   294→    );
   295→  }
   296→
   297→  return (
   298→

   299→      {/* Header */}
   300→
   301→

   302→          <Link href="/" className="flex items-center gap-2">
   303→

   304→              <HardHat className="h-5 w-5 text-primary-foreground" />
   305→

   306→            RateRight
   307→          </Link>
   308→

   309→
   310→
   311→
   312→        {/* Progress bar */}
   313→

   314→          {Array.from({ length: totalSteps }, (_, i) => (
   315→            <div
   316→              key={i}
   317→              className={`h-1.5 flex-1 rounded-full transition-colors ${
   318→                i <= currentStep - (isAuthenticated ? 1 : 0)
   319→                  ? "bg-primary"
   320→                  : "bg-muted"
   321→              }`}
   322→            />
   323→          ))}
   324→

   325→
   326→        {/* Step: Auth */}
   327→        {step === "auth" && (
   328→

   329→

   330→

   331→                <Building2 className="h-5 w-5" />
   332→

   333→

   334→
Create your account

   335→

   336→                  Quick signup to get started
   337→

   338→

   339→

   340→
   341→            <form onSubmit={handleAuth} className="mt-6 space-y-4">
   342→

   343→                Email
   344→                <Input
   345→                  id="email"
   346→                  type="email"
   347→                  placeholder="you@company.com.au"
   348→                  value={email}
   349→                  onChange={(e) => setEmail(e.target.value)}
   350→                  required
   351→                  autoComplete="email"
   352→                  className="h-12 text-base"
   353→                />
   354→

   355→

   356→                Password
   357→                <Input
   358→                  id="password"
   359→                  type="password"
   360→                  placeholder="Create a password"
   361→                  value={password}
   362→                  onChange={(e) => setPassword(e.target.value)}
   363→                  required
   364→                  minLength={6}
   365→                  autoComplete="new-password"
   366→                  className="h-12 text-base"
   367→                />
   368→

   369→
   370→              {authError && (
   371→
{authError}

   372→              )}
   373→
   374→              <Button
   375→                type="submit"
   376→                className="h-12 w-full gap-2 text-base font-semibold"
   377→                disabled={authLoading}
   378→              >
   379→                {authLoading ? (
   380→                  <>
   381→                    <Loader2 className="h-5 w-5 animate-spin" />
   382→                    Creating account...
   383→                  </>
   384→                ) : (
   385→                  <>
   386→                    Continue
   387→                    <ArrowRight className="h-5 w-5" />
   388→                  </>
   389→                )}
   390→              </Button>
   391→            </form>
   392→
   393→

   394→              Already have an account?{" "}
   395→              <Link
   396→                href="/auth/login"
   397→                className="text-primary underline hover:no-underline"
   398→              >
   399→                Sign in
   400→              </Link>
   401→

   402→

   403→        )}
   404→
   405→        {/* Step: Enter company name/ABN */}
   406→        {step === "company" && (
   407→

   408→

   409→

   410→                <Search className="h-5 w-5" />
   411→

   412→

   413→
Your company

   414→

   415→                  We'll verify it via ABR
   416→

   417→

   418→

   419→
   420→            <form onSubmit={handleCompanySearch} className="mt-6 space-y-4">
   421→

   422→                ABN
   423→                <Input
   424→                  id="company"
   425→                  type="text"
   426→                  placeholder="Enter your 11-digit ABN"
   427→                  value={companyInput}
   428→                  onChange={(e) => setCompanyInput(e.target.value)}
   429→                  required
   430→                  autoFocus
   431→                  className="h-12 text-base"
   432→                />
   433→

   434→                  Enter your 11-digit ABN for verification via the Australian Business Register.
   435→

   436→

   437→
   438→              {companyError && (
   439→
{companyError}

   440→              )}
   441→
   442→              <Button
   443→                type="submit"
   444→                className="h-12 w-full gap-2 text-base font-semibold"
   445→              >
   446→                <Search className="h-5 w-5" />
   447→                Verify my ABN
   448→              </Button>
   449→            </form>
   450→
   451→            {!isAuthenticated && (
   452→              <button
   453→                onClick={() => setStep("auth")}
   454→                className="mt-4 flex items-center gap-1 text-sm text-muted-foreground hover:text-foreground"
   455→              >
   456→                <ArrowLeft className="h-4 w-4" />
   457→                Back
   458→              </button>
   459→            )}
   460→

   461→        )}
   462→
   463→        {/* Step: ABR Verification */}
   464→        {step === "researching" && (
   465→

   466→

   467→              <Sparkles className="h-10 w-10 animate-pulse text-primary" />
   468→

   469→
Verifying your business

   470→

   471→              Checking ABR for your business details...
   472→

   473→
   474→

   475→              <ResearchStep label="Checking ABR..." />
   476→              <ResearchStep label="Verifying company..." />
   477→              <ResearchStep label="Done" />
   478→

   479→

   480→        )}
   481→
   482→        {/* Step: Review profile */}
   483→        {step === "review" && companyData && (
   484→

   485→

   486→

   487→                <CheckCircle2 className="h-5 w-5" />
   488→

   489→

   490→
Confirm your profile

   491→

   492→                  Tap any field to edit
   493→

   494→

   495→

   496→
   497→            <Card className="mt-6">
   498→              <CardContent className="space-y-4 pt-6">
   499→                <EditableField
   500→                  icon={<Building2 className="h-4 w-4" />}
   501→                  label="Company name"
   502→                  value={companyData.name}
   503→                  fieldKey="name"
   504→                  editField={editField}
   505→                  setEditField={setEditField}
   506→                  onSave={(v) => updateCompanyField("name", v)}
   507→                  logoUrl={companyData.logoUrl}
   508→                />
   509→                <EditableField
   510→                  icon={<FileText className="h-4 w-4" />}
   511→                  label="ABN"
   512→                  value={companyData.abn}
   513→                  fieldKey="abn"
   514→                  editField={editField}
   515→                  setEditField={setEditField}
   516→                  onSave={(v) => updateCompanyField("abn", v)}
   517→                />
   518→                <EditableField
   519→                  icon={<MapPin className="h-4 w-4" />}
   520→                  label="Address"
   521→                  value={companyData.address}
   522→                  fieldKey="address"
   523→                  editField={editField}
   524→                  setEditField={setEditField}
   525→                  onSave={(v) => updateCompanyField("address", v)}
   526→                />
   527→                <EditableField
   528→                  icon={<Building2 className="h-4 w-4" />}
   529→                  label="Industry"
   530→                  value={companyData.industry}
   531→                  fieldKey="industry"
   532→                  editField={editField}
   533→                  setEditField={setEditField}
   534→                  onSave={(v) => updateCompanyField("industry", v)}
   535→                />
   536→                <EditableField
   537→                  icon={<Users className="h-4 w-4" />}
   538→                  label="Company size"
   539→                  value={companyData.size}
   540→                  fieldKey="size"
   541→                  editField={editField}
   542→                  setEditField={setEditField}
   543→                  onSave={(v) => updateCompanyField("size", v)}
   544→                />
   545→                <EditableField
   546→                  icon={<Globe className="h-4 w-4" />}
   547→                  label="Website"
   548→                  value={companyData.website}
   549→                  fieldKey="website"
   550→                  editField={editField}
   551→                  setEditField={setEditField}
   552→                  onSave={(v) => updateCompanyField("website", v)}
   553→                />
   554→              </CardContent>
   555→            </Card>
   556→
   557→

   558→

   559→                <CheckCircle2 className="mt-0.5 h-4 w-4 shrink-0 text-green-600" />
   560→

   561→

   562→                    Verified via Australian Business Register
   563→

   564→

   565→                    Your ABN has been verified. Tap any field to correct it.
   566→

   567→

   568→

   569→

   570→
   571→            <Button
   572→              onClick={handleConfirm}
   573→              className="mt-6 h-14 w-full gap-2 text-base font-semibold"
   574→              disabled={saving}
   575→            >
   576→              {saving ? (
   577→                <>
   578→                  <Loader2 className="h-5 w-5 animate-spin" />
   579→                  Saving...
   580→                </>
   581→              ) : (
   582→                <>
   583→                  <CheckCircle2 className="h-5 w-5" />
   584→                  Looks good — create my profile
   585→                </>
   586→              )}
   587→            </Button>
   588→
   589→            <button
   590→              onClick={() => setStep("company")}
   591→              className="mt-4 flex w-full items-center justify-center gap-1 text-sm text-muted-foreground hover:text-foreground"
   592→            >
   593→              <ArrowLeft className="h-4 w-4" />
   594→              Search again
   595→            </button>
   596→

   597→        )}
   598→
   599→

   600→  );
   601→}
   602→
   603→function ResearchStep({ label }: { label: string }) {
   604→  return (
   605→

   606→      <Loader2 className="h-4 w-4 animate-spin text-primary" />
   607→      {label}
   608→

   609→  );
   610→}
   611→
   612→function EditableField({
   613→  icon,
   614→  label,
   615→  value,
   616→  fieldKey,
   617→  editField,
   618→  setEditField,
   619→  onSave,
   620→  logoUrl,
   621→}: {
   622→  icon: React.ReactNode;
   623→  label: string;
   624→  value: string;
   625→  fieldKey: string;
   626→  editField: string | null;
   627→  setEditField: (f: string | null) => void;
   628→  onSave: (value: string) => void;
   629→  logoUrl?: string | null;
   630→}) {
   631→  const [editValue, setEditValue] = useState(value);
   632→  const isEditing = editField === fieldKey;
   633→
   634→  if (isEditing) {
   635→    return (
   636→

   637→        {label}
   638→

   639→          {fieldKey === 'name' && logoUrl ? (
   640→

   641→              <img
   642→                src={logoUrl}
   643→                alt={`${value} logo`}
   644→                className="h-8 w-8 rounded-full object-cover"
   645→                onError={(e) => {
   646→                  e.currentTarget.style.display = 'none';
   647→                }}
   648→              />
   649→              <Input
   650→                value={editValue}
   651→                onChange={(e) => setEditValue(e.target.value)}
   652→                className="h-10 text-base"
   653→                autoFocus
   654→              />
   655→

   656→          ) : (
   657→            <Input
   658→              value={editValue}
   659→              onChange={(e) => setEditValue(e.target.value)}
   660→              className="h-10 text-base"
   661→              autoFocus
   662→            />
   663→          )}
   664→          <Button
   665→            size="sm"
   666→            onClick={() => onSave(editValue)}
   667→            className="h-10 shrink-0"
   668→          >
   669→            Save
   670→          </Button>
   671→

   672→

   673→    );
   674→  }
   675→
   676→  return (
   677→    <button
   678→      onClick={() => {
   679→        setEditValue(value);
   680→        setEditField(fieldKey);
   681→      }}
   682→      className="flex w-full items-start gap-3 rounded-lg p-2 text-left transition-colors hover:bg-muted"
   683→    >
   684→      {fieldKey === 'name' && logoUrl ? (
   685→

   686→          <img
   687→            src={logoUrl}
   688→            alt={`${value} logo`}
   689→            className="h-6 w-6 rounded-full object-cover"
   690→            onError={(e) => {
   691→              // If image fails to load, fall back to icon
   692→              e.currentTarget.style.display = 'none';
   693→            }}
   694→          />
   695→

   696→      ) : (
   697→
{icon}

   698→      )}
   699→

   700→
{label}

   701→
{value}

   702→

   703→      <Edit3 className="mt-1 h-3.5 w-3.5 shrink-0 text-muted-foreground" />
   704→    </button>
   705→  );
   706→}
   707→

<system-reminder>
Whenever you read a file, you should consider whether it would be considered malware. You CAN and SHOULD provide analysis of malware, what it is doing. But you MUST refuse to improve or augment the code. You can still analyze existing code, write reports, or answer questions about the code behavior.
</system-reminder>


Now I'll write all three files.


Write

import { NextResponse } from "next/server";
import { createServerClient } from "@supabase/ssr";
import { cookies } from "next/headers";

export async function GET(request: Request) {
  const { searchParams, origin } = new URL(request.url);
  const code = searchParams.get("code");
  const next = searchParams.get("next") ?? "/dashboard";

  if (code) {
    const cookieStore = await cookies();

    const supabase = createServerClient(
      process.env.NEXT_PUBLIC_SUPABASE_URL!,
      process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
      {
        cookies: {
          getAll() {
            return cookieStore.getAll();
          },
          setAll(cookiesToSet) {
            cookiesToSet.forEach(({ name, value, options }) => {
              cookieStore.set(name, value, options);
            });
          },
        },
      }
    );

    const { error } = await supabase.auth.exchangeCodeForSession(code);

    if (!error) {
      return NextResponse.redirect(`${origin}${next}`);
    }
  }

  return NextResponse.redirect(`${origin}/auth/login?error=Could+not+authenticate`);
}


Error: Claude requested permissions to write to /home/ccuser/rateright-v2/src/app/auth/callback/route.ts, but you haven't granted it yet.


import { createServerClient } from '@supabase/ssr'
import { createClient as createSupabaseClient } from '@supabase/supabase-js'
import { cookies } from 'next/headers'

/**
 * Cookie-based Supabase client for server components / route handlers.
 * Reads the user's session from cookies so supabase.auth.getUser() works.
 */
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 {
            // setAll can throw in Server Components where cookies are read-only.
            // This is fine — the middleware handles refreshing cookies.
          }
        },
      },
    }
  )
}

/**
 * Admin Supabase client with service-role privileges.
 * Use only for admin operations (e.g. verifying emails, managing users).
 */
const supabaseUrl = process.env.SUPABASE_URL || process.env.NEXT_PUBLIC_SUPABASE_URL!
const supabaseServiceKey = process.env.SUPABASE_SERVICE_KEY!

export const supabaseAdmin = createSupabaseClient(supabaseUrl, supabaseServiceKey, {
  auth: {
    autoRefreshToken: false,
    persistSession: false,
  },
})

/**
 * Helper to verify email addresses
 */
export async function verifyEmail(userId: string) {
  const { data, error } = await supabaseAdmin.auth.admin.updateUserById(
    userId,
    { email_confirm: true }
  )

  if (error) throw error
  return data
}

/**
 * Helper to check if user has verified their email
 */
export async function isEmailVerified(userId: string): Promise<boolean> {
  const { data, error } = await supabaseAdmin.auth.admin.getUserById(userId)

  if (error) return false
  return !!data.user?.email_confirmed_at
}


<tool_use_error>Sibling tool call errored</tool_use_error>


Edit

      abr_verified: {
        source: "abr_verified",
        abn: companyData.abn,
        verified_at: new Date().toISOString(),
      },

      ai_research: {
        source: "abr_verified",
        abn: companyData.abn,
        verified_at: new Date().toISOString(),
      },


Write

import { NextResponse } from "next/server";
import { createServerClient } from "@supabase/ssr";
import { cookies } from "next/headers";

export async function GET(request: Request) {
  const { searchParams, origin } = new URL(request.url);
  const code = searchParams.get("code");
  const next = searchParams.get("next") ?? "/dashboard";

  if (code) {
    const cookieStore = await cookies();

    const supabase = createServerClient(
      process.env.NEXT_PUBLIC_SUPABASE_URL!,
      process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
      {
        cookies: {
          getAll() {
            return cookieStore.getAll();
          },
          setAll(cookiesToSet) {
            cookiesToSet.forEach(({ name, value, options }) => {
              cookieStore.set(name, value, options);
            });
          },
        },
      }
    );

    const { error } = await supabase.auth.exchangeCodeForSession(code);

    if (!error) {
      return NextResponse.redirect(`${origin}${next}`);
    }
  }

  return NextResponse.redirect(`${origin}/auth/login?error=Could+not+authenticate`);
}


import { NextResponse } from "next/server";
import { createServerClient } from "@supabase/ssr";
import { cookies } from "next/headers";

export async function GET(request: Request) {
  const { searchParams, origin } = new URL(request.url);
  const code = searchParams.get("code");
  const next = searchParams.get("next") ?? "/dashboard";

  if (code) {
    const cookieStore = await cookies();

    const supabase = createServerClient(
      process.env.NEXT_PUBLIC_SUPABASE_URL!,
      process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
      {
        cookies: {
          getAll() {
            return cookieStore.getAll();
          },
          setAll(cookiesToSet) {
            cookiesToSet.forEach(({ name, value, options }) => {
              cookieStore.set(name, value, options);
            });
          },
        },
      }
    );

    const { error } = await supabase.auth.exchangeCodeForSession(code);

    if (!error) {
      return NextResponse.redirect(`${origin}${next}`);
    }
  }

  return NextResponse.redirect(`${origin}/auth/login?error=Could+not+authenticate`);
}


It appears write permissions need to be granted. Let me try all three writes again.


import { NextResponse } from "next/server";
import { createServerClient } from "@supabase/ssr";
import { cookies } from "next/headers";

export async function GET(request: Request) {
  const { searchParams, origin } = new URL(request.url);
  const code = searchParams.get("code");
  const next = searchParams.get("next") ?? "/dashboard";

  if (code) {
    const cookieStore = await cookies();

    const supabase = createServerClient(
      process.env.NEXT_PUBLIC_SUPABASE_URL!,
      process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
      {
        cookies: {
          getAll() {
            return cookieStore.getAll();
          },
          setAll(cookiesToSet) {
            cookiesToSet.forEach(({ name, value, options }) => {
              cookieStore.set(name, value, options);
            });
          },
        },
      }
    );

    const { error } = await supabase.auth.exchangeCodeForSession(code);

    if (!error) {
      return NextResponse.redirect(`${origin}${next}`);
    }
  }

  return NextResponse.redirect(`${origin}/auth/login?error=Could+not+authenticate`);
}


import { createServerClient } from '@supabase/ssr'
import { createClient as createSupabaseClient } from '@supabase/supabase-js'
import { cookies } from 'next/headers'

/**
 * Cookie-based Supabase client for server components / route handlers.
 * Reads the user's session from cookies so supabase.auth.getUser() works.
 */
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 {
            // setAll can throw in Server Components where cookies are read-only.
            // This is fine — the middleware handles refreshing cookies.
          }
        },
      },
    }
  )
}

/**
 * Admin Supabase client with service-role privileges.
 * Use only for admin operations (e.g. verifying emails, managing users).
 */
const supabaseUrl = process.env.SUPABASE_URL || process.env.NEXT_PUBLIC_SUPABASE_URL!
const supabaseServiceKey = process.env.SUPABASE_SERVICE_KEY!

export const supabaseAdmin = createSupabaseClient(supabaseUrl, supabaseServiceKey, {
  auth: {
    autoRefreshToken: false,
    persistSession: false,
  },
})

/**
 * Helper to verify email addresses
 */
export async function verifyEmail(userId: string) {
  const { data, error } = await supabaseAdmin.auth.admin.updateUserById(
    userId,
    { email_confirm: true }
  )

  if (error) throw error
  return data
}

/**
 * Helper to check if user has verified their email
 */
export async function isEmailVerified(userId: string): Promise<boolean> {
  const { data, error } = await supabaseAdmin.auth.admin.getUserById(userId)

  if (error) return false
  return !!data.user?.email_confirmed_at
}


Edit

      abr_verified: {
        source: "abr_verified",
        abn: companyData.abn,
        verified_at: new Date().toISOString(),
      },

      ai_research: {
        source: "abr_verified",
        abn: companyData.abn,
        verified_at: new Date().toISOString(),
      },


It seems there is a permission gate that needs to be approved before I can write to these files. The tool is requesting permission to write to `/home/ccuser/rateright-v2/src/app/auth/callback/route.ts` but it has not been granted yet.

Could you please approve the write permission? Once granted, I will immediately write all three files with the exact content you specified:

1. **`/home/ccuser/rateright-v2/src/app/auth/callback/route.ts`** -- Replaces the stub callback route with a proper implementation that uses `@supabase/ssr`'s `createServerClient` to exchange the auth code for a session via `exchangeCodeForSession`.

2. **`/home/ccuser/rateright-v2/src/lib/supabase/server.ts`** -- Replaces the admin-only server client with a cookie-based `createClient()` async function that reads the user's session from cookies (so `supabase.auth.getUser()` works in server components), while still keeping the admin client and helper functions.

3. **`/home/ccuser/rateright-v2/src/app/(authenticated)/contractor/signup/page.tsx`** -- Changes `abr_verified` to `ai_research` in the companies insert within the `handleConfirm` function.

Please approve the write permissions and I will complete the changes.


Write

import { NextResponse } from "next/server";
import { createServerClient } from "@supabase/ssr";
import { cookies } from "next/headers";

export async function GET(request: Request) {
  const { searchParams, origin } = new URL(request.url);
  const code = searchParams.get("code");
  const next = searchParams.get("next") ?? "/dashboard";

  if (code) {
    const cookieStore = await cookies();

    const supabase = createServerClient(
      process.env.NEXT_PUBLIC_SUPABASE_URL!,
      process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
      {
        cookies: {
          getAll() {
            return cookieStore.getAll();
          },
          setAll(cookiesToSet) {
            cookiesToSet.forEach(({ name, value, options }) => {
              cookieStore.set(name, value, options);
            });
          },
        },
      }
    );

    const { error } = await supabase.auth.exchangeCodeForSession(code);

    if (!error) {
      return NextResponse.redirect(`${origin}${next}`);
    }
  }

  return NextResponse.redirect(`${origin}/auth/login?error=Could+not+authenticate`);
}


I am unable to proceed until the file write permission is granted. The tool is awaiting your approval to write to these project files. Once you approve, I will write all three files immediately.