Aller au contenu

Structure du projet

Un projet de démarrage Rebase comporte trois packages interconnectés :

my-app/
├── .env # Generated for you: JWT_SECRET, a database password, a free port
├── rebase.json # Which apps this repository contains, and how each is built
├── package.json # Root workspace config
├── tsconfig.json # Typechecks scripts/; each workspace typechecks on its own
├── docker-compose.yml # Self-hosting: Postgres + the published runtime image
├── scripts/
│ └── example.ts # The SDK end to end against the running backend: `pnpm example`
│
├── config/ # Shared by the backend and the admin panel
│ ├── index.ts # Re-exports `collections`; the runtime reads `storageAuthorize` from here
│ ├── collections/ # Your data model
│ │ ├── index.ts # Sort order (`collections`) and `defaultSecurityRules` — not a registry
│ │ ├── posts.ts # Example collections
│ │ └── users.ts # The auth collection
│ ├── resources.ts # What this project needs from wherever it runs
│ ├── storage.ts # Who may read, write and list files
│ └── cms.d.ts # One line that makes the `admin` block legal here
│
├── backend/
│ ├── functions/ # Custom API routes, auto-mounted at /api/functions/<name>
│ │ └── hello.ts
│ └── src/
│ └── schema.generated.ts # Drizzle schema, regenerated from your collections
│
└── frontend/ # The admin panel (React + Vite)
├── src/App.tsx
├── src/main.tsx
└── vite.config.ts

tsc --noEmit à la racine vérifie scripts/ ; dans config/, backend/ ou frontend/, il vérifie ce workspace. Depuis 0.25 En 0.24, la racine n’a pas de tsconfig.json, et tsc y affiche son aide et ne vérifie rien.

Le frontend est une application standard Vite + React + TypeScript. Le fichier clé est App.tsx, qui relie tous les contrôleurs Rebase ensemble :

import React from "react";
import "@fontsource/jetbrains-mono";
import "@fontsource-variable/inter";
import "@fontsource-variable/instrument-sans";
import { Rebase, RebaseAuth, useRebaseAuthController } from "@rebasepro/app";
import { RebaseCMS, RebaseShell } from "@rebasepro/cms";
import { ErrorBoundary } from "@rebasepro/ui";
import { RebaseStudio } from "@rebasepro/studio";
import { createRebaseClient } from "@rebasepro/client";
import { collections } from "virtual:rebase-collections";
// `rebase dev` injects VITE_API_URL with the port it actually bound, and that
// port is derived from this project's path rather than fixed — so a
// `http://localhost:3001` fallback here names a port nothing is listening on.
// A deployed build serves the admin from the same origin as the API, where an
// empty value is exactly what you want.
const API_URL = import.meta.env.VITE_API_URL;
const GOOGLE_CLIENT_ID = import.meta.env.VITE_GOOGLE_CLIENT_ID;
export function App() {
const rebaseClient = React.useMemo(() => createRebaseClient({
baseUrl: API_URL,
// Store the refresh token in an httpOnly cookie (XSS-safe) rather than
// localStorage. The backend issues it via `auth.cookieAuth`.
auth: { authFlowMode: "cookie" }
}), []);
const authController = useRebaseAuthController({
client: rebaseClient,
googleClientId: GOOGLE_CLIENT_ID
});
return (
<ErrorBoundary fullPage>
<Rebase
client={rebaseClient}
authController={authController}
>
{/* The sign-in screen. On its own this changes nothing —
it is where you pass `loginView` to replace it. */}
<RebaseAuth />
<RebaseCMS
collections={collections}
/>
<RebaseStudio/>
<RebaseShell title="Rebase"/>
</Rebase>
</ErrorBoundary>
);
}

main.tsx le monte sous un basename de react-router récupéré depuis import.meta.env.BASE_URL, que rebase build définit à partir du path déclaré par cette application dans rebase.json — ainsi, les assets, le routeur et le serveur s’accordent sur une seule et même valeur sans avoir à l’écrire trois fois.

  • createRebaseClient — Crée le client SDK qui gère les requêtes HTTP, les connexions WebSocket et la gestion des jetons d’authentification
  • virtual:rebase-collections — Un plugin Vite qui importe automatiquement vos collections partagées au moment du build
  • useRebaseAuthController — Conserve l’utilisateur connecté et le cycle de vie des jetons, et constitue ce que <Rebase> distribue à tous les éléments en dessous de lui

