Zum Inhalt springen

Projektstruktur

Ein Rebase-Starterprojekt besteht aus drei miteinander verbundenen Packages:

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 im Root prüft scripts/; in config/, backend/ oder frontend/ prüft es jeweils diesen Workspace. Seit 0.25 Unter 0.24 hat das Root keine tsconfig.json, und tsc gibt dort seine Hilfe aus und prüft nichts.

Das Frontend ist eine standardmäßige Vite + React + TypeScript-Anwendung. Die wichtigste Datei ist App.tsx, die alle Rebase-Controller miteinander verknüpft:

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 bindet es unter einem react-router-basename ein, der aus import.meta.env.BASE_URL übernommen wird. Diesen setzt rebase build anhand des path, den diese App in rebase.json deklariert — so stimmen die Assets, der Router und der Server bei einem einzigen Wert überein, ohne dass er dreimal manuell angegeben werden muss.

  • createRebaseClient — Erstellt den SDK-Client, der HTTP-Anfragen, WebSocket-Verbindungen und die Verwaltung von Authentifizierungstoken übernimmt
  • virtual:rebase-collections — Ein Vite-Plugin, das Ihre geteilten Collections zur Build-Zeit automatisch importiert
  • useRebaseAuthController — Verwaltet den angemeldeten Benutzer sowie den Token-Lebenszyklus und wird von <Rebase> an alle untergeordneten Komponenten weitergegeben

Es gibt keine Server-Datei zu lesen, und das ist beabsichtigt: Ein neu erstelltes Projekt deklariert runtime: "managed", sodass das veröffentlichte rebasepro/server-Image Ihr Projekt startet. backend/ enthält den Code, den die Runtime einliest:

Pfad Beschreibung
backend/functions/ Eigene Routen, automatisch unter /api/functions/<filename> gemountet
backend/crons/ Zeitgesteuerte Jobs (Cronjobs), die auf dieselbe Weise erkannt werden (erstellen Sie das Verzeichnis bei Bedarf)
backend/src/schema.generated.ts Das Drizzle-Schema Ihrer Collections: von rebase init geschrieben und bei jedem rebase dev und rebase build neu generiert

Die Runtime richtet Folgendes ein:

  • REST-API unter /api/data/* — generierte CRUD-Operationen für jede Collection
  • Auth unter /api/auth/* — Registrierung, Login, Refresh, OAuth
  • Storage unter /api/storage/* — Upload und Download
  • WebSocket — Echtzeitsynchronisierung über Postgres LISTEN/NOTIFY
  • Ihre Functions und Crons aus den oben genannten Verzeichnissen

Die Konfiguration erfolgt über rebase.json, das config/-Verzeichnis und Umgebungsvariablen. Siehe Environment & Configuration.

rebase build wandelt all dies in ein Bundle um — die kompilierten Collections, Functions und Crons samt einem Manifest —, das die Managed Runtime bootet. Nichts an diesem Bundle wird von Hand geschrieben; wenn Sie sehen möchten, wie eines aufgebaut ist, finden Sie die Details unter Runtime & Bundles.

Das vom Frontend bereitgestellte Panel besteht aus zwei Hälften. Studio ist der Entwicklerbereich — der Schema-Editor, die SQL-Konsole, der RLS-Policy-Browser — und befindet sich hinter dem Umschalter im Drawer, kein separates Deployment. Siehe Studio.

Um stattdessen die Kontrolle über den Prozess zu übernehmen — eigene Middleware, Routen und Auth-Verdrahtung —, führen Sie rebase eject aus. Alles unterhalb dieses Absatzes gilt nur für ausgeworfene (ejected) Projekte: Ein neu erstelltes Projekt besitzt keine dieser Dateien, und nichts darin ruft initializeRebaseBackend auf. Der Befehl schreibt einen Einstiegspunkt, der initializeRebaseBackend direkt aufruft, sowie ein Dockerfile und eine Compose-Datei, die dieses baut; von da an warten Sie den Server selbst, und Plattform-Runtime-Upgrades werden nicht mehr auf das Projekt angewendet. Diese Schnittstelle ist in Custom Server Integration dokumentiert.

Collections sind die Single Source of Truth für Ihr Datenmodell. Sie werden in TypeScript definiert und sowohl vom Frontend (zur UI-Generierung) als auch vom Backend (zur Schema-Generierung und für das API-Routing) verwendet.

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;

Der slug wird zum URL-Pfad in der Admin-UI und zum REST-API-Endpunkt (/api/data/products), und der PostgreSQL-Tabellenname entspricht standardmäßig diesem Wert. Geben Sie table nur an, wenn sich beide voneinander unterscheiden.

  1. Sie definieren Collections in config/collections/
  2. Das Backend liest sie ein, um Drizzle-Schemas zu generieren und REST-Routen einzubinden
  3. Das Frontend liest sie ein (über ein Vite-Plugin), um Tabellen, Formulare und die Navigation zu rendern
  4. Die CLI liest sie ein, um das Drizzle-Schema (rebase schema generate), die SDK-Typen (rebase generate-sdk) und, aus diesem Schema, Migrationsdateien (rebase db generate) zu erzeugen

Während rebase dev läuft, werden beim Speichern einer Datei unter config/collections/ die Datei backend/src/schema.generated.ts und die SDK-Typen in generated/sdk/ neu generiert und das Backend neu gestartet; beim Hochfahren werden fehlende Tabellen und Spalten automatisch erstellt. Außerhalb von rebase dev entsprechen diese Schritte rebase schema generate und rebase generate-sdk.

Unter 0.23 generiert rebase dev nur das Schema neu, und rebase generate-sdk ist ein eigener Schritt.