---
source_hash: "e8bd42ed"
title: "Chapter 1: Project Structure"
weight: 490
---

# Chapter 1: Project Structure

## Overview

A SmartMaker project consists of two parts:

1. **mobile/**: React source code (development)
2. **pwa/**: Compiled application + PHP API (production)

## Complete Tree Structure

```
monmodule/                          # Dolibarr module
├── mobile/                         # REACT SOURCE CODE
│   ├── src/
│   │   ├── App.jsx                # Root component
│   │   ├── main.jsx               # Entry point
│   │   ├── appConfig.js           # Configuration
│   │   ├── components/
│   │   │   ├── app/
│   │   │   │   └── Router/        # Route configuration
│   │   │   │       ├── index.jsx
│   │   │   │       └── Guards/    # Route protection
│   │   │   └── pages/
│   │   │       ├── public/        # Pages without auth
│   │   │       │   ├── LoginPage/
│   │   │       │   └── WelcomePage/
│   │   │       ├── private/       # Pages with auth
│   │   │       │   ├── HomePage/
│   │   │       │   └── ItemPage/
│   │   │       └── errors/
│   │   │           └── Error404Page/
│   │   ├── redux/                 # Redux store (optional)
│   │   │   └── reducers/
│   │   ├── i18n/                  # i18next configuration
│   │   ├── utils/                 # Helpers, constants
│   │   └── locales/               # Translation files
│   ├── public/
│   │   ├── images/                # PWA icons
│   │   └── locales/               # Translations
│   ├── index.html                 # HTML template
│   ├── package.json               # npm dependencies
│   ├── vite.config.js             # Vite configuration
│   └── .env                       # Environment variables
│
├── pwa/                           # COMPILED APPLICATION + API
│   ├── api.php                    # API entry point
│   └── dist/                      # Compiled React files
│
├── smartmaker-api/                # PHP BACKEND
│   ├── Controllers/               # Business logic
│   └── Mappers/                   # Dolibarr -> DTO conversion
│
└── smartmaker-api-prepend.php     # PHP bootstrap
```

## Key Files Detail

### main.jsx - Entry Point

```javascript
// src/main.jsx
import { StrictMode } from 'react';
import { createRoot } from 'react-dom/client';
import { App } from './App';
import './index.css';

createRoot(document.getElementById('root')).render(
    <StrictMode>
        <App />
    </StrictMode>
);
```

This is the file called by `index.html`. It mounts the React application in the DOM.

### App.jsx - Root Component

```javascript
// src/App.jsx
import { Provider } from '@cap-rel/smartcommon';
import { Router } from './components/app/Router';
import { config } from './appConfig';

export const App = () => (
    <Provider config={config}>
        <Router />
    </Provider>
);
```

The SmartCommon `Provider` wraps the entire application and provides:

- Global configuration
- Redux store
- API context
- i18next

### appConfig.js - Configuration

```javascript
// src/appConfig.js
export const config = {
    debug: import.meta.env.DEV,

    api: {
        prefixUrl: import.meta.env.VITE_API_URL,
        timeout: 30000,
        paths: {
            login: "login",
            logout: "logout",
            refresh: "refresh"
        }
    },

    storage: {
        local: ["session", "settings"]
    },

    globalState: {
        reducers: {
            session: null,
            settings: { lng: "fr" },
            items: []
        }
    },

    pages: {
        "/": { "/settings": "slideLeft", "*": "fade" },
        "*": "fade"
    }
};
```

Detailed in the next chapter.

### index.html - Template

```html
<!DOCTYPE html>
<html lang="fr">
<head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>My Application</title>
</head>
<body>
    <div id="root"></div>
    <script type="module" src="/src/main.jsx"></script>
</body>
</html>
```

Vite automatically injects the compiled scripts in production.

## Component Organization

### Recommended Structure for a Page

```
components/pages/private/ItemPage/
├── index.jsx           # Main component
├── ItemPage.module.css # Styles (optional)
└── components/         # Local sub-components (optional)
    ├── ItemHeader.jsx
    └── ItemActions.jsx
```

### Example Page

```javascript
// components/pages/private/ItemPage/index.jsx
import { useEffect } from 'react';
import { useParams } from 'react-router-dom';
import { Page, Block, Spinner } from '@cap-rel/smartcommon';
import { useApi, useStates } from '@cap-rel/smartcommon';

export const ItemPage = () => {
    const { id } = useParams();
    const api = useApi();

    const st = useStates({
        initialStates: {
            item: null,
            loading: true,
            error: null
        }
    });

    useEffect(() => {
        const fetchItem = async () => {
            try {
                const data = await api.private.get(`items/${id}`).json();
                st.set('item', data);
            } catch (err) {
                st.set('error', err.message);
            } finally {
                st.set('loading', false);
            }
        };
        fetchItem();
    }, [id]);

    if (st.get('loading')) {
        return <Page><Spinner /></Page>;
    }

    if (st.get('error')) {
        return <Page><Block>Error: {st.get('error')}</Block></Page>;
    }

    const item = st.get('item');

    return (
        <Page title={item.label}>
            <Block>
                <p>{item.description}</p>
            </Block>
        </Page>
    );
};
```

## Router

### Route Configuration

```javascript
// components/app/Router/index.jsx
import { BrowserRouter, Routes, Route } from 'react-router-dom';
import { PublicRoutes, PrivateRoutes } from './Guards';

// Pages
import { LoginPage } from '../../pages/public/LoginPage';
import { HomePage } from '../../pages/private/HomePage';
import { ItemPage } from '../../pages/private/ItemPage';
import { Error404Page } from '../../pages/errors/Error404Page';

export const Router = () => {
    return (
        <BrowserRouter>
            <Routes>
                {/* Public routes */}
                <Route element={<PublicRoutes />}>
                    <Route path="/login" element={<LoginPage />} />
                </Route>

                {/* Protected routes */}
                <Route element={<PrivateRoutes />}>
                    <Route path="/" element={<HomePage />} />
                    <Route path="/items/:id" element={<ItemPage />} />
                </Route>

                {/* Fallback */}
                <Route path="*" element={<Error404Page />} />
            </Routes>
        </BrowserRouter>
    );
};
```

### Authentication Guards

```javascript
// components/app/Router/Guards/index.jsx
import { Outlet, Navigate } from 'react-router-dom';
import { useGlobalStates } from '@cap-rel/smartcommon';

