Overview
UpdatedEasyLaunchpad is a comprehensive .NET Core boilerplate designed to accelerate your SaaS application development. It provides a solid foundation with pre-built features, modern architecture, and clean code practices.
Key Features
- Complete user authentication and authorization system
- Modular architecture, easy to extend and customize
- Subscription management with Stripe and Paddle integration
- Responsive admin dashboard with Tailwind CSS and DaisyUI components
- Email templating and notification system
- Background job processing with Hangfire
- System logs by Serilog
- Centralized application settings to manage all app areas
Architecture Overview
EasyLaunchpad follows a clean, modular architecture that separates concerns and promotes maintainability:
Backend Architecture
- Clean Architecture pattern
- Domain-driven design principles
- Repository pattern for data access
- Entity Framework Core ORM
- Scheduled jobs with Hangfire & System logs
Frontend Architecture
- Razor Pages for server-rendered UI
- Tailwind CSS for styling
- DaisyUI component library
- Responsive design principles
- Clean separation of view components and partials
Technology Stack
EasyLaunchpad Quick Setup
5 minsEasyLaunchpad is a comprehensive, production-ready solution designed to get your business up and running in minimal time. This complete platform comes with all essential features pre-integrated, requiring only simple configuration to launch your branded service.
With your valid license, you can deploy a fully functional SAAS platform by following our streamlined setup process. The intuitive configuration workflow allows you to:
- Establish core branding (app name, logo, color scheme)
- Configure essential business operations (payments, email, authentication)
- Enable advanced features as needed (social integration, security enhancements)
Setup Organization
The setup is organized into mandatory and optional sections:
Essential configurations
(required for basic operation)
- Server
- Branding (app name, logo etc)
- Email account for messages and updates
- Stripe/Paddle configuration to accept app purchases
Premium features
(activate as your business needs evolve)
- Google OAuth support
- Captcha
- Email confirmation
Most features work immediately after configuration - no additional development required. Our sensible defaults minimize setup time while maintaining flexibility for customization.
Implementation Tip
For optimal results, we recommend completing all basic configurations before launching, then revisiting optional features as your user base grows. The entire setup can typically be completed in under 10 minutes for basic deployments.
Further Reading
For comprehensive technical specifications and advanced configuration options, please refer to the dedicated module documentation. Each feature section contains detailed implementation guides, best practices, and troubleshooting resources to support your deployment.
Follow these steps to quickly configure and customize your application within few minutes.
Core Features
- Automatic database creation
- Custom branding options
- Social media integration
- Email configuration
- Payment gateway support
Security Features
- Google OAuth integration
- reCAPTCHA protection
- Email confirmation
- Secure payment processing
- Admin-only configuration
1. Database Configuration
Connection String Setup
Locate appsettings.json
Find the configuration file in your project root
Update Connection String
Modify the DefaultConnection with your database details
Run Application
The database will be created automatically on first run
"ConnectionStrings": {
"DefaultConnection": "Server=your_server;Database=your_db_name;User Id=your_username;Password=your_password;"
}
2. Branding Configuration
Customize Application Appearance
Setting | Description | Location |
---|---|---|
Application Name | The name displayed throughout the app | Admin → System Settings → Branding |
Favicon | Browser tab icon (32x32px, .ico) | Admin → System Settings → Branding |
Application Logo | Main logo displayed in header (150x50px, .png) | Admin → System Settings → Branding |
3. Footer Configuration
Social Links & Copyright
Navigate to Footer Settings
Go to Admin → System Settings → Social & Footer
Add Social Media Links
Enter URLs for Facebook, Twitter, LinkedIn
Set Copyright Notice
Add your copyright text (e.g., "© 2023 Your Company")
Save Changes
Click Save to apply
4. Email Configuration
Email Account Setup
Navigate to Email System
Go to Admin → Email System → Email Accounts
Add Account
Add new Email Account and Emails will be functional and working after the successful configuration - nothing else is required.
Next, Test the newly added email account, Open Emial Account list, and click on 3 dots menu in the grid, click on Test Email
5. Payment Gateway Setup
Stripe/Paddle Integration
Creating Subscription Packages
Navigate to Packages
Go to Admin → Payment System → Packages
Add New Package
Click "Add New Package" button
Configure Package
Set name, price, features, and duration
Save Package
Package will be available for purchase immediately
6. Google OAuth Setup
Google Authentication
Before You Begin
You'll need to create OAuth credentials in the Google Cloud Console.
Navigate to Authentication Settings
Go to Admin → System Settings → Authentication
7. reCAPTCHA Setup
Google reCAPTCHA
Navigate to Authentication Settings
Go to Admin → System Settings → Security
Note
Get your keys from the reCAPTCHA admin console.
8. Email Confirmation
Navigate to Authentication Settings
Go to Admin → System Settings → Authentication
Require Email Confirmation
When enabled, new users will receive a confirmation email with a verification link before they can log in.
Important
Ensure your email configuration is working properly before enabling this feature.
9. Theme Customization
Customize UI Elements for your Business/SaaS
Navigate to Landing Page
Open Views/Home/Index.cshtml
Locate Partial Views
Find partial views in Views/Shared/
or Views/Home/Partials/
Modify Components
Edit these files to customize different sections:
_Header.cshtml
- Navigation and header_Hero.cshtml
- Main banner section_Features.cshtml
- Features listing_Footer.cshtml
- Footer content
CSS Customization
Modify CSHTML files directly with TailwindCSS utility classes according to your need, clean and rebuild soltution and site.csss and admin.css files will be updated automaticaly.
💡 Pro Tip
Want to match the design with your brand? Need more flexibility?
Explore our pre-built variants for the Hero section, Features, Navigation, CTA, and Footer inside the UI documentation.
🎨 Mix & match components and apply your own branding — no need to start from scratch.
Installation Guide
UpdatedGet started with EasyLaunchpad in just a few minutes. Follow these steps to set up your development environment and run the application locally.
Prerequisites
Make sure you have the following installed before proceeding:
- .NET 8.0 SDK
- Node.js (v22+ recommended) – for Tailwind CSS, frontend assets, and package management
- Visual Studio 2022+ or VS Code with C# extension
- SQL Server 2019+ (Express edition supported)
- Git for version control
- IIS (Internet Information Services)
Step 1: Download the source code
Make sure you have proper license to use the code
Step 2: Configure Database Connection
Update the connection string in appsettings.json
with your SQL Server details:
{
"ConnectionStrings": {
"DefaultConnection": "Server=localhost;Database=EasyLaunchpad;Trusted_Connection=True;MultipleActiveResultSets=true"
},
// Other settings...
}
Security Warning
Never commit sensitive connection strings to source control. Use environment variables or user secrets for production environments.
Step 3: Restore NuGet Packages
dotnet restore
This will download all required NuGet packages for the project
Step 4: Restoring Node.js Packages
npm install
Open terminal in your Easylaunchpad.Website root
Step 5: Build the Application
dotnet build
Compiles the application and checks for build errors
Step 6: Run the Application
dotnet run
The application will automatically:
- Apply database migrations
- Start the web server
Success!
You've successfully installed EasyLaunchpad. Default admin credentials are:
- Email: admin@easylaunchpad.com
- Password: Admin@123
Folder Structure
Understanding the project structure is essential for efficient development. EasyLaunchpad adopts a clean, modular architecture that promotes separation of concerns and scalability.
EasyLaunchpad/
├── DataAccess/ # Handles database context and EF Core migrations
│ ├── Migrations/ # Auto-generated database migrations
│ └── ApplicationDbContext.cs # Main database context
│
├── Infrastructure/ # Infrastructure-level implementations
│ ├── Extensions/ # Core utility and extension methods
│ ├── Filters/ # Custom action and authorization filters
│ ├── Services/ # Service interfaces and implementations
│ └── Utilities/ # Middleware, constants, and helper classes
│
├── Models/ # Domain models and shared DTOs
│ ├── Db/ # Entity framework domain entities
│ ├── Dto/ # Data Transfer Objects
│ ├── VM/ # View Models for UI binding
│ └── Utilities/ # Enums, constants, and shared types
│
└── Website/ # Main web application (MVC + Razor)
├── Areas/ # Modular feature areas (e.g., Admin)
├── Controllers/ # API and MVC controllers
├── Models/ # View-specific model classes
├── Core/ # Core configurations (e.g., AutoMapper, jobs)
├── Views/ # Razor views and layout templates
├── wwwroot/ # Static files (CSS, JS, images)
└── Program.cs # Application entry point
Configuration
EasyLaunchpad uses a configuration system that allows you to customize various aspects of the application without modifying code.
Application Settings
The main configuration file is appsettings.json
. Here are the key sections:
{
"ConnectionStrings": {
"DefaultConnection": "Server=localhost;Database=EasyLaunchpad;Trusted_Connection=True;MultipleActiveResultSets=true"
},
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"AllowedHosts": "*",
}
Environment-Specific Configuration
For different environments, use environment-specific settings files:
appsettings.Development.json
- Development environmentappsettings.Staging.json
- Staging environmentappsettings.Production.json
- Production environment
Security Best Practice
Store sensitive configuration values like API keys and connection strings in environment variables or user secrets. Never commit these values to source control.
Authentication & Authorization
EasyLaunchpad provides a complete authentication and authorization system built on ASP.NET Core Identity.
Authentication Options
The following authentication methods are supported out of the box:
Local Authentication
- Username/password authentication
- Email confirmation
- Password reset functionality
External Providers
- Google authentication
Configuring External Providers
To enable external authentication providers, enable the open authentication from admin > settings > authentication settings
:
Role-Based Authorization
EasyLaunchpad includes a role-based authorization system with predefined roles:
Role | Description | Permissions |
---|---|---|
Admin | System-wide administrator | Full access to all features |
Registered | Standard user | Basic application access |
Using Authorization in Controllers
Apply authorization attributes to controllers or actions:
[Authorize(Roles = "Admin,Registered")]
public class UserManagementController : Controller
{
[HttpGet]
public IActionResult Index()
{
// Only TenantAdmin and Manager can access this
return View();
}
[Authorize(Roles = "Admin")]
[HttpPost]
public async Task DeleteUser(string userId)
{
// Only Admin can delete users
// Implementation...
return RedirectToAction("Index");
}
}
Admin Dashboard
UpdatedThe Admin Dashboard provides real-time monitoring of your application's key metrics and operations.
Dashboard Features
- Quick status overview of all system components
- Visual indicators for critical issues
- Historical data tracking and trends
System Requirements
- Modern web browser (Chrome, Firefox, Edge, Safari)
- Admin privileges to access the dashboard
- ASP.NET Core 8.0 runtime
Dashboard Widgets
Sync
All widgets showing quick data overview. Click any widget for more detailed information.
Users & Roles Widget
Description
Displays statistics about user accounts and their roles in the system. Shows total users, active users.
Technical Details
- Endpoint:
/dashboard/user-role-stats
- Data Source: User service
Email Notification Widget
Description
Tracks email notification status including queued emails, emails sent today, failed deliveries, and scheduled emails with color-coded severity indicators.
Technical Details
- Endpoint:
/dashboard/email-notification
- Data Source: QueuedEmail database table
-
Metrics:
- Queued: Emails waiting to be sent
- Sent Today: Successful deliveries today
- Failed: Emails with >3 failed attempts
Cron Jobs Widget
Description
Monitors background jobs and scheduled tasks, showing currently running jobs, recurring jobs, and success/failure rates.
Technical Details
- Endpoint:
/dashboard/cron-job
- Data Source: ScheduledJob database table
-
Metrics:
- Recurring Jobs: Total scheduled jobs
- Running Now: Currently executing jobs
- Success/Fail: Last 24 hours stats
Logs Widget
Description
Provides insight into system logging activity, showing total logs today broken down by severity level (info, warning, error) with trend analysis.
Technical Details
- Endpoint:
/dashboard/logs
- Data Source: Logs database table
-
Metrics:
- Total Logs: Today's log entries
- Info: Informational messages
- Warning: Potential issues
- Error: Critical errors
- Logs/Hour: Average logging rate
Sitemap Widget
Description
Tracks the status of your website's sitemap, showing total pages, indexed pages, and hidden pages with last update timestamp.
Technical Details
- Endpoint:
/dashboard/sitemap
- Data Source: SitemapEntry database table
-
Metrics:
- Total Entries: All sitemap entries
- Indexed: Pages marked for search engines
- Hidden: Pages with noindex
- Last Update: Most recent change
Payment & Subscriptions Widget
Description
Provides financial metrics including today's payments, active subscriptions, failed payments, and upcoming renewals with revenue breakdowns.
Technical Details
- Endpoint:
/dashboard/payments-subscription
- Data Source: Subscription database table
-
Metrics:
- Payments Today: Total revenue today
- Active Subs: Currently active subscriptions
- Failed Payments: Today's failures
- Upcoming Renewals: Next 7 days
- MRR (Monthly Recurring Revenue): Current monthly revenue
Extending the Dashboard
Important
These extensions require developer access and knowledge of ASP.NET Core and Razor views.
Adding New Widgets
To add a new widget to the dashboard:
- Create a new partial view in
Views/Shared
folder - Add the widget to the dashboard grid in
Views/Dashboard/Index.cshtml
- Create a new endpoint in
DashboardController
- Implement the service method in
DashboardService
- Create DTO classes for the response data
Customizing Widgets
Existing widgets can be customized by:
- Modifying the partial view HTML/CSS
- Adding new metrics to service methods
- Extending DTO classes with additional properties
- Changing visualization types (charts, gauges, etc.)
Example Widget Implementation
// 1. Add Controller Endpoint
[HttpGet("new-widget")]
public async Task<IActionResult> GetNewWidgetData()
{
var data = await _dashboardService.GetNewWidgetDataAsync();
return Ok(data);
}
// 2. Add Service Method
public async Task<NewWidgetDto> GetNewWidgetDataAsync()
{
// Fetch data from database or external API
var metrics = await _repository.GetWidgetMetricsAsync();
return new NewWidgetDto
{
TotalItems = metrics.Count,
SuccessRate = metrics.SuccessPercentage,
LastUpdated = DateTime.UtcNow
};
}
// 3. Create DTO
public class NewWidgetDto
{
public int TotalItems { get; set; }
public double SuccessRate { get; set; }
public DateTime LastUpdated { get; set; }
}
// 4. Add partial view to dashboard
<partial name="_NewWidget" model="Model.NewWidgetData" />
Widget Customization Example
public class EmailNotificationDto
{
public int Queued { get; set; }
public int SentToday { get; set; }
public int Failed { get; set; }
// Added properties
public double DeliveryRate { get; set; }
public TimeSpan AvgProcessingTime { get; set; }
public Dictionary<string, int> ByProvider { get; set; }
[JsonIgnore]
public bool IsHealthy => DeliveryRate > 0.95;
}
User & Roles Management
UpdatedManage users and roles, control access, and define responsibilities across your application.
User Management Features
- Create, update, and delete user accounts
- Assign multiple roles to users
- Activate/deactivate accounts
- Advanced search & filtering
- Pagination support
- Profile management
Role Management Features
- Create, update, and delete roles
- Search & filter capabilities
- Pagination support
- Default role protection
User Management
Important
All user management endpoints require admin privileges.
User Statuses
Status | Value | Description |
---|---|---|
Active | 1 | User can log in and access the system |
Inactive | 2 | User account deactivated/inactive and cannot login and access the system |
Pending | 3 | User account created but not yet activated |
Deleted | 4 | Soft-deleted user (retained for auditing) |
User's Controller Endpoints
Endpoint | Method | Description | Parameters |
---|---|---|---|
/user |
GET | Main user management page | None |
/user/list |
POST | Get paginated user list | start, draw, role, status, search, length |
/user/add |
GET | Get add user form | None |
/user/add |
POST | Create new user | UserVM model |
/user/update/{id} |
GET | Get edit user form | User ID |
/user/update/{id} |
PUT | Update user | User ID, UserVM model |
/user/delete/{userId} |
DELETE | Delete user | User ID |
User Data Models
UserVM (View Model)
public class UserVM {
public string Email { get; set; }
public string Password { get; set; }
public string FullName { get; set; }
public string PhoneNumber { get; set; }
public string Address { get; set; }
public string City { get; set; }
public string State { get; set; }
public string Country { get; set; }
public string ZipCode { get; set; }
public IFormFile ProfilePicture { get; set; }
public string[] Role { get; set; }
public bool IsActive { get; set; }
}
UserUpdateDto
public class UserUpdateDto {
public string Id { get; set; }
public string Email { get; set; }
public string FullName { get; set; }
public string PhoneNumber { get; set; }
public string Address { get; set; }
public string City { get; set; }
public string State { get; set; }
public string Country { get; set; }
public string ZipCode { get; set; }
public string ProfilePicture { get; set; }
public string[] RoleIds { get; set; }
public SelectListItem[] RolesList { get; set; }
public bool IsActive { get; set; }
}
Role Management
Security Note
Role modifications can affect system security. Changes are logged and require admin privileges.
Role's Controller Endpoints
Endpoint | Method | Description | Parameters |
---|---|---|---|
/role |
GET | Main role management page | None |
/role/list |
POST | Get paginated role list | start, draw, search, length |
/role/add |
GET | Get add role form | None |
/role/add |
POST | Create new role | RoleVM model |
/role/update/{id} |
GET | Get edit role form | Role ID |
/role/update/{roleId} |
PUT | Update role | Role ID, RoleVM model |
Role Data Models
RoleVM (View Model)
public class RoleVM {
public string Name { get; set; }
}
Default System Roles
Role | Description | Permissions |
---|---|---|
Admin | Application administrator | Full access within the application |
Registered | Standard user | Basic application access |
Extending Functionality
Developer Note
These extensions require developer access and knowledge of ASP.NET Core and Razor views.
Adding New User Fields
To add new fields to the user model:
- Add the property to
ApplicationUser
entity - Update the
UserVM
andUserUpdateDto
models - Modify the
Add
andUpdate
methods in UserService - Update the relevant views (add/edit forms)
- Add any necessary validation rules
Customizing User Search
To add new search criteria to the user list:
// In UserService.GetAllUsersAsync()
if (!string.IsNullOrEmpty(searchPage.NewCriteria))
{
query = query.Where(u => u.NewProperty.Contains(searchPage.NewCriteria));
}
Implementing User Import
To add bulk user import functionality:
// In UserController
[HttpPost("import")]
public async Task ImportUsers(IFormFile file)
{
if (file == null || file.Length == 0)
return BadRequest("No file uploaded");
using var stream = file.OpenReadStream();
var result = await _userService.ImportUsersAsync(stream);
if (result.Success)
return Ok(result);
return BadRequest(result);
}
Security Considerations
- Always validate and sanitize user input when managing users and roles
- Implement proper audit logging for all user and role modifications
- Consider implementing rate limiting on user management endpoints
- Protect sensitive operations with additional authentication factors
- Regularly review role assignments
Payment & Subscription
UpdatedComprehensive documentation for managing payment gateways, packages, and subscriptions
These modules allow administrators to configure payment gateways, create subscription packages, and manage customer subscriptions.
Payment Gateways
- Stripe and Paddle integration
- Secure credential storage
- Default gateway selection
- No-code configuration
Packages
- Multiple package types
- Flexible durations
- Gateway association
- Easy management
Subscriptions
- Active/inactive tracking
- Searchable records
- Pagination support
- Detailed monitoring
Payment Gateway
Controller: PaymentGatewayController.cs
Handles all operations related to payment gateways including listing, adding, updating, and deleting gateways. It also allows for configuring gateway-specific settings such as API credentials.
Key Actions
Action | Description |
---|---|
Index() |
Returns the payment gateway overview page |
GetList() |
Retrieves a paginated list of gateways |
Add() /Update() |
Shows the form to add or edit a gateway |
SetDefault() |
Marks a payment gateway as default |
Delete() |
Deletes a payment gateway |
The configuration interface for payment methods is intuitive and secure. Simply paste your credentials and save - no code changes required!
Configuration Process
Stripe Configuration
- Publishable Key
- Secret Key
- Webhook Secret
- Customer Portal Url
Paddle Configuration
- API Key
- Client Token
- Success Url
- Error Url
- Customer Portal Url
Packages
Controller: PackageController.cs
Manages subscription packages, each linked to a payment gateway with specific types and frequencies.
Key Actions
Action | Description |
---|---|
Index() |
View for all packages |
GetList() |
Retrieves paginated package list |
Add() /Update() |
Opens views for package editing |
Adding packages automatically update the public pricing page.
Package Configuration
Package Properties
- Associated Gateway
- Name and Description
- Actual Amount (To show the original pricing)
- Current Amount(Show discounted pricing)
- Pricing Header (Pricing Heading inside the pricing card)
- Currency symbol selection
- Billing Frequency (One time or Subscription)
- Product Id (from Paddle/Stripe)
- Price Id (from Paddle/Stripe)
- Display order (used to show the packages 1st, 2nd or the 3rd place)
- Package Type (Basic, Best Valued, Most Popular) Shows the outer lines highlighted and packge is prominantly shown
- Active (show the package on public site or not)
- Description (Package features to be added here)
UI Elements
- Gateway dropdown
- Type selection
- Duration options
- Price input with validation
Important Notes
- Package features must be manually configured in the Pricing section
- All payment credentials are encrypted before storage
- Test your new payment gateway in sandbox mode before going live
Email Templates
UpdatedDynamic email templating, queuing, and sending system for Easylaunchpad using DotLiquid templates and SMTP configurations.
Email Accounts
- SMTP configuration
- Multiple account support
- AES encrypted credentials
- Default account selection
Templates
- DotLiquid templating
- Dynamic placeholders
- Subject/Body customization
- Recipient fields
Queue System
- Asynchronous sending
- Bulk email support
- Retry mechanism
- Background processing
Email Account Configuration
Security Note
SMTP credentials are encrypted using AES-256 before storage in the database.
SMTP Account Management
The EmailAccount
model represents SMTP credentials and settings for sending emails.
Key Features
- Multiple SMTP account support
- Default account selection
- SSL/TLS encryption
- Credential encryption using AES
- Test email functionality
Message Templates with DotLiquid
Dynamic Email Templating
MessageTemplates are stored email blueprints that use DotLiquid placeholders for dynamic content rendering.
Template Fields
Field | Description | Example Placeholder |
---|---|---|
Subject | Email subject line | {{OrderNumber}} |
Body | HTML/Text email content | {{CustomerName}} |
To | Primary recipient | {{UserEmail}} |
CC/BCC | Carbon copy recipients | {{ManagerEmail}} |
Rendering Process
Retrieve template from database by name
Create dictionary with placeholder values
DotLiquid replaces placeholders with actual values
Add rendered email to queue for sending
Queued Email System
Performance Note
Emails are processed asynchronously via background service for better performance.
Asynchronous Email Processing
Emails are inserted into the QueuedEmail
table and sent by a background service.
Queue Benefits
Reliability
Emails persist in queue until successfully sent
Performance
Non-blocking sending process
Retry Mechanism
Automatic retries for failed sends
Bulk Sending
Efficient processing of multiple emails
Queue Status Tracking
Status | Description |
---|---|
Pending | Email waiting to be sent |
Sent | Successfully delivered |
Retrying | Failed but will retry |
Failed | Permanently failed after retries |
EmailEngineService
Primary Email Interface
The EmailEngineService.Execute()
method is the main entry point for sending emails.
Method Signature
Task Execute(string templateName, Dictionary<string, string> keyValuePairs);
Required Dictionary Keys
Subject
- Email subject lineToEmail
- Primary recipient emailReplyTo
- (Optional) Reply-to addressCC
/BCC
- (Optional) Carbon copy recipients
Adding New Templates
Important
Ensure all required placeholders are provided when executing templates to avoid rendering errors.
Template Creation Process
-
Add template to database
Create new record in MessageTemplate table with placeholders
-
Define required placeholders
Document all variables needed for the template
// Required placeholders: // - CustomerName // - OrderNumber // - CustomerEmail // - OrderTotal
-
Test the template
Use sample data to verify rendering works correctly
-
Implement in code
Call EmailEngineService.Execute() with proper data
Important Notes
-
SMTP credentials are encrypted using AES-256 before storage
-
Emails are sent asynchronously via background processing
-
Test templates thoroughly before production use
Scheduled Jobs
UpdatedComprehensive solution for managing background jobs in ASP.NET Core with Hangfire integration.
User Interface
- Job listing with sorting/filtering
- Advance Control Panel (Hangfire)
- Quick Run action
- Server-side pagination
Service Layer
- Job initialization
- Type synchronization
- Automatic discovery
Job Interfaces
- IScheduledJob
- IAsyncScheduledJob
- AsyncScheduledJob base
- Flexible implementation
User Interface Components
Note
All UI components are responsive and work across desktop and mobile devices.
Index View (Index.cshtml)
Feature | Description |
---|---|
Job Listing | Datatable with all scheduled jobs |
Columns | Name, Type, Schedule, Status, Dates |
Actions | Quick Run |
Pagination | Server-side with sorting/searching |
Service Layer (SchedulerJobService)
Important
Service layer handles all job management logic and synchronization with Hangfire.
Core Functionality
Job Initialization
public async Task InitializeSchedulerJobsAsync()
{
// Setup all active jobs with Hangfire
// RecurringJob.AddOrUpdate(...)
}
Key Features
- Automatic discovery of job implementations
- Support for sync/async job types
- Database persistence of configurations
- Automatic reinitialization on updates
Job Interfaces
IScheduledJob
Base interface for all scheduled jobs
public interface IScheduledJob
{
void Execute();
}
IAsyncScheduledJob
Extends IScheduledJob for async operations
public interface IAsyncScheduledJob : IScheduledJob
{
Task ExecuteAsync();
}
AsyncScheduledJob
Abstract base class for async jobs
public abstract class AsyncScheduledJob : IAsyncScheduledJob
{
public abstract Task ExecuteAsync();
public void Execute() =>
throw new NotSupportedException();
}
Extending the Functionality
Developer Note
These extensions require developer access and knowledge of ASP.NET Core and Hangfire.
Adding New Job Types
- Implement IScheduledJob or IAsyncScheduledJob
- System auto-discovers & registers the types to DI
- Sync with database types (optional)
public class MyNewJob : IAsyncScheduledJob
{
public async Task ExecuteAsync()
{
// Job logic here
await Task.Delay(1000);
}
public void Execute() =>
throw new NotSupportedException();
}
// In Startup.cs
services.AddTransient();
Customizing Job Behavior
- Change default schedule in InitializeSchedulerJobsAsync Or SyncJobTypesWithDatabaseAsync (if not depending on hanfgire storage)
- Extend ScheduledJob entity for parameters
- Update DTOs and views
// Example: Changing default schedule
var newJob = new ScheduledJob
{
JobName = jobType.Name,
JobType = typeName,
CronExpression = Cron.Hourly(), // Default
IsActive = false,
CreatedAt = DateTime.UtcNow
};
Usage Instructions
Action | Instructions |
---|---|
Viewing Jobs | Navigate to Scheduled Jobs page to see all configured jobs |
Advance Configuration | Navigate to the Hangfire console panel |
Quick Run | Use action button to immediately execute the job |
Adding New Jobs | Implement interface - system auto-discovers new jobs |
Best Practices
Job Implementation
- Use IAsyncScheduledJob for IO-bound work
- Keep CPU-bound jobs short
- Implement robust error handling
- Design jobs to be idempotent
Monitoring
- Add detailed execution logging
- Set up alerts for failures
- Review Hangfire dashboard
Troubleshooting
Issue | Solution |
---|---|
Job not appearing |
|
Job not executing |
|
Changes not effective |
|
System Summary
This system provides a flexible foundation for scheduled job management that can be extended to meet specific application needs while maintaining a consistent interface for administration.
Sitemaps
UpdatedAutomated website crawling and XML sitemap generation solution
System Overview
Note
This system automatically crawls your website and generates standards-compliant XML sitemaps through scheduled background jobs.
Scheduled Job
- Runs on configurable schedule (daily)
- Controlled by SEO settings
- Uses application's root as the base URL
- Automatic execution
Crawler Service
- Starts from root URL
- Follows internal links
- Excludes admin paths
- Normalizes URLs
Data Management
- CRUD operations
- Paginated listing
- Duplicate detection
- Search/sort capabilities
Key Components
CrawlAndGenerateSitemapJob
Responsibilities
- Executes sitemap generation process
- Checks auto-generation setting
- Initiates crawling process
- Generates and update sitemap.xml
Configuration
SeoSettings.GenerateAutoSitemap
flag- Root Address as Base URL and from
SeoSettings.SitemapBaseUrl primarily from Application Constants
- Cron schedule configuration
SitemapCrawlerService
Website Crawling
- Starts from root URL (/)
- Follows internal links
- Excludes admin/account paths
- Processes only HTML with 200 status
URL Normalization
- Converts to absolute URLs
- Removes fragments/queries
- Filters external links
- Detects duplicates
Key Features
SitemapService
Core Operations
- Create/Read/Update/Delete
- Paginated listing
- Search & sort
- Existence checking
Example: Add Entry
await _sitemapService.AddAsync(new SitemapEntry
{
Url = "https://example.com/page",
LastModified = DateTime.UtcNow,
ChangeFrequency = "weekly",
Priority = 0.8
});
Example: Get All
var entries = await _sitemapService
.GetAllAsync(pageNumber, pageSize);
How It Works
Job runs periodically based on cron schedule, checks if auto-generation is enabled
Starts from root URL, discovers internal links, skips excluded paths
Valid URLs stored in database SitemapEntries table with metadata
Generates XML sitemap with all URLs, saves to sitemap.xml
Sitemap XML Structure
<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
<url>
<loc>https://example.com/</loc>
<lastmod>2023-06-30</lastmod>
<changefreq>weekly</changefreq>
<priority>0.8</priority>
</url>
<!-- Additional URLs -->
</urlset>
Extending the Functionality
Customizing Crawling Behavior
Exclusion List
// Add to excludedPaths in SitemapCrawlerService
private readonly List<string> excludedPaths = new() {
"/admin",
"/login",
"/account",
"/dashboard",
"/new-path-to-exclude" // Add your paths
};
Enhancing Sitemap Content
Dynamic Priority
// Dynamic priority calculation
await _sitemapService.AddAsync(new SitemapEntry
{
Url = fullUrl,
LastModified = DateTime.UtcNow,
ChangeFrequency = "weekly",
Priority = CalculatePriority(fullUrl) // Custom logic
});
Adding Manual Triggers
[HttpPost]
public async Task<IActionResult> GenerateNow()
{
var job = new CrawlAndGenerateSitemapJob(...);
job.Execute();
return RedirectToAction(nameof(Index));
}
Multi-Language Support
// In CrawlAsync method
if (urlContainsLanguageParameter(fullUrl))
{
// Handle language-specific URL
// Add hreflang tags
}
Monitoring & Reporting
public class CrawlStats {
public int TotalPages { get; set; }
public int NewUrlsAdded { get; set; }
public DateTime LastRun { get; set; }
}
Usage Instructions
Action | Instructions |
---|---|
Enable Auto-Generation | Set SeoSettings.GenerateAutoSitemap to true and configure AppSettings:BaseUrl |
Manual Generation | Manual trigger or wait for scheduled execution |
Viewing Results | Access generated sitemap at /sitemap.xml |
Admin Interface | View crawled URLs and manage settings through admin UI |
Best Practices
Schedule Frequency
- Dynamic sites: Daily or weekly
- Static sites: Monthly
- E-commerce: Consider hourly for inventory
Performance
- Schedule during low-traffic periods
- Add delays between requests for large sites
- Monitor memory usage
- Consider distributed crawling
SEO Recommendations
- Ensure important pages are reachable
- Verify excluded paths
- Check sitemap completeness
- Submit to search consoles
Troubleshooting
Issue | Solution |
---|---|
Missing Pages |
|
Sitemap Not Updating |
|
Performance Issues |
|
System Summary
This system provides a flexible foundation for automated sitemap generation that can be customized to meet specific website requirements while following SEO best practices.
Settings
UpdatedCentralized configuration system for managing application settings
System Overview
Note
This system provides a centralized way to manage application settings through a web interface with role-based access control.
Configuration
- Key-value storage
- Dynamic loading
- Type-safe access
- Cache integration
Management
- Admin web interface
- Category organization
Key Components
AppSettingsService
Core Operations
- Load settings by type
- Save settings changes
- Cache management
Key Features
SettingsController
Core Actions
- Index - List all settings
- Details/Edit - View & Update settings
Example: Get Settings
[HttpGet("branding")]
public IActionResult Branding()
{
var model = _settingsService
.LoadSettings<BrandingSettings>();
return View(model);
}
Example: Save Settings
[HttpPost("branding")]
public IActionResult Branding(
BrandingSettings model)
{
_settingsService.SaveSettings(model);
_cache.Refresh();
return RedirectToAction(nameof(Branding));
}
SettingsBase
Example Implementation
public class BrandingSettings : SettingsBase
{
public string SiteName { get; set; }
public string LogoUrl { get; set; }
public string PrimaryColor { get; set; }
// Additional properties...
}
How It Works
Application requests settings through AppSettingsService
Service checks cache, then database, returns typed settings
Changes made through UI are validated and saved
Cache is invalidated and settings are reloaded on next request
Database Structure
CREATE TABLE AppSettings (
Id INT PRIMARY KEY,
Name NVARCHAR(255) NOT NULL,
Value NVARCHAR(MAX) NOT NULL
);
Extending the Functionality
Adding New Settings
Create Settings Class
public class NotificationSettings : SettingsBase
{
public bool EnableEmail { get; set; }
public string AdminEmail { get; set; }
public int MaxNotifications { get; set; }
// Additional properties
}
Settings UI
@model BrandingSettings
<form method="post">
<div class="form-group">
<label asp-for="SiteName"></label>
<input asp-for="SiteName" class="form-control" />
</div>
<!-- Additional fields -->
<button type="submit" class="btn btn-primary">Save</button>
</form>
Validation
public class BrandingSettings : SettingsBase
{
[Required]
[StringLength(100)]
public string SiteName { get; set; }
[Url]
public string LogoUrl { get; set; }
[RegularExpression("^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$")]
public string PrimaryColor { get; set; }
}
Audit Logging
public async Task SaveSettingsAsync<T>(T settings)
where T : SettingsBase
{
var oldSettings = await LoadSettingsAsync<T>();
settings.UpdatedAt = DateTime.UtcNow;
settings.UpdatedBy = _userService.GetCurrentUserId();
// Log changes
_auditLogger.LogChange(
typeof(T).Name,
oldSettings,
settings
);
// Save to database
await _repository.SaveAsync(settings);
}
Usage Instructions
Action | Instructions |
---|---|
Access Settings | Use _settingsService.LoadSettings<T>() in your application code |
Modify Settings | Use admin UI or call _settingsService.SaveSettings<T>() |
Add New Category | Create new Settings class and implement UI |
Best Practices
Organization
- Group related settings: Keep similar settings together
- Use clear names: Self-documenting property names
- Default values: Provide sensible defaults
Security
- Encrypt sensitive data
- Implement proper access controls
- Validate all inputs
Performance
- Cache settings appropriately
- Batch related updates
- Minimize database calls
- Consider distributed caching
System Summary
This settings module provides a robust, secure foundation for managing all application configuration and role-based access control.
Stripe Payment Gateway Integration
UpdatedSeamlessly integrate Stripe as a payment gateway to accept credit card payments and manage subscriptions.
Stripe Features
- Secure credit card processing
- Recurring subscription billing
- PCI compliant payment handling
- Support for multiple currencies
- Webhook integration for real-time updates
Security Features
- Credentials encrypted at rest
- Token-based payment processing
- No sensitive data stored on your servers
- Secure API communication
- Automatic PCI compliance
- Two-factor authentication support
Stripe Setup Guide
Before You Begin
You'll need an active Stripe account. Create one at stripe.com if you don't have one already.
Configuration Steps
Navigate to Payment Gateways
Go to Settings → Payment Gateways
in the admin panel
Change default Payment Gateway
Click action and select "Default"
Enter Credentials
Copy your API keys etc. from Stripe Dashboard and paste them on configuration form.
Save Configuration
Click Save to activate your Stripe integration
Required Stripe Credentials
Field | Description | Where to Find |
---|---|---|
Publishable Key |
Used for client-side operations | Stripe Dashboard → Developers → API Keys |
Secret Key |
Used for server-side operations | Stripe Dashboard → Developers → API Keys |
Webhook Secret |
Verifies webhook requests from Stripe | Stripe Dashboard → Developers → Webhooks |
Customer Portal Url |
A secure link provided by Stripe that allows customers to view and manage their subscriptions, billing details, and payment methods directly. |
Webhook Configuration
To receive real-time payment events from Stripe:
Endpoint URL: https://yourdomain.com/webhook/stripe
Events to listen for:
- checkout.session.completed
- checkout.session.expired
- customer.subscription.updated
- customer.subscription.deleted
- invoice.payment_failed
Important
Webhooks are essential for subscription management. Without proper webhook setup, subscription statuses may not update correctly.
Testing Your Integration
Test Mode
Use Stripe's test mode to verify your integration without processing real payments. Toggle between live and test mode in the payment gateway configuration.
Test Cards
Use these test card numbers:
4242 4242 4242 4242
- Successful payment4000 0000 0000 0002
- Failed payment5555 5555 5555 4444
- Mastercard (success)
Troubleshooting
Verify your API keys are correct and in the right mode (test/live). Check your server logs for any Stripe API errors.
Ensure your webhook endpoint is accessible from the internet and the secret key matches what's in your Stripe dashboard.
Check that all required webhook events are enabled and your webhook handler is processing them correctly.
Best Practices
- Always use HTTPS for your payment pages and webhook endpoints
- Regularly rotate your API keys and webhook secrets
- Monitor your Stripe dashboard for failed payments and disputes
- Implement proper error handling for payment failures
- Keep your Stripe SDK updated to the latest version
Paddle Payment Gateway Integration
UpdatedIntegrate Paddle as a payment gateway to accept payments and manage subscriptions with built-in tax compliance and global payment methods.
Paddle Features
- Unified payments and subscriptions
- Global payment methods support
- Sandbox environment for testing
- Webhook integration for real-time updates
Security Features
- API key authentication
- Sandbox and production environments
- Webhook signature verification
- PCI compliant payment handling
- Role-based access control
Paddle Setup Guide
Before You Begin
You'll need an active Paddle account. Create one at paddle.com if you don't have one already.
Configuration Steps
Navigate to Payment Gateways
Go to Settings → Payment Gateways
in the admin panel
Change default Payment Gateway
Click action and select "Default"
Enter Credentials
Copy your API keys from Paddle Dashboard and paste them on configuration form
Save Configuration
Click Save to activate your Paddle integration
Required Paddle Credentials
Field | Description | Where to Find |
---|---|---|
API Key |
Used for server-side API calls | Paddle Dashboard → Authentication → API Keys |
Client Token |
Used for client-side operations | Paddle Dashboard → Authentication → Client Tokens |
Success Url |
Used to redirect the user once payment is successful | |
Error Url |
Used to redirect the user once payment is failed | |
Customer Portal Url |
A secure link provided by Paddle that allows customers to view and manage their subscriptions, billing details, and payment methods directly. | |
Sandbox Mode |
Toggle between test and production environments | Configuration setting in admin UI |
Webhook Configuration
To receive real-time payment events from Paddle:
Endpoint URL: https://yourdomain.com/webhook/paddle
Events to listen for:
- subscription.created
- subscription.updated
- subscription.cancelled
- transaction.completed
- transaction.paid
Important
Webhooks are essential for subscription management. Without proper webhook setup, subscription statuses may not update correctly.
Testing Your Integration
Sandbox Mode
Use Paddle's sandbox environment to test your integration without processing real payments. Toggle sandbox mode in the payment gateway configuration.
Test Cards
Use these test card numbers in sandbox mode:
4242 4242 4242 4242
- Successful payment4000 0000 0000 0002
- Failed payment5555 5555 5555 4444
- Mastercard (success)
Troubleshooting
Verify your API key is correct and has the proper permissions. Ensure you're using the correct base URL (sandbox vs production).
Check that your webhook endpoint is publicly accessible and returns a 200 status code. Verify the webhook URL is correctly configured in Paddle Dashboard.
Ensure all required webhook events are enabled and your webhook handler is processing them correctly. Check your server logs for any processing errors.
Best Practices
- Always use HTTPS for your payment pages and webhook endpoints
- Regularly rotate your API keys
- Implement proper error handling for payment failures
- Test your integration thoroughly in sandbox mode before going live
- Monitor your Paddle dashboard for failed payments and disputes
Google OAuth Integration
UpdatedImplement secure authentication with Google OAuth 2.0, allowing users to sign in with their Google accounts.
OAuth Features
- Secure Google account authentication
- Configurable through admin UI
Google OAuth Setup Guide
Before You Begin
You'll need to create a project in the Google Cloud Console and configure OAuth credentials.
Admin UI Configuration
Field | Description | Where to Find |
---|---|---|
Client ID |
Google OAuth client identifier | Google Cloud Console → APIs & Services → Credentials |
Client Secret |
Google OAuth client secret (stored encrypted) | Google Cloud Console → APIs & Services → Credentials |
Configuration Steps:
- Navigate to
Admin → Settings → Authentication
- Click on "Google OAuth Configuration"
- Enter your Google Client ID and Client Secret
- Save the configuration
Testing Your Integration
Test Mode
Use Google's test mode to verify your integration without affecting real users. You can configure test users in the Google Cloud Console under OAuth consent screen.
Test Accounts
For testing purposes:
- Use any Google account you control for basic testing
- For restricted scopes, add test users in Google Cloud Console
- Verify different scenarios (new users vs returning users)
Troubleshooting
Verify your Client ID and Client Secret are correctly entered in the admin UI and match what's in your Google Cloud Console. Ensure the Client Secret hasn't expired.
Ensure the authorized redirect URIs in Google Cloud Console exactly match your domain and the standard /signin-google
endpoint.
Best Practices
- Always use HTTPS for your authentication endpoints
- Request only the scopes your application needs
- Regularly review authorized applications in your Google Cloud Console
- Implement proper session management and logout functionality
- Monitor your Google Cloud Console for any security alerts
Google reCAPTCHA Integration
UpdatedIntegrate Google reCAPTCHA to protect your application from spam and automated submissions on login, registration, and other sensitive forms.
reCAPTCHA Features
- Protects against spam and automated abuse
- Simple "I'm not a robot" checkbox
- Invisible reCAPTCHA options available
- Detailed analytics in Google admin console
Security Features
- Server-side token validation
- Configurable for specific forms
- Conditional rendering based on settings
- Graceful degradation if reCAPTCHA fails to load
reCAPTCHA Setup Guide
Before You Begin
You'll need to register your site at Google reCAPTCHA Admin to obtain your site key and secret key.
Configuration Steps
Register Your Site
Go to reCAPTCHA Admin and register your site
Configure Security Settings
Navigate to Settings → Security
in the admin panel
Enter reCAPTCHA Keys
Add your site key and secret key from Google reCAPTCHA
Enable for Specific Forms
Toggle which forms should use reCAPTCHA (login, register, etc.)
Required reCAPTCHA Credentials
Field | Description | Where to Find |
---|---|---|
Site Key |
Used for client-side widget integration | Google reCAPTCHA Admin → Your Sites |
Secret Key |
Used for server-side token validation | Google reCAPTCHA Admin → Your Sites |
Enable for Forms |
Toggle which forms require reCAPTCHA | Security Settings in admin UI |
Implementation Details
Server-Side Validation
public class ValidateRecaptchaAttribute : TypeFilterAttribute
{
public ValidateRecaptchaAttribute() : base(typeof(ValidateRecaptchaFilter))
{
}
private class ValidateRecaptchaFilter : IAsyncActionFilter
{
// Validates reCAPTCHA token with Google's API
// Checks if reCAPTCHA is enabled for the specific action
// Returns appropriate error responses if validation fails
}
}
Apply this attribute to any action that requires reCAPTCHA validation:
[HttpPost]
[ValidateRecaptcha]
public async Task<IActionResult> Login(LoginModel model)
{
// Your login logic
}
Client-Side Implementation
Load reCAPTCHA Script
@section Scripts {
<script src="https://www.google.com/recaptcha/api.js" async defer></script>
}
Add reCAPTCHA Widget
if (ViewBag.CaptchEnabled)
{
<div class="g-recaptcha" data-sitekey="@_securitySettings.CaptchaPublicKey"></div>
}
Validate Before Submission
if (isCaptchaEnabled) {
if (typeof grecaptcha === 'undefined') {
showToast('reCAPTCHA failed to load. Please refresh the page.', 'error');
return;
}
var token = grecaptcha.getResponse();
if (!token) {
showToast('Please verify you are a human.', 'error');
return;
}
}
Troubleshooting
Verify the site key is correct and the reCAPTCHA script is properly loaded. Check browser console for errors. Ensure the widget is only rendered when ViewBag.CaptchEnabled
is true.
Check your secret key is correct. Verify your server can reach Google's reCAPTCHA API (no firewall restrictions). Ensure you're passing the correct token from the client-side.
Check your security settings to ensure reCAPTCHA is enabled for the specific form type (login, register, etc.). Verify the ValidateRecaptcha
attribute is applied to the action.
Best Practices
- Always validate reCAPTCHA tokens server-side - client-side validation alone is not secure
- Monitor your reCAPTCHA analytics in the Google admin console
- Consider using reCAPTCHA v3 for less intrusive protection
- Provide clear error messages when reCAPTCHA validation fails
- Regularly review your security settings and adjust reCAPTCHA sensitivity as needed
Framework Configuration
CoreOur application uses separate Tailwind configurations for admin and public areas with customized DaisyUI themes.
Admin Configuration
// tailwind.admin.config.js
module.exports = {
content: [
'./Areas/Admin/Views/**/*.cshtml',
],
theme: {
extend: {},
}
};
Public Configuration
// tailwind.public.js
module.exports = {
content: [
'./Views/**/*.cshtml',
'./Pages/**/*.cshtml',
'./wwwroot/**/*.html',
],
theme: {
extend: {},
},
plugins: [
require('daisyui')
]
}
Theme Management
CustomizableThemes can be customized by modifying the configuration files or extended with custom CSS.
Theme Customization Tips
Color Contrast
Ensure text remains readable with sufficient contrast against backgrounds.
Component States
Define hover, focus, and active states for interactive elements.
Responsive Design
Test themes at different breakpoints for consistency.
Accessibility
Check color contrast ratios meet WCAG standards.
Dark/Light Mode
AutomaticThe application supports system preference detection with manual override capability.
Implementation
Theme Switcher Function
// Set theme and save preference
function setTheme(theme) {
document.documentElement.setAttribute('data-theme', theme);
localStorage.setItem('theme', theme);
}
// Initialize on load
document.addEventListener('DOMContentLoaded', () => {
const savedTheme = localStorage.getItem('theme') || 'dark';
document.documentElement.setAttribute('data-theme', savedTheme);
});
Toggle Component
<!-- Theme toggle button -->
<label class="swap swap-rotate">
<input type="checkbox"
onclick="setTheme(this.checked ? 'dark' : 'light')" />
<!-- Sun icon -->
<svg class="swap-on w-6 h-6" ... ></svg>
<!-- Moon icon -->
<svg class="swap-off w-6 h-6" ... ></svg>
</label>
Partial Views
TemplatesReusable partial views with consistent styling that adapt to the current theme.
Hero Section Variants
_hero_00.cshtml
to _hero_09.cshtml
Views/Home/Partials/_hero_00.cshtml
Select a hero variant to preview. Customize any version by editing its partial file.
_hero_00.cshtml

