Overview
This document provides complete specifications for hosting the Minastix React frontend on your own server while maintaining Base44 backend integration for authentication, database, and functions.
⚠️ Important: This is an unsupported configuration
Base44 apps are designed to be hosted on Base44. Self-hosting requires manual configuration and maintenance.
1. Project Setup
Initialize React Project
npm create vite@latest minastix-frontend -- --template react cd minastix-frontend npm install
Install Required Dependencies
npm install @base44/sdk@^0.8.3 \ react-router-dom@^7.2.0 \ @tanstack/react-query@^5.84.1 \ @radix-ui/react-accordion@^1.2.3 \ @radix-ui/react-alert-dialog@^1.1.6 \ @radix-ui/react-avatar@^1.1.3 \ @radix-ui/react-checkbox@^1.1.4 \ @radix-ui/react-dialog@^1.1.6 \ @radix-ui/react-dropdown-menu@^2.1.6 \ @radix-ui/react-label@^2.1.2 \ @radix-ui/react-popover@^1.1.6 \ @radix-ui/react-select@^2.1.6 \ @radix-ui/react-tabs@^1.1.3 \ @radix-ui/react-toast@^1.2.2 \ @radix-ui/react-slot@^1.1.2 \ lucide-react@^0.475.0 \ framer-motion@^11.16.4 \ date-fns@^3.6.0 \ lodash@^4.17.21 \ moment@^2.30.1 \ recharts@^2.15.4 \ react-markdown@^9.0.1 \ sonner@^2.0.1 \ class-variance-authority@^0.7.1 \ clsx@^2.1.1 \ tailwind-merge@^3.0.2
Install Tailwind CSS
npm install -D tailwindcss@latest postcss autoprefixer npx tailwindcss init -p
2. Project Structure
minastix-frontend/ ├── src/ │ ├── api/ │ │ └── base44Client.js # Base44 SDK initialization │ ├── components/ │ │ ├── ui/ # shadcn/ui components │ │ ├── home/ │ │ │ ├── HeroSection.jsx │ │ │ └── ProgramCard.jsx │ │ ├── enrollment/ │ │ └── admin/ │ ├── pages/ │ │ ├── Home.js │ │ ├── Enroll.js │ │ ├── Shop.js │ │ ├── Cart.js │ │ ├── Dashboard.js │ │ ├── EnrollmentSuccess.js │ │ ├── CheckoutSuccess.js │ │ └── NotFound.js │ ├── utils/ │ │ └── index.js # Utility functions │ ├── lib/ │ │ └── utils.js # cn() helper for Tailwind │ ├── Layout.js # App layout wrapper │ ├── App.jsx # Main app component │ ├── main.jsx # Entry point │ └── index.css # Global styles ├── public/ │ └── wp-content/ │ └── uploads/ │ └── 2021/ │ └── 10/ │ └── MONKEYNASTIX-THEME.mp3 ├── package.json ├── vite.config.js └── tailwind.config.js
3. Configuration Files
vite.config.js
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import path from 'path'
export default defineConfig({
plugins: [react()],
resolve: {
alias: {
'@': path.resolve(__dirname, './src'),
},
},
server: {
port: 3000,
proxy: {
'/api': {
target: 'https://base44.app',
changeOrigin: true,
secure: false,
}
}
}
})tailwind.config.js
module.exports = {
darkMode: ["class"],
content: [
'./pages/**/*.{js,jsx}',
'./components/**/*.{js,jsx}',
'./app/**/*.{js,jsx}',
'./src/**/*.{js,jsx}',
],
theme: {
container: {
center: true,
padding: "2rem",
screens: {
"2xl": "1400px",
},
},
extend: {
colors: {
border: "hsl(var(--border))",
input: "hsl(var(--input))",
ring: "hsl(var(--ring))",
background: "hsl(var(--background))",
foreground: "hsl(var(--foreground))",
primary: {
DEFAULT: "hsl(var(--primary))",
foreground: "hsl(var(--primary-foreground))",
},
secondary: {
DEFAULT: "hsl(var(--secondary))",
foreground: "hsl(var(--secondary-foreground))",
},
destructive: {
DEFAULT: "hsl(var(--destructive))",
foreground: "hsl(var(--destructive-foreground))",
},
muted: {
DEFAULT: "hsl(var(--muted))",
foreground: "hsl(var(--muted-foreground))",
},
accent: {
DEFAULT: "hsl(var(--accent))",
foreground: "hsl(var(--accent-foreground))",
},
popover: {
DEFAULT: "hsl(var(--popover))",
foreground: "hsl(var(--popover-foreground))",
},
card: {
DEFAULT: "hsl(var(--card))",
foreground: "hsl(var(--card-foreground))",
},
},
borderRadius: {
lg: "var(--radius)",
md: "calc(var(--radius) - 2px)",
sm: "calc(var(--radius) - 4px)",
},
keyframes: {
"accordion-down": {
from: { height: 0 },
to: { height: "var(--radix-accordion-content-height)" },
},
"accordion-up": {
from: { height: "var(--radix-accordion-content-height)" },
to: { height: 0 },
},
},
animation: {
"accordion-down": "accordion-down 0.2s ease-out",
"accordion-up": "accordion-up 0.2s ease-out",
},
},
},
plugins: [require("tailwindcss-animate")],
}package.json (scripts section)
{
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview"
}
}4. Base44 SDK Configuration
src/api/base44Client.js
import { createClient } from '@base44/sdk';
export const base44 = createClient({
appId: '69010ca5cc964c7fd44065a4',
apiUrl: 'https://base44.app/api',
// Optional: Use local storage for auth token
storage: {
getItem: (key) => localStorage.getItem(key),
setItem: (key, value) => localStorage.setItem(key, value),
removeItem: (key) => localStorage.removeItem(key),
}
});src/utils/index.js
export function createPageUrl(pageName, params = {}) {
const searchParams = new URLSearchParams(params);
const queryString = searchParams.toString();
return `/${pageName}${queryString ? '?' + queryString : ''}`;
}src/lib/utils.js
import { clsx } from "clsx"
import { twMerge } from "tailwind-merge"
export function cn(...inputs) {
return twMerge(clsx(inputs))
}5. Router Setup
src/App.jsx
import React from 'react';
import { BrowserRouter, Routes, Route, useLocation } from 'react-router-dom';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import Layout from './Layout';
// Import all pages
import HomePage from './pages/Home';
import EnrollPage from './pages/Enroll';
import ShopPage from './pages/Shop';
import CartPage from './pages/Cart';
import DashboardPage from './pages/Dashboard';
import EnrollmentSuccessPage from './pages/EnrollmentSuccess';
import CheckoutSuccessPage from './pages/CheckoutSuccess';
import NotFoundPage from './pages/NotFound';
const queryClient = new QueryClient();
function AppContent() {
const location = useLocation();
const currentPageName = location.pathname.replace('/', '') || 'Home';
return (
<Layout currentPageName={currentPageName}>
<Routes>
<Route path="/" element={<HomePage />} />
<Route path="/Home" element={<HomePage />} />
<Route path="/Enroll" element={<EnrollPage />} />
<Route path="/Shop" element={<ShopPage />} />
<Route path="/Cart" element={<CartPage />} />
<Route path="/Dashboard" element={<DashboardPage />} />
<Route path="/EnrollmentSuccess" element={<EnrollmentSuccessPage />} />
<Route path="/CheckoutSuccess" element={<CheckoutSuccessPage />} />
<Route path="*" element={<NotFoundPage />} />
</Routes>
</Layout>
);
}
export default function App() {
return (
<QueryClientProvider client={queryClient}>
<BrowserRouter>
<AppContent />
</BrowserRouter>
</QueryClientProvider>
);
}src/main.jsx
import React from 'react'
import ReactDOM from 'react-dom/client'
import App from './App.jsx'
import './index.css'
ReactDOM.createRoot(document.getElementById('root')).render(
<React.StrictMode>
<App />
</React.StrictMode>,
)6. Styling Setup
src/index.css
@tailwind base;
@tailwind components;
@tailwind utilities;
@layer base {
:root {
--background: 0 0% 100%;
--foreground: 222.2 84% 4.9%;
--card: 0 0% 100%;
--card-foreground: 222.2 84% 4.9%;
--popover: 0 0% 100%;
--popover-foreground: 222.2 84% 4.9%;
--primary: 222.2 47.4% 11.2%;
--primary-foreground: 210 40% 98%;
--secondary: 210 40% 96.1%;
--secondary-foreground: 222.2 47.4% 11.2%;
--muted: 210 40% 96.1%;
--muted-foreground: 215.4 16.3% 46.9%;
--accent: 210 40% 96.1%;
--accent-foreground: 222.2 47.4% 11.2%;
--destructive: 0 84.2% 60.2%;
--destructive-foreground: 210 40% 98%;
--border: 214.3 31.8% 91.4%;
--input: 214.3 31.8% 91.4%;
--ring: 222.2 84% 4.9%;
--radius: 0.5rem;
}
.dark {
--background: 222.2 84% 4.9%;
--foreground: 210 40% 98%;
--card: 222.2 84% 4.9%;
--card-foreground: 210 40% 98%;
--popover: 222.2 84% 4.9%;
--popover-foreground: 210 40% 98%;
--primary: 210 40% 98%;
--primary-foreground: 222.2 47.4% 11.2%;
--secondary: 217.2 32.6% 17.5%;
--secondary-foreground: 210 40% 98%;
--muted: 217.2 32.6% 17.5%;
--muted-foreground: 215 20.2% 65.1%;
--accent: 217.2 32.6% 17.5%;
--accent-foreground: 210 40% 98%;
--destructive: 0 62.8% 30.6%;
--destructive-foreground: 210 40% 98%;
--border: 217.2 32.6% 17.5%;
--input: 217.2 32.6% 17.5%;
--ring: 212.7 26.8% 83.9%;
}
}
@layer base {
* {
@apply border-border;
}
body {
@apply bg-background text-foreground;
}
}7. Building for Production
Build Command
npm run build
This creates a dist/ folder with optimized production files.
Server Configuration
For proper routing, configure your server to redirect all requests to index.html:
Nginx
server {
listen 80;
server_name minastix.com;
root /var/www/minastix/dist;
index index.html;
# Serve the MP3 file directly
location /wp-content/uploads/2021/10/MONKEYNASTIX-THEME.mp3 {
alias /var/www/minastix/dist/wp-content/uploads/2021/10/MONKEYNASTIX-THEME.mp3;
add_header Content-Type audio/mpeg;
}
# Handle React routing
location / {
try_files $uri $uri/ /index.html;
}
# Cache static assets
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
expires 1y;
add_header Cache-Control "public, immutable";
}
}Apache (.htaccess)
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
# Serve MP3 file directly
RewriteRule ^wp-content/uploads/2021/10/MONKEYNASTIX-THEME\.mp3$ /wp-content/uploads/2021/10/MONKEYNASTIX-THEME.mp3 [L]
# Handle React routing
RewriteRule ^index\.html$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.html [L]
</IfModule>8. Environment Variables
Create a .env file:
VITE_BASE44_APP_ID=69010ca5cc964c7fd44065a4 VITE_BASE44_API_URL=https://base44.app/api
Update base44Client.js to use these:
export const base44 = createClient({
appId: import.meta.env.VITE_BASE44_APP_ID,
apiUrl: import.meta.env.VITE_BASE44_API_URL,
});9. Deployment Checklist
src/pages/src/components/src/public/wp-content/uploads/2021/10/10. Important Notes
🚨 CORS Configuration Required
You may need to contact Base44 support to whitelist your domain for CORS requests to their API.
ℹ️ Backend Functions
All backend functions (fetchSchools, sendWelcomeEmails, etc.) will continue running on Base44 infrastructure.
⚠️ Authentication
Authentication is handled by Base44. Login/logout flows will redirect to Base44's auth pages.
✅ WordPress Path Solution
Place the MP3 file in your public folder at the exact WordPress path, and configure your server to serve it directly.
11. Testing Locally
# Start development server npm run dev # Access at http://localhost:3000 # Test the MP3 path: # http://localhost:3000/wp-content/uploads/2021/10/MONKEYNASTIX-THEME.mp3
12. Support & Troubleshooting
Issue: 404 on refresh
→ Configure server to redirect all requests to index.html
Issue: CORS errors
→ Contact Base44 support to whitelist your domain
Issue: Auth not working
→ Ensure Base44 SDK is configured with correct appId and apiUrl
Issue: MP3 file not found
→ Verify file is in public/wp-content/uploads/2021/10/ and server is configured correctly
