docs(01): create phase 1 plans - Foundation & Auth
Phase 01: Foundation & Auth - 6 plans in 4 execution waves - Wave 1: Project setup (01) + Database schema (02) [parallel] - Wave 2: Email/password auth (03) + Google OAuth (04) [parallel] - Wave 3: Middleware & route protection (05) - Wave 4: Subscription management UI (06) Requirements covered: AUTH-01, AUTH-02, AUTH-03 Ready for execution Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
450
.planning/phases/01-foundation-auth/01-04-PLAN.md
Normal file
450
.planning/phases/01-foundation-auth/01-04-PLAN.md
Normal file
@@ -0,0 +1,450 @@
|
||||
---
|
||||
phase: 01-foundation-auth
|
||||
plan: 04
|
||||
type: execute
|
||||
wave: 2
|
||||
depends_on: ["01-01", "01-02"]
|
||||
files_modified:
|
||||
- src/components/auth/google-button.tsx
|
||||
- src/app/(auth)/login/page.tsx
|
||||
- src/app/(auth)/register/page.tsx
|
||||
- docs/GOOGLE_OAUTH_SETUP.md
|
||||
autonomous: true
|
||||
user_setup:
|
||||
- service: google-cloud
|
||||
why: "Google OAuth for social login"
|
||||
env_vars: []
|
||||
dashboard_config:
|
||||
- task: "Create OAuth 2.0 Client ID"
|
||||
location: "Google Cloud Console -> APIs & Services -> Credentials"
|
||||
- task: "Add authorized JavaScript origins"
|
||||
location: "OAuth Client -> Authorized JavaScript origins"
|
||||
value: "http://localhost:3000, https://your-domain.com"
|
||||
- task: "Add authorized redirect URI"
|
||||
location: "OAuth Client -> Authorized redirect URIs"
|
||||
value: "https://<project-ref>.supabase.co/auth/v1/callback"
|
||||
- service: supabase
|
||||
why: "Enable Google OAuth provider"
|
||||
env_vars: []
|
||||
dashboard_config:
|
||||
- task: "Enable Google provider"
|
||||
location: "Supabase Dashboard -> Authentication -> Providers -> Google"
|
||||
- task: "Paste Google Client ID and Secret"
|
||||
location: "Same settings page"
|
||||
|
||||
must_haves:
|
||||
truths:
|
||||
- "User can click 'Accedi con Google' button"
|
||||
- "User is redirected to Google consent screen"
|
||||
- "User returns to app authenticated after consent"
|
||||
- "User session persists after Google login"
|
||||
artifacts:
|
||||
- path: "src/components/auth/google-button.tsx"
|
||||
provides: "Google Sign-In button component"
|
||||
exports: ["GoogleSignInButton"]
|
||||
- path: "docs/GOOGLE_OAUTH_SETUP.md"
|
||||
provides: "Setup instructions for Google OAuth"
|
||||
contains: "Google Cloud Console"
|
||||
key_links:
|
||||
- from: "src/components/auth/google-button.tsx"
|
||||
to: "Supabase Auth"
|
||||
via: "signInWithOAuth"
|
||||
pattern: "signInWithOAuth.*google"
|
||||
- from: "Google OAuth"
|
||||
to: "src/app/auth/callback/route.ts"
|
||||
via: "redirect after consent"
|
||||
pattern: "auth/callback"
|
||||
---
|
||||
|
||||
<objective>
|
||||
Implement Google OAuth login allowing users to sign in with their Google account.
|
||||
|
||||
Purpose: Enable social login per AUTH-02 requirement. Google OAuth provides frictionless registration/login.
|
||||
|
||||
Output: Working Google Sign-In button that authenticates users and creates their profile automatically.
|
||||
</objective>
|
||||
|
||||
<execution_context>
|
||||
@C:\Users\miche\.claude/get-shit-done/workflows/execute-plan.md
|
||||
@C:\Users\miche\.claude/get-shit-done/templates/summary.md
|
||||
</execution_context>
|
||||
|
||||
<context>
|
||||
@.planning/PROJECT.md
|
||||
@.planning/ROADMAP.md
|
||||
@.planning/phases/01-foundation-auth/01-RESEARCH.md
|
||||
@.planning/phases/01-foundation-auth/01-01-SUMMARY.md
|
||||
@.planning/phases/01-foundation-auth/01-02-SUMMARY.md
|
||||
</context>
|
||||
|
||||
<tasks>
|
||||
|
||||
<task type="auto">
|
||||
<name>Task 1: Create Google Sign-In button component</name>
|
||||
<files>
|
||||
src/components/auth/google-button.tsx
|
||||
</files>
|
||||
<action>
|
||||
Create the Google Sign-In button at src/components/auth/google-button.tsx:
|
||||
|
||||
```typescript
|
||||
'use client'
|
||||
|
||||
import { createClient } from '@/lib/supabase/client'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { useState } from 'react'
|
||||
|
||||
// Simple Google icon SVG
|
||||
function GoogleIcon({ className }: { className?: string }) {
|
||||
return (
|
||||
<svg className={className} viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92c-.26 1.37-1.04 2.53-2.21 3.31v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.09z"
|
||||
fill="#4285F4"
|
||||
/>
|
||||
<path
|
||||
d="M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z"
|
||||
fill="#34A853"
|
||||
/>
|
||||
<path
|
||||
d="M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.07H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.93l2.85-2.22.81-.62z"
|
||||
fill="#FBBC05"
|
||||
/>
|
||||
<path
|
||||
d="M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53z"
|
||||
fill="#EA4335"
|
||||
/>
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
|
||||
export function GoogleSignInButton() {
|
||||
const [loading, setLoading] = useState(false)
|
||||
const supabase = createClient()
|
||||
|
||||
async function handleGoogleSignIn() {
|
||||
setLoading(true)
|
||||
|
||||
const { error } = await supabase.auth.signInWithOAuth({
|
||||
provider: 'google',
|
||||
options: {
|
||||
redirectTo: `${window.location.origin}/auth/callback`,
|
||||
queryParams: {
|
||||
access_type: 'offline',
|
||||
prompt: 'consent',
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
if (error) {
|
||||
console.error('Google sign-in error:', error)
|
||||
setLoading(false)
|
||||
}
|
||||
// Note: No need to handle success - user is redirected to Google
|
||||
}
|
||||
|
||||
return (
|
||||
<Button
|
||||
type="button"
|
||||
variant="outline"
|
||||
onClick={handleGoogleSignIn}
|
||||
disabled={loading}
|
||||
className="w-full flex items-center justify-center gap-2"
|
||||
>
|
||||
<GoogleIcon className="w-5 h-5" />
|
||||
{loading ? 'Reindirizzamento...' : 'Accedi con Google'}
|
||||
</Button>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
Key points:
|
||||
- Uses 'use client' since it needs browser APIs
|
||||
- Uses createClient from lib/supabase/client.ts (browser client)
|
||||
- redirectTo points to /auth/callback which handles the code exchange
|
||||
- access_type: 'offline' requests refresh token
|
||||
- prompt: 'consent' ensures user always sees consent screen (good for debugging)
|
||||
- Italian button text per project requirement
|
||||
</action>
|
||||
<verify>
|
||||
- Component file exists
|
||||
- No TypeScript errors
|
||||
- Button renders with Google icon
|
||||
</verify>
|
||||
<done>
|
||||
Google Sign-In button component created with proper OAuth configuration.
|
||||
</done>
|
||||
</task>
|
||||
|
||||
<task type="auto">
|
||||
<name>Task 2: Add Google button to login and register pages</name>
|
||||
<files>
|
||||
src/app/(auth)/login/page.tsx
|
||||
src/app/(auth)/register/page.tsx
|
||||
src/components/auth/login-form.tsx
|
||||
src/components/auth/register-form.tsx
|
||||
</files>
|
||||
<action>
|
||||
Update login page to include Google button. Modify src/app/(auth)/login/page.tsx:
|
||||
|
||||
```typescript
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'
|
||||
import { LoginForm } from '@/components/auth/login-form'
|
||||
import { GoogleSignInButton } from '@/components/auth/google-button'
|
||||
|
||||
export default function LoginPage() {
|
||||
return (
|
||||
<Card>
|
||||
<CardHeader className="text-center">
|
||||
<CardTitle>Accedi a Leopost</CardTitle>
|
||||
<CardDescription>
|
||||
Inserisci le tue credenziali per continuare
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent className="space-y-4">
|
||||
<GoogleSignInButton />
|
||||
|
||||
<div className="relative">
|
||||
<div className="absolute inset-0 flex items-center">
|
||||
<span className="w-full border-t border-gray-300" />
|
||||
</div>
|
||||
<div className="relative flex justify-center text-xs uppercase">
|
||||
<span className="bg-white px-2 text-gray-500">oppure</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<LoginForm />
|
||||
</CardContent>
|
||||
</Card>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
Update register page similarly. Modify src/app/(auth)/register/page.tsx:
|
||||
|
||||
```typescript
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'
|
||||
import { RegisterForm } from '@/components/auth/register-form'
|
||||
import { GoogleSignInButton } from '@/components/auth/google-button'
|
||||
|
||||
export default function RegisterPage() {
|
||||
return (
|
||||
<Card>
|
||||
<CardHeader className="text-center">
|
||||
<CardTitle>Crea il tuo account</CardTitle>
|
||||
<CardDescription>
|
||||
Inizia a usare Leopost gratuitamente
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent className="space-y-4">
|
||||
<GoogleSignInButton />
|
||||
|
||||
<div className="relative">
|
||||
<div className="absolute inset-0 flex items-center">
|
||||
<span className="w-full border-t border-gray-300" />
|
||||
</div>
|
||||
<div className="relative flex justify-center text-xs uppercase">
|
||||
<span className="bg-white px-2 text-gray-500">oppure</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<RegisterForm />
|
||||
</CardContent>
|
||||
</Card>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
The divider uses "oppure" (Italian for "or") to separate social login from email form.
|
||||
Google button appears FIRST (above the form) as it's the faster option.
|
||||
</action>
|
||||
<verify>
|
||||
- Login page shows Google button above email form
|
||||
- Register page shows Google button above email form
|
||||
- "oppure" divider separates the two methods
|
||||
- Pages render without errors
|
||||
</verify>
|
||||
<done>
|
||||
Google Sign-In button integrated into login and registration pages.
|
||||
</done>
|
||||
</task>
|
||||
|
||||
<task type="auto">
|
||||
<name>Task 3: Document Google OAuth setup process</name>
|
||||
<files>
|
||||
docs/GOOGLE_OAUTH_SETUP.md
|
||||
</files>
|
||||
<action>
|
||||
Create comprehensive setup documentation at docs/GOOGLE_OAUTH_SETUP.md:
|
||||
|
||||
```markdown
|
||||
# Google OAuth Setup Guide
|
||||
|
||||
This guide explains how to configure Google OAuth for Leopost.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Google Cloud account
|
||||
- Supabase project created
|
||||
- Access to Supabase Dashboard
|
||||
|
||||
## Step 1: Google Cloud Console Setup
|
||||
|
||||
1. Go to [Google Cloud Console](https://console.cloud.google.com/)
|
||||
|
||||
2. Create a new project or select existing one
|
||||
|
||||
3. Navigate to **APIs & Services > Credentials**
|
||||
|
||||
4. Click **Create Credentials > OAuth client ID**
|
||||
|
||||
5. If prompted, configure the OAuth consent screen:
|
||||
- User Type: External
|
||||
- App name: Leopost
|
||||
- User support email: your email
|
||||
- Developer contact: your email
|
||||
- Scopes: email, profile, openid (default)
|
||||
|
||||
6. Create OAuth Client ID:
|
||||
- Application type: **Web application**
|
||||
- Name: Leopost Web Client
|
||||
|
||||
7. Add **Authorized JavaScript origins**:
|
||||
```
|
||||
http://localhost:3000
|
||||
https://your-production-domain.com
|
||||
```
|
||||
|
||||
8. Add **Authorized redirect URIs**:
|
||||
```
|
||||
https://<your-project-ref>.supabase.co/auth/v1/callback
|
||||
```
|
||||
|
||||
Find your project ref in Supabase Dashboard > Project Settings > General
|
||||
|
||||
9. Click **Create** and save the **Client ID** and **Client Secret**
|
||||
|
||||
## Step 2: Supabase Configuration
|
||||
|
||||
1. Go to [Supabase Dashboard](https://supabase.com/dashboard)
|
||||
|
||||
2. Select your project
|
||||
|
||||
3. Navigate to **Authentication > Providers**
|
||||
|
||||
4. Find **Google** and click to enable
|
||||
|
||||
5. Enter:
|
||||
- **Client ID**: From Google Cloud Console
|
||||
- **Client Secret**: From Google Cloud Console
|
||||
|
||||
6. Copy the **Callback URL** shown (should match what you entered in Google)
|
||||
|
||||
7. Click **Save**
|
||||
|
||||
## Step 3: Environment Variables
|
||||
|
||||
No additional environment variables needed for Google OAuth.
|
||||
The configuration is stored in Supabase Dashboard.
|
||||
|
||||
Your existing `.env.local` should have:
|
||||
```
|
||||
NEXT_PUBLIC_SUPABASE_URL=your-project-url
|
||||
NEXT_PUBLIC_SUPABASE_ANON_KEY=your-anon-key
|
||||
```
|
||||
|
||||
## Step 4: Test the Integration
|
||||
|
||||
1. Start development server: `npm run dev`
|
||||
|
||||
2. Go to http://localhost:3000/login
|
||||
|
||||
3. Click "Accedi con Google"
|
||||
|
||||
4. You should be redirected to Google consent screen
|
||||
|
||||
5. After consent, you should return to the app authenticated
|
||||
|
||||
6. Check Supabase Dashboard > Authentication > Users to verify user was created
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### "redirect_uri_mismatch" error
|
||||
|
||||
The redirect URI in Google Console doesn't match Supabase's callback URL.
|
||||
- Verify the exact URL in Supabase Auth Providers matches Google Console
|
||||
- Check for trailing slashes
|
||||
- Ensure using HTTPS for Supabase callback
|
||||
|
||||
### "Access blocked: This app's request is invalid"
|
||||
|
||||
OAuth consent screen not configured or not published.
|
||||
- Configure OAuth consent screen in Google Cloud Console
|
||||
- For testing, add your email as a test user
|
||||
- For production, submit for verification
|
||||
|
||||
### User created but profile missing
|
||||
|
||||
The database trigger might not have fired.
|
||||
- Check if `on_auth_user_created` trigger exists
|
||||
- Verify `handle_new_user` function has correct permissions
|
||||
- Check Supabase logs for errors
|
||||
|
||||
### Session not persisting
|
||||
|
||||
Middleware might not be refreshing sessions.
|
||||
- Ensure middleware.ts is in project root
|
||||
- Check middleware matcher includes auth routes
|
||||
- Verify cookies are being set correctly
|
||||
|
||||
## Security Notes
|
||||
|
||||
- Never commit Client Secret to version control
|
||||
- For production, publish OAuth consent screen for verification
|
||||
- Use a separate OAuth client for production vs development
|
||||
- Regularly rotate Client Secrets
|
||||
|
||||
## Local Development vs Production
|
||||
|
||||
| Setting | Local | Production |
|
||||
|---------|-------|------------|
|
||||
| JavaScript origins | http://localhost:3000 | https://your-domain.com |
|
||||
| Redirect URI | Same Supabase callback | Same Supabase callback |
|
||||
| Consent screen | Testing mode | Published/Verified |
|
||||
| Test users | Your email added | Not needed |
|
||||
```
|
||||
|
||||
This documentation helps future developers (or the user) configure Google OAuth correctly.
|
||||
</action>
|
||||
<verify>
|
||||
- File exists at docs/GOOGLE_OAUTH_SETUP.md
|
||||
- Contains step-by-step instructions
|
||||
- Includes troubleshooting section
|
||||
- Covers both Google Cloud and Supabase configuration
|
||||
</verify>
|
||||
<done>
|
||||
Google OAuth setup documentation created.
|
||||
</done>
|
||||
</task>
|
||||
|
||||
</tasks>
|
||||
|
||||
<verification>
|
||||
After all tasks complete:
|
||||
1. Google button appears on /login and /register pages
|
||||
2. Clicking button redirects to Google (or shows error if not configured)
|
||||
3. Documentation provides clear setup steps
|
||||
4. No TypeScript or build errors
|
||||
</verification>
|
||||
|
||||
<success_criteria>
|
||||
- GoogleSignInButton component exists and renders
|
||||
- Login/register pages show Google option prominently
|
||||
- Setup documentation is comprehensive
|
||||
- OAuth flow uses correct callback URL (/auth/callback)
|
||||
- Italian text used throughout UI
|
||||
</success_criteria>
|
||||
|
||||
<output>
|
||||
After completion, create `.planning/phases/01-foundation-auth/01-04-SUMMARY.md`
|
||||
</output>
|
||||
Reference in New Issue
Block a user