docs: Update architecture for supabase

test: Add tests for auth workflow
This commit is contained in:
2026-04-12 10:14:44 -04:00
parent 355f3c5dfa
commit c789454810
13 changed files with 900 additions and 14 deletions

View File

@@ -1,10 +1,7 @@
import { checkAuthRedirect } from '~/utils/auth'
export default defineNuxtRouteMiddleware((to) => {
const user = useSupabaseUser()
const publicRoutes = ['/', '/login', '/signup', '/auth/callback']
if (publicRoutes.includes(to.path)) return
if (!user.value) {
return navigateTo('/')
}
const redirect = checkAuthRedirect(user.value, to.path)
if (redirect) return navigateTo(redirect)
})

View File

@@ -1,13 +1,59 @@
<template>
<IonPage>
<IonContent class="ion-padding ion-text-center">
<p>Signing you in...</p>
<div class="callback-state">
<IonSpinner v-if="!errorMessage" name="crescent" class="callback-spinner" />
<IonIcon v-else :icon="alertCircleOutline" class="callback-error-icon" color="danger" />
<p>{{ errorMessage || 'Signing you in...' }}</p>
</div>
</IonContent>
</IonPage>
</template>
<script setup lang="ts">
import { IonPage, IonContent } from '@ionic/vue'
import { IonPage, IonContent, IonSpinner, IonIcon } from '@ionic/vue'
import { alertCircleOutline } from 'ionicons/icons'
definePageMeta({ layout: false })
const supabase = useSupabaseClient()
const user = useSupabaseUser()
const route = useRoute()
const errorMessage = ref('')
onMounted(async () => {
const code = route.query.code as string | undefined
if (code) {
const { error } = await supabase.auth.exchangeCodeForSession(code)
if (error) {
errorMessage.value = 'Sign-in failed. Please try again.'
return
}
}
})
// Navigate home once session is established (handles both hash-based and PKCE flows)
watch(user, (value) => {
if (value) navigateTo('/')
}, { immediate: true })
</script>
<style scoped>
.callback-state {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 100%;
gap: 1rem;
}
.callback-spinner {
width: 2.5rem;
height: 2.5rem;
}
.callback-error-icon {
font-size: 2.5rem;
}
</style>

14
app/utils/auth.ts Normal file
View File

@@ -0,0 +1,14 @@
export const PUBLIC_ROUTES = ['/', '/login', '/signup', '/auth/callback'] as const
/**
* Pure auth decision logic — no Nuxt/Supabase dependencies.
* Returns the path to redirect to, or null if no redirect is needed.
*/
export function checkAuthRedirect(
userValue: { id: string } | null,
path: string,
): string | null {
if ((PUBLIC_ROUTES as readonly string[]).includes(path)) return null
if (!userValue) return '/'
return null
}