export const PrivateRoutes = () => {
    const gst = useGlobalStates();
    return gst.get('session') ? <Outlet /> : <Navigate to="/login" />;
};

export const PublicRoutes = () => {
    const gst = useGlobalStates();
    return gst.get('session') ? <Navigate to="/" /> : <Outlet />;
};
```

## Environment Variables

```bash
# .env
VITE_API_URL=https://mydomain.com/modules/mymodule/pwa/api.php
```

Access in code:

```javascript
const apiUrl = import.meta.env.VITE_API_URL;
const isDev = import.meta.env.DEV;
const isProd = import.meta.env.PROD;
```

**Important**: Variables must start with `VITE_` to be exposed to the client.

## pwa/ Directory - Production

After compilation (`npm run build`), files are generated in `pwa/dist/`:

```
pwa/
├── api.php           # API entry point (to be created)
└── dist/
    ├── index.html    # HTML with injected assets
    ├── assets/
    │   ├── index-abc123.js   # JS bundle
    │   └── index-def456.css  # CSS bundle
    └── images/
```

## Key Points to Remember

1. **mobile/** = source code for development
2. **pwa/** = compiled code for production
3. **App.jsx** wraps everything with the SmartCommon Provider
4. **appConfig.js** centralizes configuration
5. **Router** manages routes with authentication guards
6. Environment variables prefixed with **VITE_**

[Back to Module](/training/module5-architecture-smartmaker) | [Next Chapter: Configuration ->](/training/module5-architecture-smartmaker/configuration)
