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
- Open
http://localhost:5173in your browser. - Register a new account.
- Create some products.
- Upload product images.
- Toggle dark mode.
Available REST APIs
With this setup, the following endpoints are automatically available:
| Method | Endpoint | Description |
|---|---|---|
POST | /auth/register | Register |
POST | /auth/login | Login |
GET | /auth/me | Current user |
POST | /store/products | Create product |
GET | /store/products | List products |
PUT | /store/products/:id | Update product |
DELETE | /store/products/:id | Delete product |
POST | /store/upload | Upload file |
POST | /messaging/email | Send email |
Next Steps
- Add PayPal or Stripe payments for product purchases
- Add on-chain features for NFT receipts
- Deploy to production with the microservices guide