Skip to main content

Building a Full-Stack App with FluxKit

This guide walks you through building a complete application with a FluxKit backend and a React frontend using @fluxkitdev/ui.

What We Are Building

A simple product management app with:

  • User authentication (email/password + Google OAuth)
  • Product CRUD with file uploads
  • Email notifications
  • Dark mode support

Prerequisites

  • Node.js >= 18
  • MongoDB running locally or on Atlas
  • Google OAuth credentials (optional)

Step 1: Backend Setup

Create the project structure:

mkdir product-app && cd product-app
mkdir backend frontend

Initialize the Backend

cd backend
npm init -y
npm install @fluxkitdev/core @fluxkitdev/auth @fluxkitdev/messaging @fluxkitdev/store
npm install typescript tsx @types/node --save-dev

Create backend/.env:

MONGODB_URI=mongodb://localhost:27017/product-app
JWT_SECRET=your-super-secret-key-change-this
SMTP_HOST=smtp.gmail.com
SMTP_PORT=587
SMTP_USER=your@gmail.com
SMTP_PASS=your-app-password
SMTP_FROM=noreply@product-app.com
CORS_ORIGIN=http://localhost:5173

Create backend/src/index.ts:

import { FluxKit, Schema } from "@fluxkitdev/core";
import { auth } from "@fluxkitdev/auth";
import { messaging } from "@fluxkitdev/messaging";
import { store } from "@fluxkitdev/store";

const app = new FluxKit({
wires: [
auth({
jwt: { secret: process.env.JWT_SECRET },
oauth: {
google: {
clientId: process.env.OAUTH_GOOGLE_CLIENT_ID,
clientSecret: process.env.OAUTH_GOOGLE_CLIENT_SECRET,
callbackUrl: "/auth/google/callback",
},
},
}),
messaging({
email: {
provider: "smtp",
host: process.env.SMTP_HOST,
port: Number(process.env.SMTP_PORT),
auth: {
user: process.env.SMTP_USER,
pass: process.env.SMTP_PASS,
},
from: process.env.SMTP_FROM,
},
}),
store({
uploads: {
provider: "local",
directory: "./uploads",
servePublicly: true,
maxFileSize: "5mb",
allowedTypes: ["image/*"],
},
crud: {
schemas: {
products: Schema.object({
name: Schema.string().min(1).max(200).required(),
description: Schema.string().max(2000).optional(),
price: Schema.number().min(0).required(),
image: Schema.string().url().optional(),
}),
},
},
}),
],
database: { uri: process.env.MONGODB_URI },
server: {
cors: {
origin: [process.env.CORS_ORIGIN || "http://localhost:5173"],
credentials: true,
},
},
});

// Custom route: send notification when a product is created
app.http.post("/products/notify", {
auth: true,
body: Schema.object({
productName: Schema.string().required(),
}),
handler: async (req, res) => {
await app.messaging.email.send({
to: req.user.email,
subject: `Product Created: ${req.body.productName}`,
body: `<p>Your product "${req.body.productName}" has been created.</p>`,
});
res.json({ sent: true });
},
});

await app.start({ port: 3000 });
console.log("Backend running on http://localhost:3000");

Add scripts to backend/package.json:

{
"type": "module",
"scripts": {
"dev": "tsx watch src/index.ts",
"build": "tsc",
"start": "node dist/index.js"
}
}

Start the backend:

npm run dev

Step 2: Frontend Setup

cd ../frontend
npm create vite@latest . -- --template react-ts
npm install @fluxkitdev/ui

App Component

Replace frontend/src/App.tsx:

import {
FluxKitProvider,
useAuth,
LoginForm,
UserMenu,
DataTable,
FileUpload,
useCollection,
useToast,
} from "@fluxkitdev/ui";

function App() {
return (
<FluxKitProvider
apiUrl="http://localhost:3000"
theme={{
primaryColor: "#6366f1",
defaultColorMode: "system",
}}
>
<Main />
</FluxKitProvider>
);
}

function Main() {
const { user, loading } = useAuth();

if (loading) return <div>Loading...</div>;
if (!user) return <LoginForm providers={["google"]} />;

return (
<div style={{ maxWidth: 1200, margin: "0 auto", padding: "2rem" }}>
<header style={{ display: "flex", justifyContent: "space-between" }}>
<h1>Product Manager</h1>
<UserMenu />
</header>
<ProductList />
</div>
);
}

function ProductList() {
const { data, loading, create, refetch } = useCollection("products");
const toast = useToast();

const addProduct = async () => {
await create({
name: "New Product",
price: 9.99,
description: "A great product",
});
toast.success("Product created!");
refetch();
};

return (
<div>
<button onClick={addProduct}>Add Product</button>
<DataTable
collection="products"
columns={[
{ key: "name", label: "Name", sortable: true },
{ key: "price", label: "Price", format: "currency" },
{ key: "createdAt", label: "Created", format: "date" },
]}
pageSize={10}
searchable
/>
</div>
);
}

export default App;

Start the frontend:

npm run dev

Step 3: Test the Application

  1. Open http://localhost:5173 in your browser.
  2. Register a new account.
  3. Create some products.
  4. Upload product images.
  5. Toggle dark mode.

Available REST APIs

With this setup, the following endpoints are automatically available:

MethodEndpointDescription
POST/auth/registerRegister
POST/auth/loginLogin
GET/auth/meCurrent user
POST/store/productsCreate product
GET/store/productsList products
PUT/store/products/:idUpdate product
DELETE/store/products/:idDelete product
POST/store/uploadUpload file
POST/messaging/emailSend email

Next Steps