cda-app-fullstack-react

cda-app-fullstack-react

Application fullstack pédagogique structurée en deux sous-projets (API Express/Prisma et client React/Parcel) avec authentification JWT, routage protégé et persistance MySQL. Le projet couvre le cycle complet de développement fullstack : modélisation de données, routes API sécurisées, gestion d'état côté client et documentation technique.

🎯 Contexte et objectifs

  • Construire un socle pédagogique fullstack couvrant la chaîne complète backend + frontend.
  • Implémenter un module utilisateur sécurisé (création, authentification, token) côté API.
  • Mettre en place côté web une navigation publique/privée et des appels API centralisés.

🛠️ Réalisations

🧩 Conception

  • La solution est découpée en api/ et web/, avec stacks dédiées à chaque couche (Express/Prisma côté serveur, React/Redux/Router côté client). Source: cda-app-fullstack-react/api/package.json
{
  "scripts": {
    "watch": "npx tsc -w",
    "build": "npx tsc",
    "dev": "nodemon ./dist/index.js",
    "start": "node ./dist/index.js"
  },
  "devDependencies": {
    "@types/express": "^4.17.13",
    "argon2": "^0.28.2",
    "cors": "^2.8.5",
    "express": "^4.17.1",
    "jsonwebtoken": "^8.5.1",
    "prisma": "^2.29.0",
    "typescript": "^4.3.5"
  },
  "dependencies": {
    "@prisma/client": "^2.29.0"
  }
}

Source: cda-app-fullstack-react/web/package.json

{
  "scripts": {
    "dev": "npx parcel ./src/index.html"
  },
  "devDependencies": {
    "axios": "^0.21.1",
    "parcel": "^2.0.0-rc.0",
    "react-redux": "^7.2.4",
    "react-router-dom": "^5.2.0",
    "redux": "^4.1.1",
    "redux-logger": "^3.0.6",
    "typescript": "^4.3.5"
  },
  "dependencies": {
    "react": "^17.0.2",
    "react-dom": "^17.0.2"
  }
}
model Post {
  id        Int      @default(autoincrement()) @id
  title     String   @db.VarChar(255)
  content   String?
  published Boolean  @default(false)
  author    User     @relation(fields: [authorId], references: [id])
  authorId  Int
}

model User {
  id       Int      @default(autoincrement()) @id
  email    String   @unique
  name     String?
  password String
  username String?
  posts    Post[]
  profile  Profile?
}

💻 Développement

export const createServer = async () => {
    const server: express.Application = express();

    server.use(express.json())

    server.use(cors({
        origin:"http://localhost:1234"
    }))

    server.use(APP_BASE_URL, mainRouter)

    return server
}

Le routeur principal compose endpoints racine, lecture de posts et sous-routes utilisateurs. Source: cda-app-fullstack-react/api/src/router.ts

const mainRouter: Router = Router();

mainRouter.get("/", (_: Request,res: Response) => {
    res.send('voici la racine')
})

mainRouter.get('/posts', async (_:Request, res:Response) => {
    const posts = await prisma.post.findMany();
    res.send(posts);
})

mainRouter.use('/users',userRouter)

Le use case de création utilisateur chiffre le mot de passe (Argon2) puis persiste via repository Prisma. Source: cda-app-fullstack-react/api/src/modules/user/useCases/createUser/createUser.ts

const userAlreadyExists = await this.userRepo.exists(props.email)
if (userAlreadyExists) {
  return {
    success: false,
    message: 'User already exists'
  }
}

const hashPassword = await argon2.hash(props.password);
props.password = hashPassword;

await this.userRepo.create(props);

return {
  success: true,
  message: 'User is correctly created'
}

L’authentification vérifie Argon2 et génère un JWT, ensuite renvoyé en cookie HTTP-only par le contrôleur. Source: cda-app-fullstack-react/api/src/modules/user/useCases/login/login.ts

const user = await this.userRepo.getUserByEmail(email);

if (!user) {
  return {
    success: false,
    message: "Email or password missmatch"
  }
}

const passwordMatches = await argon2.verify(user.password, password)
if (!passwordMatches) {
  return {
    success: false,
    message: "Email or password missmatch"
  }
}

const jwtToken = sign({ id: user.id }, JWT_PASSPHRASE)
<Router>
  <Switch>
    <Route path="/register" component={Register} />
    <Route path="/login" component={Login} />
    <Layout>
      <AuthRoute exact path="/" component={Posts} />
      <AuthRoute path="/posts" component={Posts} />
    </Layout>
  </Switch>
</Router>

La garde AuthRoute lit la session depuis le stockage local et redirige les utilisateurs non authentifiés. Source: cda-app-fullstack-react/web/src/js/components/authRoute.jsx

const AuthRoute = ({ component, path, exact, ...props }) => {
    const Component = component;
    const isLogged = useAuth();

    if (!isLogged)
        return <Redirect to="/login" />;

    return <Route exact={exact} path={path} render={() => <Component {...props} />} />;
};

const useAuth = () => {
    const auth = getLocalStorageItem('user');
    return auth !== null;
};

🏗️ DevOps & Qualité

  • Le projet s’appuie sur une compilation TypeScript stricte côté API et sur un store Redux instrumenté (redux-logger) côté web pour faciliter le debug des transitions d’état. Source: cda-app-fullstack-react/api/tsconfig.json
{
  "compilerOptions": {
    "noImplicitAny": true,
    "strictNullChecks": true,
    "strictFunctionTypes": true,
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "experimentalDecorators": true,
    "esModuleInterop": true
  },
  "include": ["./src/**/*.ts"]
}

Source: cda-app-fullstack-react/web/src/js/store/store.js

import { createStore, applyMiddleware } from "redux";
import { createLogger } from "redux-logger";
import rootReducer from "./root";

const loggerMiddleware = createLogger();

export default preloadedState => {
    return createStore(
        rootReducer,
        preloadedState,
        applyMiddleware(
            loggerMiddleware,
        )
    );
};

📈 Résultats

  • Sur la base de l’historique Git du dépôt analysé, le travail couvre la période 2021-08-09 -> 2026-02-14, avec 27 commits et 2 contributeurs. Le projet a permis de livrer une chaîne fullstack fonctionnelle: API Express/Prisma, création/connexion utilisateur sécurisée, et frontend React avec routes protégées. La séparation api/web et l’introduction de patterns repository/use case améliorent la lisibilité des responsabilités techniques. Le bénéfice technique est un socle complet pour prototyper rapidement des applications métier avec authentification.

🔧 Environnement technique

  • Backend: Node.js, Express, TypeScript, Prisma, MySQL, Argon2, JWT, CORS.
  • Frontend: React 17, React Router v5, Redux, Redux Logger, Parcel, Axios.
  • Architecture: séparation api / web, router versionné, repository + use cases.
  • Sécurité: hash mot de passe, token JWT, cookie HTTP-only côté login.
  • Qualité: compilation TS stricte, debug middleware Redux.
🌐 Voir le projet

Technologies utilisées

Backend
Express
Node.js
Bases de donnees (SGBD & SQL)
MySQL
Design Patterns & Architecture
Prisma
Frontend
React
Redux
TypeScript