_hero_01.cshtml

_hero_02.cshtml

_hero_03.cshtml

_hero_04.cshtml

_hero_05.cshtml

_hero_06.cshtml

Customization Options
All hero variants share these customization points:
- Edit text content directly in each partial file
- Modify colors via Tailwind classes like
from-primary
- Adjust spacing with padding/margin utilities
- Change button styles in the component markup
Tech Stack Section
Views/Home/Partials/_technology_stack.cshtml
Select a technology stack variant to preview. Customize any version by editing its partial file.
_technology_stack00.cshtml

_technology_stack01.cshtml

Customization Options
All hero variants share these customization points:
- Edit text content directly in each partial file
- Modify colors via Tailwind classes like
from-primary
- Adjust background overlay
Features Section
Views/Home/Partials/_feature00.cshtml
Select a feature variant to preview. Customize any version by editing its partial file.
_feature00.cshtml

_feature01.cshtml

_feature02.cshtml

_feature03.cshtml

_feature04.cshtml

Customization Options
All hero variants share these customization points:
- Edit text content directly in each partial file
- Modify colors via Tailwind classes like
from-primary
- Adjust background overlay
Pricing Section
Views/Home/Partials/_pricing00.cshtml
Select a pricing variant to preview. Customize any version by editing its partial file.
_pricing.cshtml

_pricing01.cshtml

_pricing02.cshtml

_pricing03.cshtml

Customization Options
All hero variants share these customization points:
- Edit text content directly in each partial file
- Modify colors via Tailwind classes like
from-primary
- Adjust background overlay
CTA Section
Views/Home/Partials/_cta.cshtml
Customization Options
As of now we only have one CTA:
- Edit text content directly in partial file mentioned at the path
FAQ Section
Views/Shared/Partials/_faq01.cshtml
Select a faq variant to preview. Customize any version by editing its partial file.
_faq01.cshtml

_faq02.cshtml

Customization Options
All faq variants share these customization points:
- Edit text content directly in each partial file
- Modify colors via Tailwind classes like
from-primary
- Adjust background overlay
Theming Best Practices
Consistency
- Use the same color palette across all components
- Maintain consistent spacing and typography
- Reuse partial views for common UI elements
Performance
- Purge unused CSS in production builds
- Use utility classes instead of custom CSS when possible
- Optimize images and assets used in themes