Il n’y a aucun fichier serveur à consulter, et c’est voulu : un projet échafaudé déclare runtime: "managed", de sorte que l’image publiée rebasepro/server démarre votre projet. Ce que contient backend/, c’est le code pris en compte par le runtime :

Chemin Description
backend/functions/ Routes personnalisées, montées automatiquement sur /api/functions/<filename>
backend/crons/ Tâches planifiées, découvertes de la même manière (à créer selon vos besoins)
backend/src/schema.generated.ts Le schéma Drizzle de vos collections : écrit par rebase init, et régénéré à chaque rebase dev et rebase build

Le runtime met en place :

  • API REST à /api/data/* — CRUD généré pour chaque collection
  • Authentification à /api/auth/* — inscription, connexion, rafraîchissement, OAuth
  • Stockage à /api/storage/* — téléversement et téléchargement
  • WebSocket — synchronisation en temps réel via LISTEN/NOTIFY de Postgres
  • Vos fonctions et crons, issus des répertoires ci-dessus

La configuration provient de rebase.json, du répertoire config/ et des variables d’environnement. Voir Environnement et configuration.

rebase build transforme l’ensemble en un bundle — les collections, fonctions et crons compilés, accompagnés d’un manifeste — que le runtime managé démarre. Rien dans le bundle n’est écrit à la main ; si vous souhaitez voir à quoi il ressemble, consultez Runtime et bundles.

Le panneau servi par le frontend comporte deux volets. Le Studio est celui destiné aux développeurs — l’éditeur de schéma, la console SQL, l’explorateur de politiques RLS — et il est accessible via le bouton de bascule dans le menu latéral, sans nécessiter de déploiement séparé. Voir Studio.

Pour reprendre plutôt le contrôle du processus — vos propres middlewares, routes et configuration d’authentification —, exécutez rebase eject. Tout ce qui suit ce paragraphe s’applique uniquement après un eject : un projet échafaudé ne contient aucun de ces fichiers, et rien n’y appelle initializeRebaseBackend. Cette commande génère un point d’entrée qui appelle directement initializeRebaseBackend, ainsi qu’un Dockerfile et un fichier compose pour le compiler ; à partir de ce moment, vous maintenez le serveur et les mises à niveau du runtime de la plateforme ne s’appliquent plus au projet. Cet aspect est documenté dans Intégration d’un serveur personnalisé.

Les collections constituent la source unique de vérité de votre modèle de données. Elles sont définies en TypeScript et consommées à la fois par le frontend (pour la génération de l’interface utilisateur) et par le backend (pour la génération du schéma et le routage de l’API).

import { defineCollection } from "@rebasepro/cms-types";
const productsCollection = defineCollection({
slug: "products",
name: "Products",
properties: {
name: { type: "string", name: "Name" },
price: { type: "number", name: "Price" }
}
});
// The default export is what the loader picks up — every file in this directory
// is loaded, listed in index.ts or not, and every collection in the scaffold is
// written this way.
export default productsCollection;

Le slug devient le chemin d’URL dans l’interface d’administration ainsi que le point de terminaison de l’API REST (/api/data/products), et le nom de table PostgreSQL correspond par défaut à ce slug. N’ajoutez table que s’ils diffèrent.

  1. Vous définissez les collections dans config/collections/
  2. Le backend les lit pour générer les schémas Drizzle et monter les routes REST
  3. Le frontend les lit (via le plugin Vite) pour afficher les tables, les formulaires et la navigation
  4. La CLI les lit pour générer le schéma Drizzle (rebase schema generate), les types du SDK (rebase generate-sdk) et, à partir de ce schéma, les fichiers de migration (rebase db generate)

Pendant l’exécution de rebase dev, enregistrer un fichier dans config/collections/ régénère backend/src/schema.generated.ts et les types du SDK dans generated/sdk/, redémarre le backend, et le démarrage crée les tables et les colonnes manquantes. En dehors de rebase dev, les mêmes étapes s’effectuent via rebase schema generate et rebase generate-sdk.

Sur la 0.23, rebase dev ne régénère que le schéma, et rebase generate-sdk est une étape à part.