Content loader utility, Content directory structuur
This commit is contained in:
43
lib/content/loader.ts
Normal file
43
lib/content/loader.ts
Normal file
@@ -0,0 +1,43 @@
|
||||
/**
|
||||
* Content Loader Utility
|
||||
*
|
||||
* Loads JSON content files from the content directory structure.
|
||||
* Supports server-side loading with TypeScript type safety.
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* const manifesto = await getContent<ManifestoContent>('nl', 'manifesto')
|
||||
* ```
|
||||
*/
|
||||
|
||||
export async function getContent<T>(
|
||||
locale: string = 'nl',
|
||||
file: string
|
||||
): Promise<T> {
|
||||
try {
|
||||
const content = await import(`@/content/${locale}/${file}.json`)
|
||||
return content.default as T
|
||||
} catch (error) {
|
||||
console.error(`Failed to load content: ${locale}/${file}.json`, error)
|
||||
throw new Error(`Content not found: ${locale}/${file}.json`)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Type-safe content loader with fallback
|
||||
*
|
||||
* Returns default content if file is not found (useful for development)
|
||||
*/
|
||||
export async function getContentWithFallback<T>(
|
||||
locale: string = 'nl',
|
||||
file: string,
|
||||
fallback: T
|
||||
): Promise<T> {
|
||||
try {
|
||||
return await getContent<T>(locale, file)
|
||||
} catch (error) {
|
||||
console.warn(`Using fallback content for: ${locale}/${file}.json`)
|
||||
return fallback
|
||||
}
|
||||
}
|
||||
|
||||
67
lib/supabase/README.md
Normal file
67
lib/supabase/README.md
Normal file
@@ -0,0 +1,67 @@
|
||||
# Supabase Configuration
|
||||
|
||||
Deze folder bevat de Supabase client configuratie voor het Mini-EPD project.
|
||||
|
||||
## Bestanden
|
||||
|
||||
- **`client.ts`** - Client-side Supabase client (browser-safe, gebruikt anon key)
|
||||
- **`server.ts`** - Server-side Supabase client (admin, gebruikt service role key)
|
||||
- **`types.ts`** - TypeScript types (auto-gegenereerd uit database schema)
|
||||
- **`index.ts`** - Export file voor makkelijke imports
|
||||
|
||||
## Gebruik
|
||||
|
||||
### Client-side (React components)
|
||||
```typescript
|
||||
import { supabase } from '@/lib/supabase'
|
||||
|
||||
// Voorbeeld: ophalen van clients
|
||||
const { data, error } = await supabase
|
||||
.from('clients')
|
||||
.select('*')
|
||||
```
|
||||
|
||||
### Server-side (API routes, Server Components)
|
||||
```typescript
|
||||
import { supabaseAdmin } from '@/lib/supabase/server'
|
||||
|
||||
// Voorbeeld: admin operatie
|
||||
const { data, error } = await supabaseAdmin
|
||||
.from('clients')
|
||||
.insert({ ... })
|
||||
```
|
||||
|
||||
## TypeScript Types Genereren
|
||||
|
||||
Na het aanmaken van database schema (EP01), run:
|
||||
|
||||
```bash
|
||||
pnpm run types:generate
|
||||
```
|
||||
|
||||
Dit genereert TypeScript types uit je Supabase database schema.
|
||||
|
||||
## Environment Variables
|
||||
|
||||
Zorg dat deze variabelen in `.env.local` staan:
|
||||
|
||||
```env
|
||||
NEXT_PUBLIC_SUPABASE_URL=https://dqugbrpwtisgyxscpefg.supabase.co
|
||||
NEXT_PUBLIC_SUPABASE_ANON_KEY=...
|
||||
SUPABASE_SERVICE_ROLE_KEY=...
|
||||
```
|
||||
|
||||
## Security
|
||||
|
||||
⚠️ **Belangrijk:**
|
||||
- `NEXT_PUBLIC_*` variabelen zijn zichtbaar in de browser
|
||||
- `SUPABASE_SERVICE_ROLE_KEY` moet **NOOIT** naar de client worden gestuurd
|
||||
- Gebruik `supabase` (client) voor frontend operaties
|
||||
- Gebruik `supabaseAdmin` (server) alleen in API routes en Server Components
|
||||
|
||||
## Volgende Stappen
|
||||
|
||||
1. ✅ EP00-ST03: Supabase configuratie (Done)
|
||||
2. ⏳ EP01-ST01: Database schema aanmaken
|
||||
3. ⏳ EP01-ST02: Row Level Security policies
|
||||
4. ⏳ EP02-ST01: Authentication implementeren
|
||||
20
lib/supabase/client.ts
Normal file
20
lib/supabase/client.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
import { createClient } from '@supabase/supabase-js'
|
||||
|
||||
const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL!
|
||||
const supabaseAnonKey = process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!
|
||||
|
||||
if (!supabaseUrl || !supabaseAnonKey) {
|
||||
throw new Error('Missing Supabase environment variables. Check your .env.local file.')
|
||||
}
|
||||
|
||||
/**
|
||||
* Supabase client for client-side operations.
|
||||
* Uses anon key - safe for browser/frontend.
|
||||
* Row Level Security (RLS) policies apply.
|
||||
*/
|
||||
export const supabase = createClient(supabaseUrl, supabaseAnonKey, {
|
||||
auth: {
|
||||
persistSession: true,
|
||||
autoRefreshToken: true,
|
||||
},
|
||||
})
|
||||
6
lib/supabase/index.ts
Normal file
6
lib/supabase/index.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
// Export Supabase clients
|
||||
export { supabase } from './client'
|
||||
export { supabaseAdmin } from './server'
|
||||
|
||||
// Export types (will be generated later)
|
||||
export type { Database } from './types'
|
||||
25
lib/supabase/server.ts
Normal file
25
lib/supabase/server.ts
Normal file
@@ -0,0 +1,25 @@
|
||||
import { createClient } from '@supabase/supabase-js'
|
||||
|
||||
const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL!
|
||||
const supabaseServiceRoleKey = process.env.SUPABASE_SERVICE_ROLE_KEY!
|
||||
|
||||
if (!supabaseUrl || !supabaseServiceRoleKey) {
|
||||
throw new Error('Missing Supabase server environment variables. Check your .env.local file.')
|
||||
}
|
||||
|
||||
/**
|
||||
* Supabase client for server-side operations.
|
||||
* Uses service role key - NEVER expose to client!
|
||||
* Bypasses Row Level Security (RLS) - use with caution.
|
||||
*
|
||||
* Use this for:
|
||||
* - API routes that need admin access
|
||||
* - Database migrations/seeding
|
||||
* - Server-side operations
|
||||
*/
|
||||
export const supabaseAdmin = createClient(supabaseUrl, supabaseServiceRoleKey, {
|
||||
auth: {
|
||||
autoRefreshToken: false,
|
||||
persistSession: false,
|
||||
},
|
||||
})
|
||||
33
lib/supabase/test-connection.ts
Normal file
33
lib/supabase/test-connection.ts
Normal file
@@ -0,0 +1,33 @@
|
||||
/**
|
||||
* Test script to verify Supabase connection
|
||||
* Run with: node --loader tsx lib/supabase/test-connection.ts
|
||||
*/
|
||||
|
||||
import { supabase } from './client'
|
||||
|
||||
async function testConnection() {
|
||||
console.log('🔗 Testing Supabase connection...')
|
||||
|
||||
try {
|
||||
// Test basic connection
|
||||
const { data, error } = await supabase.from('_prisma_migrations').select('*').limit(1)
|
||||
|
||||
if (error && error.code !== 'PGRST204') {
|
||||
// PGRST204 = table doesn't exist yet, which is fine
|
||||
console.log('⚠️ Connection works, but database schema not yet created')
|
||||
console.log(' Run EP01 migrations to create tables')
|
||||
} else {
|
||||
console.log('✅ Supabase connection successful!')
|
||||
}
|
||||
|
||||
// Show project info
|
||||
const url = process.env.NEXT_PUBLIC_SUPABASE_URL
|
||||
console.log(`📍 Project: ${url}`)
|
||||
|
||||
} catch (err) {
|
||||
console.error('❌ Connection failed:', err)
|
||||
process.exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
testConnection()
|
||||
39
lib/supabase/types.ts
Normal file
39
lib/supabase/types.ts
Normal file
@@ -0,0 +1,39 @@
|
||||
/**
|
||||
* Supabase Database Types
|
||||
*
|
||||
* This file will be auto-generated from your Supabase schema.
|
||||
* Run: pnpm run types:generate
|
||||
*
|
||||
* For now, this is a placeholder. Once you create your database schema (EP01),
|
||||
* you can generate types using the Supabase CLI.
|
||||
*/
|
||||
|
||||
export type Json =
|
||||
| string
|
||||
| number
|
||||
| boolean
|
||||
| null
|
||||
| { [key: string]: Json | undefined }
|
||||
| Json[]
|
||||
|
||||
export interface Database {
|
||||
public: {
|
||||
Tables: {
|
||||
// Tables will be generated here after schema is created
|
||||
[key: string]: {
|
||||
Row: Record<string, unknown>
|
||||
Insert: Record<string, unknown>
|
||||
Update: Record<string, unknown>
|
||||
}
|
||||
}
|
||||
Views: {
|
||||
[_ in never]: never
|
||||
}
|
||||
Functions: {
|
||||
[_ in never]: never
|
||||
}
|
||||
Enums: {
|
||||
[_ in never]: never
|
||||
}
|
||||
}
|
||||
}
|
||||
6
lib/utils.ts
Normal file
6
lib/utils.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
import { clsx, type ClassValue } from "clsx"
|
||||
import { twMerge } from "tailwind-merge"
|
||||
|
||||
export function cn(...inputs: ClassValue[]) {
|
||||
return twMerge(clsx(inputs))
|
||||
}
|
||||
Reference in New Issue
Block a user