Members > Invite member says invite Staff in dialog resend email button Update form member form to say member and not staff review application function manual payment functionality basic implementation of theme actions dropdown
LOAF Membership Platform - Frontend
React 19-based frontend application for the LOAF (LGBT Organization and Friends) membership management platform.
Table of Contents
Setup & Installation
Prerequisites
- Node.js: 18.0 or higher
- Yarn: 1.22+ (or npm 8+)
- Backend API: Running on http://localhost:8000
1. Install Dependencies
cd frontend
# Using Yarn (recommended)
yarn install
# Or using npm
npm install
Key Dependencies:
react@19.0.0- UI libraryreact-router-dom@7.5.1- Routingaxios@1.8.4- HTTP clientreact-hook-form@7.56.2- Form handlingzod@3.24.4- Schema validation@radix-ui/*- UI components (45+ components)tailwindcss@3.4.17- CSS frameworklucide-react@0.507.0- Iconssonner@1.7.4- Toast notifications
2. Environment Configuration
Create .env file in the frontend directory:
# Backend API URL
REACT_APP_BACKEND_URL=http://localhost:8000
# Optional: Analytics, Sentry, etc.
# REACT_APP_SENTRY_DSN=your-sentry-dsn
# REACT_APP_GA_TRACKING_ID=UA-XXXXXXXXX-X
Important:
- All environment variables must start with
REACT_APP_ - Restart development server after changing
.env
3. Start Development Server
# Start development server
yarn start
# Or with npm
npm start
Development server will be available at:
- Frontend: http://localhost:3000
- Auto-reloads on file changes
4. Build for Production
# Create production build
yarn build
# Or with npm
npm build
Build output will be in /build directory.
5. Run Tests
# Run tests in watch mode
yarn test
# Run tests with coverage
yarn test --coverage
# Or with npm
npm test
Architecture & Code Structure
Project Structure
frontend/
├── public/ # Static assets
│ ├── loaf-logo.png # LOAF logo for admin sidebar
│ ├── hero-loaf.png # Landing page hero image
│ └── index.html # HTML template
├── src/
│ ├── pages/ # Page components (20+ pages)
│ │ ├── Landing.js # Public landing page
│ │ ├── Register.js # 4-step registration (388 lines)
│ │ ├── Login.js # Authentication
│ │ ├── Dashboard.js # Member dashboard
│ │ ├── Profile.js # User profile with photo upload
│ │ ├── Events.js # Event listing
│ │ ├── EventDetails.js # Event details + RSVP
│ │ └── admin/ # Admin pages
│ │ ├── AdminDashboard.js
│ │ ├── AdminUsers.js
│ │ ├── AdminValidations.js # Approve/reject workflow
│ │ ├── AdminEvents.js
│ │ ├── AdminSubscriptions.js # With CSV export
│ │ └── AdminDonations.js # Donation tracking
│ ├── components/ # Reusable components
│ │ ├── Navbar.js # Main navigation
│ │ ├── AdminSidebar.js # Admin sidebar with logo
│ │ ├── RejectionDialog.js # Rejection workflow dialog
│ │ └── ui/ # 45+ Radix UI components
│ │ ├── button.js
│ │ ├── dialog.js
│ │ ├── input.js
│ │ ├── select.js
│ │ └── ... (40+ more)
│ ├── context/
│ │ └── AuthContext.js # Global auth state
│ ├── hooks/
│ │ └── use-toast.js # Toast notification hook
│ ├── utils/
│ │ └── api.js # Axios instance with JWT interceptor
│ ├── App.js # Main routing setup
│ ├── index.js # React entry point
│ └── index.css # Global styles + Tailwind
├── craco.config.js # Craco configuration
├── tailwind.config.js # Tailwind CSS configuration
├── package.json # Dependencies
└── .env # Environment variables (not in git)
Core Technologies
| Technology | Purpose | Version |
|---|---|---|
| React | UI library | 19.0.0 |
| React Router | Client-side routing | 7.5.1 |
| Axios | HTTP requests | 1.8.4 |
| React Hook Form | Form handling | 7.56.2 |
| Zod | Schema validation | 3.24.4 |
| Tailwind CSS | CSS framework | 3.4.17 |
| Radix UI | Component library | Latest |
| Lucide React | Icons | 0.507.0 |
| Sonner | Toast notifications | 1.7.4 |
Key Features
Authentication System
Global Auth Context (src/context/AuthContext.js):
- JWT token storage in localStorage
- Automatic token injection via Axios interceptor
- User state management
- Protected route wrapper
Usage:
import { useAuth } from "../context/AuthContext";
function MyComponent() {
const { user, login, logout, isAuthenticated } = useAuth();
// user contains: id, email, first_name, last_name, role, status
}
Protected Routes
PrivateRoute Wrapper:
<Route path="/dashboard" element={
<PrivateRoute>
<Dashboard />
</PrivateRoute>
} />
// Admin-only route
<Route path="/admin" element={
<PrivateRoute adminOnly>
<AdminDashboard />
</PrivateRoute>
} />
API Integration
Axios Instance (src/utils/api.js):
- Automatic JWT token injection
- Request/response interceptors
- Error handling
- Base URL configuration
Usage:
import api from "../utils/api";
// GET request
const response = await api.get("/members/profile");
// POST request with data
const response = await api.post("/admin/users/123/reject", {
reason: "Incomplete application",
});
// File upload
const formData = new FormData();
formData.append("file", file);
const response = await api.post("/members/profile/upload-photo", formData, {
headers: { "Content-Type": "multipart/form-data" },
});
Form Handling
React Hook Form + Zod Pattern:
import { useForm } from "react-hook-form";
import { zodResolver } from "@hookform/resolvers/zod";
import { z } from "zod";
const schema = z.object({
email: z.string().email("Invalid email address"),
password: z.string().min(8, "Password must be at least 8 characters"),
});
function LoginForm() {
const {
register,
handleSubmit,
formState: { errors },
} = useForm({
resolver: zodResolver(schema),
});
const onSubmit = async (data) => {
try {
await api.post("/auth/login", data);
toast.success("Login successful!");
} catch (error) {
toast.error(error.response?.data?.detail || "Login failed");
}
};
return (
<form onSubmit={handleSubmit(onSubmit)}>
<Input {...register("email")} />
{errors.email && <span>{errors.email.message}</span>}
{/* ... */}
</form>
);
}
Toast Notifications
Using Sonner:
import { toast } from "sonner";
// Success
toast.success("Profile updated successfully!");
// Error
toast.error("Failed to upload photo");
// Custom
toast("Processing...", {
description: "Please wait while we process your request",
});
Page Components
Public Pages
Landing.js
- Hero section with LOAF branding
- Feature highlights
- Call-to-action buttons
Register.js (388 lines)
- 4-step registration wizard:
- Basic Info (email, password, name)
- Personal Details (phone, address, DOB)
- Partner Information (optional)
- Lead Sources & Referral
- Form validation with Zod
- Progress indicator
- Email verification trigger
Login.js
- Email/password authentication
- JWT token storage
- Remember me functionality
- Redirect to dashboard on success
Member Pages
Dashboard.js
- Welcome message with user name
- Upcoming events preview
- Membership status card
- Quick action buttons
Profile.js
- Profile photo upload with Avatar component
- File validation (image types, 50MB max)
- Personal information editing
- Partner information
- Save changes with API update
Events.js
- Event listing with filters
- Search functionality
- Upcoming/past events toggle
- Event cards with cover images
EventDetails.js
- Full event information
- RSVP form (Yes/No/Maybe)
- Attendance confirmation
- Google Maps integration (optional)
Admin Pages
AdminDashboard.js
- Statistics overview
- Pending validations count
- Recent activity feed
- Quick links to management pages
AdminUsers.js
- User listing with search/filters
- Status badges
- Bulk operations
- CSV export
AdminValidations.js
- Pending user applications
- Approve button
- Reject button with RejectionDialog
- Validation workflow management
AdminSubscriptions.js
- Subscription listing
- Status filters (active, cancelled, expired)
- CSV export dropdown (Export All / Export Current View)
- Edit subscription dialog
AdminDonations.js (400+ lines)
- 4 stats cards: Total, Member, Public, Total Amount
- Filters: type, status, date range, search
- Responsive table with mobile cards
- CSV export functionality
AdminEvents.js
- Event management interface
- Create/edit events
- Publish/unpublish toggle
- Cover image upload
- RSVP tracking
- Attendance marking
Component Library (Radix UI)
45+ UI Components in src/components/ui/:
Form Components:
- Button, Input, Textarea, Checkbox, Radio
- Select, Label, Form
Layout Components:
- Card, Dialog, Sheet (Drawer), Popover
- Dropdown Menu, Tabs, Accordion
Feedback Components:
- Alert, Badge, Toast (Sonner)
- Progress, Skeleton, Spinner
Navigation:
- Navigation Menu, Breadcrumb, Pagination
Usage Example:
import { Button } from "./components/ui/button";
import { Dialog, DialogContent, DialogTitle } from "./components/ui/dialog";
import {
Select,
SelectTrigger,
SelectContent,
SelectItem,
} from "./components/ui/select";
<Button className="bg-var(--purple-lavender) text-white">Click me</Button>;
Admin Sidebar Features
Logo Integration:
- LOAF logo in header
- Shows logo + "Admin" text when expanded
- Logo only when collapsed
- Smooth transition animations
Navigation Groups:
- Dashboard (standalone)
- MEMBERSHIP - Staff, Members, Validations
- FINANCIALS - Plans, Subscriptions, Donations
- EVENTS & MEDIA - Events, Gallery
- DOCUMENTATION - Newsletters, Financial Reports, Bylaws
- Permissions (Superadmin only)
Design System
Color Palette
LOAF Brand Colors:
--primary: #422268 /* Deep Purple - Primary brand */
--secondary: #664fa3 /* Light Purple - Secondary elements */
--accent: #ff9e77 /* Coral - Accents and highlights */
--muted: #ddd8eb /* Light Purple Gray - Borders */
--background: #f9f5ff /* Very Light Purple - Backgrounds */
--foreground: #422268 /* Text color */
Usage in Tailwind:
<div className="bg-var(--purple-ink) text-white">
<h1 className="text-var(--orange-light)">Accent Text</h1>
<p className="text-var(--purple-lavender)">Secondary Text</p>
</div>
Typography
Font Families:
- Headings: 'Inter', sans-serif
- Body: 'Nunito Sans', sans-serif
- Code: 'Fira Code', monospace (if needed)
Font Sizes:
text-xs → 0.75rem (12px)
text-sm → 0.875rem (14px)
text-base → 1rem (16px)
text-lg → 1.125rem (18px)
text-xl → 1.25rem (20px)
text-2xl → 1.5rem (24px)
text-3xl → 1.875rem (30px)
Usage:
<h1 className="text-3xl font-semibold text-var(--purple-ink)" style={{ fontFamily: "'Inter', sans-serif" }}>
Page Title
</h1>
<p className="text-base text-var(--purple-lavender)" style={{ fontFamily: "'Nunito Sans', sans-serif" }}>
Body text
</p>
Spacing System
Tailwind Spacing Scale:
p-2 → 0.5rem (8px)
p-4 → 1rem (16px)
p-6 → 1.5rem (24px)
p-8 → 2rem (32px)
gap-2, gap-4, gap-6, gap-8 (same scale for flex/grid gaps)
Component Styling Patterns
Cards:
<Card className="p-6 bg-background rounded-2xl border-2 border-var(--neutral-800)">
{/* Content */}
</Card>
Buttons:
// Primary
<Button className="bg-var(--purple-lavender) text-white hover:bg-var(--purple-ink) rounded-full px-6 py-3">
Primary Action
</Button>
// Secondary
<Button variant="outline" className="border-2 border-var(--neutral-800) text-var(--purple-lavender) hover:bg-var(--lavender-300) rounded-full">
Secondary Action
</Button>
// Destructive
<Button className="bg-red-600 text-white hover:bg-red-700 rounded-full">
Delete
</Button>
Form Inputs:
<Input className="rounded-xl border-2 border-var(--neutral-800) focus:border-var(--purple-lavender)" />
<Textarea className="rounded-xl border-2 border-var(--neutral-800) min-h-[120px]" />
<Select>
<SelectTrigger className="rounded-xl border-2 border-var(--neutral-800)">
<SelectValue placeholder="Select..." />
</SelectTrigger>
</Select>
Badges:
// Status badges
<Badge className="bg-green-100 text-green-800">Active</Badge>
<Badge className="bg-yellow-100 text-yellow-800">Pending</Badge>
<Badge className="bg-red-100 text-red-800">Rejected</Badge>
Icons (Lucide React)
Common Icons:
import {
User,
Mail,
Phone,
MapPin, // User info
Calendar,
Clock,
CheckCircle, // Status
Edit,
Trash2,
X,
Check, // Actions
Search,
Filter,
Download, // Utilities
Heart,
DollarSign,
CreditCard, // Financial
AlertTriangle,
Info,
HelpCircle, // Alerts
} from "lucide-react";
<User className="h-5 w-5 text-var(--purple-lavender)" />;
Responsive Design
Breakpoints:
sm: 640px → @media (min-width: 640px)
md: 768px → @media (min-width: 768px)
lg: 1024px → @media (min-width: 1024px)
xl: 1280px → @media (min-width: 1280px)
2xl: 1536px → @media (min-width: 1536px)
Mobile-First Approach:
<div className="flex flex-col md:flex-row gap-4">
{/* Stacks vertically on mobile, horizontal on tablet+ */}
</div>
<div className="hidden md:block">
{/* Only shows on tablet+ */}
</div>
<div className="md:hidden">
{/* Only shows on mobile */}
</div>
Animations
Tailwind Transitions:
<Button className="transition-all duration-200 hover:scale-105">
Hover me
</Button>
<div className="animate-fade-in">
{/* Fades in on mount */}
</div>
Deployment Guide
Production Build
1. Environment Variables
Create .env.production:
REACT_APP_BACKEND_URL=https://api.loaf.org
REACT_APP_SENTRY_DSN=your-production-sentry-dsn
2. Build Application
# Install dependencies
yarn install
# Create production build
yarn build
Build output will be in /build directory.
3. Deployment Options
Option A: Netlify (Recommended)
Via Netlify CLI:
# Install Netlify CLI
npm install -g netlify-cli
# Login
netlify login
# Deploy
netlify deploy --prod --dir=build
Via Git Integration:
- Push code to GitHub/GitLab
- Connect repository in Netlify dashboard
- Configure:
- Build command:
yarn build - Publish directory:
build - Environment variables (from .env.production)
- Build command:
- Deploy automatically on push
Configure Redirects (public/_redirects):
/* /index.html 200
This enables client-side routing.
Option B: Vercel
# Install Vercel CLI
npm install -g vercel
# Deploy
vercel --prod
Configure (vercel.json):
{
"rewrites": [{ "source": "/(.*)", "destination": "/index.html" }],
"env": {
"REACT_APP_BACKEND_URL": "https://api.loaf.org"
}
}
Option C: Traditional Web Server (Nginx)
1. Copy build files to server:
scp -r build/* user@server:/var/www/loaf-frontend/
2. Configure Nginx (/etc/nginx/sites-available/loaf-frontend):
server {
listen 80;
server_name app.loaf.org;
root /var/www/loaf-frontend;
index index.html;
location / {
try_files $uri /index.html;
}
# Cache static assets
location /static/ {
expires 1y;
add_header Cache-Control "public, immutable";
}
# Gzip compression
gzip on;
gzip_types text/plain text/css application/json application/javascript text/xml application/xml text/javascript;
}
3. Enable site and restart:
sudo ln -s /etc/nginx/sites-available/loaf-frontend /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl restart nginx
4. SSL Certificate:
sudo certbot --nginx -d app.loaf.org
Option D: AWS S3 + CloudFront
1. Create S3 bucket:
aws s3 mb s3://loaf-frontend
aws s3 sync build/ s3://loaf-frontend --delete
2. Configure bucket for static hosting:
aws s3 website s3://loaf-frontend --index-document index.html --error-document index.html
3. Create CloudFront distribution pointing to S3 bucket with custom error pages (all errors → /index.html).
Performance Optimization
1. Code Splitting:
// Lazy load routes
import { lazy, Suspense } from "react";
const AdminDonations = lazy(() => import("./pages/admin/AdminDonations"));
<Route
path="/admin/donations"
element={
<Suspense fallback={<div>Loading...</div>}>
<AdminDonations />
</Suspense>
}
/>;
2. Image Optimization:
- Use WebP format when possible
- Compress images before upload
- Use lazy loading:
loading="lazy"
3. Bundle Analysis:
# Install analyzer
yarn add --dev webpack-bundle-analyzer
# Analyze bundle
yarn build
npx webpack-bundle-analyzer build/static/js/*.js
CI/CD Pipeline
GitHub Actions (.github/workflows/deploy.yml):
name: Deploy Frontend
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: "18"
- run: yarn install
- run: yarn build
env:
REACT_APP_BACKEND_URL: ${{ secrets.BACKEND_URL }}
- uses: netlify/actions/cli@master
with:
args: deploy --dir=build --prod
env:
NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_TOKEN }}
NETLIFY_SITE_ID: ${{ secrets.NETLIFY_SITE_ID }}
Troubleshooting
Common Issues
1. Module Not Found Errors
Error: Module not found: Can't resolve 'package-name'
Solution:
# Clear node_modules and reinstall
rm -rf node_modules yarn.lock
yarn install
# Or with npm
rm -rf node_modules package-lock.json
npm install
2. CORS Errors
Error: Access to XMLHttpRequest blocked by CORS policy
Solution:
- Backend must include frontend URL in CORS_ORIGINS
- Check REACT_APP_BACKEND_URL is correct
- Backend:
CORS_ORIGINS=http://localhost:3000,https://app.loaf.org
3. 401 Unauthorized
Error: API returns 401 after some time
Solution:
- JWT token expired (default 30 minutes)
- User needs to log in again
- Check token is being sent in Authorization header
4. Environment Variables Not Working
Error: process.env.REACT_APP_BACKEND_URL is undefined
Solution:
- Ensure variable name starts with
REACT_APP_ - Restart development server after changing .env
- Don't commit .env to git (use .env.example)
5. Build Fails
Error: npm run build fails with memory error
Solution:
# Increase Node memory limit
NODE_OPTIONS=--max_old_space_size=4096 yarn build
6. Routing Not Working in Production
Error: Refresh on /dashboard returns 404
Solution:
- Configure server to redirect all routes to index.html
- Netlify: Add
_redirectsfile - Nginx: Use
try_files $uri /index.html - Vercel: Add vercel.json with rewrites
7. Images Not Loading
Error: Profile photos return 404
Solution:
- Check R2_PUBLIC_URL is correct in backend .env
- Verify Cloudflare R2 bucket is public
- Check CORS settings in R2 bucket
Debug Mode
// Add to any component for debugging
console.log("Component rendered", { user, props });
// Check API responses
api.interceptors.response.use(
(response) => {
console.log("API Response:", response);
return response;
},
(error) => {
console.error("API Error:", error.response);
return Promise.reject(error);
}
);
Getting Help
- Project Context: See
CLAUDE.mdandPRD.md - API Docs: http://localhost:8000/docs (backend Swagger)
- React Docs: https://react.dev/
- Tailwind CSS: https://tailwindcss.com/docs
- Radix UI: https://www.radix-ui.com/primitives
Additional Resources
- React Documentation: https://react.dev/
- React Router: https://reactrouter.com/
- Tailwind CSS: https://tailwindcss.com/
- Radix UI: https://www.radix-ui.com/
- React Hook Form: https://react-hook-form.com/
- Zod: https://zod.dev/
- Lucide Icons: https://lucide.dev/
Last Updated: December 18, 2024 Version: 1.0.0 Maintainer: LOAF Development Team
Backend API
Auth
- POST
/api/auth/register - GET
/api/auth/verify-email - POST
/api/auth/resend-verification-email - POST
/api/auth/login - POST
/api/auth/forgot-password - POST
/api/auth/reset-password - GET
/api/auth/me - GET
/api/auth/permissions
Users
- PUT
/api/users/change-password - GET
/api/users/profile - PUT
/api/users/profile
Members
- GET
/api/members/directory(defined twice in code) - GET
/api/members/directory/{user_id} - GET
/api/members/profile - PUT
/api/members/profile - POST
/api/members/profile/upload-photo - DELETE
/api/members/profile/delete-photo - GET
/api/members/calendar/events - GET
/api/members/gallery - GET
/api/members/event-activity
Events (public/member)
- GET
/api/events - GET
/api/events/{event_id} - GET
/api/events/{event_id}/gallery - POST
/api/events/{event_id}/rsvp - GET
/api/events/{event_id}/download.ics
Calendars
- GET
/api/calendars/subscribe.ics - GET
/api/calendars/all-events.ics
Newsletters (public)
- GET
/api/newsletters - GET
/api/newsletters/years
Financials (public)
- GET
/api/financials
Bylaws (public)
- GET
/api/bylaws/current - GET
/api/bylaws/history
Config/Diagnostics
- GET
/api/config - GET
/api/config/limits - GET
/api/diagnostics/cors
Invitations
- GET
/api/invitations/verify/{token} - POST
/api/invitations/accept
Subscriptions
- GET
/api/subscriptions/plans - POST
/api/subscriptions/checkout
Donations
- POST
/api/donations/checkout
Contact
- POST
/api/contact
Admin – Calendar
- POST
/api/admin/calendar/sync/{event_id} - DELETE
/api/admin/calendar/unsync/{event_id}
Admin – Event Gallery
- POST
/api/admin/events/{event_id}/gallery - DELETE
/api/admin/event-gallery/{image_id} - PUT
/api/admin/event-gallery/{image_id}
Admin – Events
- POST
/api/admin/events - PUT
/api/admin/events/{event_id} - GET
/api/admin/events/{event_id} - GET
/api/admin/events/{event_id}/rsvps - PUT
/api/admin/events/{event_id}/attendance - GET
/api/admin/events - DELETE
/api/admin/events/{event_id}
Admin – Storage
- GET
/api/admin/storage/usage - GET
/api/admin/storage/breakdown
Admin – Users & Invitations
- GET
/api/admin/users - GET
/api/admin/users/invitations - GET
/api/admin/users/export - GET
/api/admin/users/{user_id} - PUT
/api/admin/users/{user_id} - PUT
/api/admin/users/{user_id}/validate - PUT
/api/admin/users/{user_id}/status - POST
/api/admin/users/{user_id}/reject - POST
/api/admin/users/{user_id}/activate-payment - PUT
/api/admin/users/{user_id}/reset-password - PUT
/api/admin/users/{user_id}/role - POST
/api/admin/users/{user_id}/resend-verification - POST
/api/admin/users/{user_id}/upload-photo - DELETE
/api/admin/users/{user_id}/delete-photo - POST
/api/admin/users/create - POST
/api/admin/users/invite - POST
/api/admin/users/invitations/{invitation_id}/resend - DELETE
/api/admin/users/invitations/{invitation_id} - POST
/api/admin/users/import - GET
/api/admin/users/import-jobs - GET
/api/admin/users/import-jobs/{job_id}
Admin – Imports
- POST
/api/admin/import/upload-csv - GET
/api/admin/import/{job_id}/preview - POST
/api/admin/import/{job_id}/execute - POST
/api/admin/import/{job_id}/rollback - GET
/api/admin/import/{job_id}/status - GET
/api/admin/import/{job_id}/errors/download
Admin – Subscriptions
- GET
/api/admin/subscriptions/plans - GET
/api/admin/subscriptions/plans/{plan_id} - POST
/api/admin/subscriptions/plans - PUT
/api/admin/subscriptions/plans/{plan_id} - DELETE
/api/admin/subscriptions/plans/{plan_id} - GET
/api/admin/subscriptions - GET
/api/admin/subscriptions/stats - PUT
/api/admin/subscriptions/{subscription_id} - POST
/api/admin/subscriptions/{subscription_id}/cancel - GET
/api/admin/subscriptions/export
Admin – Donations
- GET
/api/admin/donations - GET
/api/admin/donations/stats - GET
/api/admin/donations/export
Admin – Newsletters
- POST
/api/admin/newsletters - PUT
/api/admin/newsletters/{newsletter_id} - DELETE
/api/admin/newsletters/{newsletter_id}
Admin – Financials
- POST
/api/admin/financials - PUT
/api/admin/financials/{report_id} - DELETE
/api/admin/financials/{report_id}
Admin – Bylaws
- POST
/api/admin/bylaws - PUT
/api/admin/bylaws/{bylaws_id} - DELETE
/api/admin/bylaws/{bylaws_id}
Admin – Roles
- GET
/api/admin/roles - GET
/api/admin/roles/assignable - POST
/api/admin/roles - GET
/api/admin/roles/{role_id} - PUT
/api/admin/roles/{role_id} - DELETE
/api/admin/roles/{role_id} - GET
/api/admin/roles/{role_id}/permissions - PUT
/api/admin/roles/{role_id}/permissions
Admin – Permissions
- GET
/api/admin/permissions - GET
/api/admin/permissions/modules - GET
/api/admin/permissions/roles/{role} - PUT
/api/admin/permissions/roles/{role} - POST
/api/admin/permissions/seed
Admin – Stripe Settings
- GET
/api/admin/settings/stripe/status - POST
/api/admin/settings/stripe/test-connection - PUT
/api/admin/settings/stripe
Webhooks
- POST
/api/webhooks/stripe