feat: implement business and user CRUD API endpoints with authentication utilities and update feature documentation
All checks were successful
Build and Push App / build (push) Successful in 5m46s
All checks were successful
Build and Push App / build (push) Successful in 5m46s
This commit is contained in:
@@ -1,5 +1,6 @@
|
|||||||
import { NextRequest, NextResponse } from 'next/server'
|
import { NextRequest, NextResponse } from 'next/server'
|
||||||
import prisma from '@/lib/prisma'
|
import prisma from '@/lib/prisma'
|
||||||
|
import { USER_SAFE_SELECT } from '@/lib/auth-utils'
|
||||||
|
|
||||||
type Params = { params: Promise<{ id: string }> }
|
type Params = { params: Promise<{ id: string }> }
|
||||||
|
|
||||||
@@ -17,7 +18,12 @@ export async function GET(
|
|||||||
{ slug: id }
|
{ slug: id }
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
include: { owner: true, offers: true },
|
include: {
|
||||||
|
owner: {
|
||||||
|
select: USER_SAFE_SELECT
|
||||||
|
},
|
||||||
|
offers: true
|
||||||
|
},
|
||||||
})
|
})
|
||||||
if (!business) return NextResponse.json({ error: 'Non trouvé' }, { status: 404 })
|
if (!business) return NextResponse.json({ error: 'Non trouvé' }, { status: 404 })
|
||||||
return NextResponse.json(business)
|
return NextResponse.json(business)
|
||||||
@@ -38,7 +44,12 @@ export async function PATCH(
|
|||||||
const business = await prisma.business.update({
|
const business = await prisma.business.update({
|
||||||
where: { id },
|
where: { id },
|
||||||
data: body,
|
data: body,
|
||||||
include: { owner: true, offers: true },
|
include: {
|
||||||
|
owner: {
|
||||||
|
select: USER_SAFE_SELECT
|
||||||
|
},
|
||||||
|
offers: true
|
||||||
|
},
|
||||||
})
|
})
|
||||||
return NextResponse.json(business)
|
return NextResponse.json(business)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { NextRequest, NextResponse } from 'next/server'
|
import { NextRequest, NextResponse } from 'next/server'
|
||||||
import prisma from '@/lib/prisma'
|
import prisma from '@/lib/prisma'
|
||||||
|
import { USER_SAFE_SELECT } from '@/lib/auth-utils'
|
||||||
|
|
||||||
// GET /api/businesses — List all businesses (Mock + DB)
|
// GET /api/businesses — List all businesses (Mock + DB)
|
||||||
export async function GET(request: NextRequest) {
|
export async function GET(request: NextRequest) {
|
||||||
@@ -42,7 +43,12 @@ export async function GET(request: NextRequest) {
|
|||||||
|
|
||||||
const dbBusinesses = await prisma.business.findMany({
|
const dbBusinesses = await prisma.business.findMany({
|
||||||
where,
|
where,
|
||||||
include: { owner: true, offers: true },
|
include: {
|
||||||
|
owner: {
|
||||||
|
select: USER_SAFE_SELECT
|
||||||
|
},
|
||||||
|
offers: true
|
||||||
|
},
|
||||||
orderBy: { createdAt: 'desc' },
|
orderBy: { createdAt: 'desc' },
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -135,7 +141,11 @@ export async function POST(request: NextRequest) {
|
|||||||
business = await prisma.business.update({
|
business = await prisma.business.update({
|
||||||
where: { id: existing.id },
|
where: { id: existing.id },
|
||||||
data: cleanData,
|
data: cleanData,
|
||||||
include: { owner: true }
|
include: {
|
||||||
|
owner: {
|
||||||
|
select: USER_SAFE_SELECT
|
||||||
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
// When creating, we add the ownerId to the sanitized cleanData
|
// When creating, we add the ownerId to the sanitized cleanData
|
||||||
@@ -144,7 +154,11 @@ export async function POST(request: NextRequest) {
|
|||||||
...cleanData,
|
...cleanData,
|
||||||
ownerId: ownerId
|
ownerId: ownerId
|
||||||
},
|
},
|
||||||
include: { owner: true }
|
include: {
|
||||||
|
owner: {
|
||||||
|
select: USER_SAFE_SELECT
|
||||||
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Automatic role upgrade
|
// Automatic role upgrade
|
||||||
|
|||||||
@@ -1,11 +1,19 @@
|
|||||||
import { NextRequest, NextResponse } from 'next/server'
|
import { NextRequest, NextResponse } from 'next/server'
|
||||||
import prisma from '@/lib/prisma'
|
import prisma from '@/lib/prisma'
|
||||||
|
import { isAdmin, USER_SAFE_SELECT } from '@/lib/auth-utils'
|
||||||
|
|
||||||
// GET /api/users
|
// GET /api/users
|
||||||
export async function GET() {
|
export async function GET(request: NextRequest) {
|
||||||
try {
|
try {
|
||||||
|
if (!(await isAdmin(request))) {
|
||||||
|
return NextResponse.json({ error: 'Accès non autorisé' }, { status: 403 })
|
||||||
|
}
|
||||||
|
|
||||||
const users = await prisma.user.findMany({
|
const users = await prisma.user.findMany({
|
||||||
include: { businesses: true },
|
select: {
|
||||||
|
...USER_SAFE_SELECT,
|
||||||
|
businesses: true
|
||||||
|
},
|
||||||
orderBy: { createdAt: 'desc' },
|
orderBy: { createdAt: 'desc' },
|
||||||
})
|
})
|
||||||
return NextResponse.json(users)
|
return NextResponse.json(users)
|
||||||
@@ -15,11 +23,22 @@ export async function GET() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// POST /api/users
|
// POST /api/users (Admin only)
|
||||||
export async function POST(request: NextRequest) {
|
export async function POST(request: NextRequest) {
|
||||||
try {
|
try {
|
||||||
|
if (!(await isAdmin(request))) {
|
||||||
|
return NextResponse.json({ error: 'Accès non autorisé' }, { status: 403 })
|
||||||
|
}
|
||||||
|
|
||||||
const body = await request.json()
|
const body = await request.json()
|
||||||
const user = await prisma.user.create({ data: body })
|
|
||||||
|
// Note: For admins, we might want to allow creating users directly,
|
||||||
|
// but we should still ensure password hashing if provided.
|
||||||
|
// For now, we just restrict it to admins to prevent the public leak.
|
||||||
|
const user = await prisma.user.create({
|
||||||
|
data: body,
|
||||||
|
select: USER_SAFE_SELECT
|
||||||
|
})
|
||||||
return NextResponse.json(user, { status: 201 })
|
return NextResponse.json(user, { status: 201 })
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('POST /api/users error:', error)
|
console.error('POST /api/users error:', error)
|
||||||
|
|||||||
72
features.md
72
features.md
@@ -33,3 +33,75 @@ ajout de paiement ponctuel pour :
|
|||||||
|
|
||||||
permettre d'ajouter un entrepreneur en favoris.
|
permettre d'ajouter un entrepreneur en favoris.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
features existante
|
||||||
|
# Liste des Fonctionnalités d'Afrohub
|
||||||
|
|
||||||
|
Ce document recense l'ensemble des fonctionnalités implémentées sur la plateforme Afrohub, ainsi que les évolutions prévues.
|
||||||
|
|
||||||
|
## 1. Gestion des Utilisateurs et Comptes
|
||||||
|
* **Authentification Sécurisée** : Connexion et inscription pour les Visiteurs et les Entrepreneurs.
|
||||||
|
* **Vérification d'Email** : Processus de validation automatique pour sécuriser les comptes.
|
||||||
|
* **Réinitialisation de Mot de Passe** : Flux complet de récupération par email.
|
||||||
|
* **Profils Utilisateurs** : Personnalisation avec avatar, biographie, localisation et coordonnées.
|
||||||
|
* **Système de Rôles** : Accès différenciés selon le type d'utilisateur (Visiteur, Entrepreneur, Administrateur).
|
||||||
|
* **Système de Favoris** : Possibilité pour les utilisateurs de sauvegarder des entreprises pour un accès rapide.
|
||||||
|
* **Modération des Comptes** : Suspension d'utilisateurs avec motifs par les administrateurs.
|
||||||
|
|
||||||
|
## 2. Annuaire des Entreprises (B2B & Vitrine)
|
||||||
|
* **Fiches Entreprises Riches** : Logo, bannière personnalisable, description détaillée, vidéo de présentation, et liens vers les réseaux sociaux.
|
||||||
|
* **Catégorisation Dynamique** : Organisation par secteurs d'activité (Technologie, Agriculture, Mode, etc.) et tags.
|
||||||
|
* **Recherche et Filtrage** : Recherche multicritère par mots-clés, catégorie, pays et ville.
|
||||||
|
* **Badge de Vérification** : Identification visuelle des entreprises validées par l'équipe Afrohub.
|
||||||
|
* **Avis et Notations** : Système d'évaluation avec commentaires et possibilité de réponse pour le propriétaire.
|
||||||
|
* **Mise en Avant (Featured)** : Affichage prioritaire des entreprises sélectionnées sur la page d'accueil.
|
||||||
|
* **Statistiques de Visibilité** : Compteur de vues et suivi des clics vers les sites web/réseaux sociaux.
|
||||||
|
* **Gestion des Offres** : Publication de catalogues de produits ou services liés à chaque entreprise.
|
||||||
|
|
||||||
|
## 3. Hub de Contenu (AfroLife & Blog)
|
||||||
|
* **Interviews AfroLife** : Formats Vidéo et Article mettant en lumière des parcours d'entrepreneurs africains.
|
||||||
|
* **Blog d'Actualités** : Section d'articles de fond, conseils et actualités du secteur.
|
||||||
|
* **Agenda des Événements** : Référencement des manifestations entrepreneuriales avec date, lieu et liens externes.
|
||||||
|
* **Optimisation SEO** : Gestion granulaire des meta-titres, meta-descriptions et slugs pour chaque article et interview.
|
||||||
|
|
||||||
|
## 4. Communication et Engagement
|
||||||
|
* **Messagerie Interne** : Système de conversations directes entre les visiteurs et les entreprises.
|
||||||
|
* **Signalement de Contenu** : Possibilité de rapporter des messages ou comportements inappropriés.
|
||||||
|
* **Modération des Avis** : Flux de validation par les administrateurs pour garantir la qualité des échanges.
|
||||||
|
* **Notifications par Email** : Alertes pour les messages reçus et les étapes de vérification.
|
||||||
|
|
||||||
|
## 5. Monétisation et Abonnements
|
||||||
|
* **Plans de Tarification Tiercés** : Offres Starter, Booster et Empire avec accès progressif aux fonctionnalités.
|
||||||
|
* **Multidevises (XOF/EUR)** : Support des paiements et affichage des prix adaptés.
|
||||||
|
* **Gestion des Limites de Plan** : Contrôle dynamique du nombre d'offres publiables selon l'abonnement.
|
||||||
|
* **Tunnel de Souscription** : Interface dédiée pour le choix et la gestion des abonnements.
|
||||||
|
|
||||||
|
## 6. Panel d'Administration (Backoffice)
|
||||||
|
* **Tableau de Bord Analytique** : Visualisation des métriques clés (utilisateurs, entreprises, revenus).
|
||||||
|
* **CMS Complet** : Éditeurs pour le blog, les interviews AfroLife, les événements et les catégories.
|
||||||
|
* **Gestion Géographique** : Configuration des pays et villes disponibles sur la plateforme.
|
||||||
|
* **Modération Centrale** : Interface de validation des avis, traitement des signalements et suspension des comptes.
|
||||||
|
* **Paramètres Globaux** : Modification du slogan, des contacts, des liens sociaux et du SEO général du site.
|
||||||
|
* **Gestion des Plans** : Configuration des prix et des avantages liés aux abonnements.
|
||||||
|
* **Éditeur de Documents Légaux** : Gestion des CGU, CGV et mentions légales directement depuis l'interface.
|
||||||
|
* **Personnalisation des Emails** : Éditeur de templates pour les communications système (reset password, verification).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 7. Roadmap & Fonctionnalités à Venir (Prochainement)
|
||||||
|
* **Progressive Web App (PWA)** : Application installable sur smartphone avec notifications push en temps réel.
|
||||||
|
* **Paiements Ponctuels** : Options de paiement à l'acte pour booster un profil ou créer un événement premium.
|
||||||
|
* **Tableau de Bord Entrepreneur Avancé** : Graphiques d'évolution des vues et origine géographique des visiteurs.
|
||||||
|
* **Portail d'Emploi (Job Board)** : Publication d'offres d'emploi et de missions freelance par les entreprises.
|
||||||
|
* **E-commerce & Paiement Direct** : Achat de produits/services via Mobile Money ou Paystack directement sur le site.
|
||||||
|
* **Matchmaking B2B** : Système de mise en relation et demandes de partenariat structurées.
|
||||||
|
* **Avis Multimédias** : Possibilité d'ajouter des photos de réalisations ou preuves d'achat dans les avis.
|
||||||
|
* **Billetterie & RSVP** : Confirmation de présence aux événements et rappels automatiques.
|
||||||
|
* **Forum Communautaire** : Espace de questions/réponses et d'entraide entre entrepreneurs.
|
||||||
|
* **Hub Investisseurs** : Espace dédié aux levées de fonds avec hébergement de Pitch Decks.
|
||||||
|
* **Recherche Géolocalisée** : Vue sur carte (Map) pour découvrir les opportunités à proximité.
|
||||||
|
* **Support Multilingue** : Traduction intégrale du site en anglais et portugais.
|
||||||
|
* **Programme de Mentorat** : Système de mise en relation entre entrepreneurs seniors et juniors.
|
||||||
|
|
||||||
|
|||||||
42
lib/auth-utils.ts
Normal file
42
lib/auth-utils.ts
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
import { NextRequest } from 'next/server';
|
||||||
|
import prisma from '@/lib/prisma';
|
||||||
|
|
||||||
|
export const USER_SAFE_SELECT = {
|
||||||
|
id: true,
|
||||||
|
name: true,
|
||||||
|
email: true,
|
||||||
|
role: true,
|
||||||
|
avatar: true,
|
||||||
|
bio: true,
|
||||||
|
location: true,
|
||||||
|
phone: true,
|
||||||
|
createdAt: true,
|
||||||
|
updatedAt: true,
|
||||||
|
emailVerified: true,
|
||||||
|
};
|
||||||
|
|
||||||
|
export async function getAuthUser(request: NextRequest) {
|
||||||
|
const userId = request.headers.get('x-user-id');
|
||||||
|
if (!userId) return null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const user = await prisma.user.findUnique({
|
||||||
|
where: { id: userId },
|
||||||
|
select: {
|
||||||
|
id: true,
|
||||||
|
role: true,
|
||||||
|
emailVerified: true,
|
||||||
|
isSuspended: true
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return user;
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error fetching auth user:', error);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function isAdmin(request: NextRequest) {
|
||||||
|
const user = await getAuthUser(request);
|
||||||
|
return user?.role === 'ADMIN';
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user