Reports & Data Export Guide
Last Updated: 2026-01-18 Status: Enhanced with Query Optimization, Progress Tracking & Export Architecture Plan Reference: 051-reports-enhancement.md, 083-reports-improvement.md, 143-report-service-architecture.md
Overview
The Reports system provides comprehensive reporting capabilities for analyzing business data. Features include:
- 11 Built-in Report Types - Financial, Operational, and Activity reports
- Custom Report Builder - Create user-defined reports with dynamic queries
- 13 Chart Types - Visual data representation with Chart.js integration
- Report Scheduling - Automated report generation with flexible frequencies
- Report Sharing - Token-based access with passwords and permissions
- Multiple Export Formats - CSV, PDF, Excel exports
Table of Contents
- Accessing Reports
- Built-in Report Types
- Custom Reports
- Chart Visualization
- Export Formats
- Report Scheduling
- Report Sharing
- Technical Architecture
- API Reference
- Related Features
Accessing Reports
Navigation
| Access Point | Location | URL | Role |
|---|---|---|---|
| Reports Dashboard | Admin sidebar | /admin/reports | Admin |
| Report Types | Registry-based | /admin/reports/type/{type} | Admin |
| Custom Reports | Reports menu | /admin/custom-reports | Admin |
| Report Schedules | Reports menu | /admin/report-schedules | Admin |
| Report History | Reports menu | /admin/reports/history | Admin |
Permissions
| Action | Admin | Client User |
|---|---|---|
| View all reports | Yes | No |
| Generate reports | Yes | No |
| Create custom reports | Yes | No |
| Schedule reports | Yes | No |
| Share reports | Yes | Limited |
| Export data | Yes | Limited |
Built-in Report Types
Reports are organized into three categories, managed by the ReportRegistry.
Financial Reports
| Report | Type Key | Description | Key Metrics |
|---|---|---|---|
| Revenue Report | revenue | Track revenue over time | Total revenue, period comparisons, client breakdown |
| Profitability Report | profitability | Profit margin analysis | Gross profit, expenses, net margin |
| Cash Flow Report | cash_flow | Payment inflows/outflows | Cash in, cash out, net cash flow |
| Aging Report | aging | Receivables by age | Current, 30/60/90+ days overdue |
| Tax Summary Report | tax_summary | Tax collected/owed | Tax by rate, period, region |
Operational Reports
| Report | Type Key | Description | Key Metrics |
|---|---|---|---|
| Project Health | project_health | Project status overview | On-time %, budget variance, status breakdown |
| Resource Utilization | resource_utilization | Team capacity analysis | Billable hours, utilization %, availability |
| Time Tracking | time_tracking | Time entry analysis | Hours by project, client, user |
| Client Retention | client_retention | Retention metrics | Churn rate, LTV, retention by cohort |
Activity Reports
| Report | Type Key | Description | Key Metrics |
|---|---|---|---|
| User Activity | user_activity | Actions by user | Logins, edits, file activity |
| Client Engagement | client_engagement | Client interaction metrics | Portal visits, file downloads, response times |
Generating a Report
- Navigate to Admin → Reports
- Select report type from the dashboard or dropdown
- Configure parameters:
- Date Range: Preset or custom dates
- Filters: Client, status, user filters
- Grouping: By client, project, period
- Chart Type: Optional visualization
- Click "Preview" to see data on screen
- Click "Generate" to create downloadable report
Custom Reports
Custom reports allow users to build their own reports by selecting data sources, columns, filters, and aggregations.
Data Sources
| Source | Description | Available Columns |
|---|---|---|
invoices | Invoice data | invoice_number, total, tax, status, issue_date, due_date, paid_at |
projects | Project data | name, status, budget, start_date, end_date, created_at |
clients | Client data | company_name, email, phone, address, is_active, created_at |
time_entries | Time tracking | description, duration, date, billable, rate, user_id |
Creating a Custom Report
- Navigate to Admin → Custom Reports
- Click "Create Report"
- Configure:
- Name: Report identifier
- Data Source: Select from available sources
- Columns: Choose which columns to include
- Filters: Add filter conditions
- Grouping: Optional group by column
- Aggregations: Sum, count, average functions
- Sorting: Order by column
- Click "Save Report"
Filter Operators
| Operator | Description | Example |
|---|---|---|
= | Equals | status = 'active' |
!= | Not equals | status != 'draft' |
> | Greater than | total > 1000 |
>= | Greater than or equal | total >= 500 |
< | Less than | total < 10000 |
<= | Less than or equal | total <= 5000 |
like | Contains pattern | name like '%Inc%' |
not_like | Does not contain | name not_like '%Test%' |
starts_with | Starts with string | name starts with 'Acme' |
ends_with | Ends with string | email ends with '.com' |
in | In array of values | status in ['active', 'completed'] |
not_in | Not in array | status not_in ['draft', 'archived'] |
between | Between two values | created_at between ['2024-01-01', '2024-12-31'] |
is_null | Is null | paid_at is_null |
is_not_null | Is not null | paid_at is_not_null |
Aggregation Functions
| Function | Description | Example |
|---|---|---|
sum | Sum of values | Sum of invoice totals |
count | Count of records | Number of invoices |
avg | Average value | Average invoice amount |
min | Minimum value | Lowest invoice total |
max | Maximum value | Highest invoice total |
Custom Report Actions
| Action | Description |
|---|---|
| View | Execute and display results |
| Edit | Modify report configuration |
| Duplicate | Create copy with "(Copy)" suffix |
| Export | Download as CSV, PDF, or Excel |
| Share | Create shareable link |
| Delete | Remove report |
Chart Visualization
Reports support 13 chart types via the ChartBuilder service for visual data representation.
Available Chart Types
| Type | Key | Description | Best For |
|---|---|---|---|
| Bar Chart | bar | Vertical bar chart | Comparing categories |
| Line Chart | line | Line graph | Trends over time |
| Pie Chart | pie | Circular pie chart | Proportions |
| Doughnut Chart | doughnut | Pie with center hole | Proportions with space for label |
| Area Chart | area | Filled line chart | Volume over time |
| Stacked Bar | stacked_bar | Stacked vertical bars | Composition comparison |
| Horizontal Bar | horizontal_bar | Horizontal bar chart | Long category names |
| Combo Chart | combo | Bar + line combined | Multiple metrics |
| Gauge Chart | gauge | Speedometer style | Progress/KPIs |
| Heatmap | heatmap | Color-coded grid | Pattern identification |
| Treemap | treemap | Hierarchical rectangles | Hierarchical data |
| Scatter Plot | scatter | Point distribution | Correlation analysis |
| Radar Chart | radar | Spider/radar chart | Multi-variable comparison |
Adding Charts to Reports
- Generate or preview a report
- Select "Chart Type" from the options
- Configure chart-specific options:
- Title
- Legend position
- Color scheme
- Chart renders with report data
Export Formats
CSV Export
- Comma-separated values
- Compatible with Excel, Google Sheets
- Best for data analysis
- All selected columns included
Excel Export
- Native .xlsx format
- Formatted headers
- Multiple sheets for complex reports
- Charts included where applicable
PDF Export
- Print-ready layout
- Company branding
- Headers and footers
- Page numbers
- Best for sharing/archiving
Export Endpoint
GET /admin/reports/generated/{id}/download/{format}
Supported formats: csv, pdf, excel
Export Architecture
The export system uses a strategy pattern with dedicated exporter classes:
app/Services/Reports/Exporters/
├── ReportExporterInterface.php # Exporter contract
├── CsvReportExporter.php # CSV with UTF-8 BOM
├── ExcelReportExporter.php # XLSX via maatwebsite/excel
├── PdfReportExporter.php # PDF via DomPDF
└── ReportExportService.php # Orchestrator
ReportExportService Usage:
use App\Services\Reports\Exporters\ReportExportService;
$exportService = app(ReportExportService::class);
// Check available formats
$formats = $exportService->getAvailableFormats();
// ['csv' => [...], 'xlsx' => [...], 'pdf' => [...]]
// Export a report (must implement ExportableInterface)
$response = $exportService->export($report, 'xlsx');
ExportableInterface Contract:
All exportable reports implement this interface:
interface ExportableInterface
{
public function toExportArray(): array; // Data rows
public function getExportHeaders(): array; // Column headers
public function getExportFilename(): string; // File name
public function getExportMetadata(): array; // Title, description, etc.
}
Adding Custom Export Format:
// 1. Create exporter implementing ReportExporterInterface
class JsonReportExporter implements ReportExporterInterface
{
public function getFormat(): string { return 'json'; }
public function getMimeType(): string { return 'application/json'; }
public function getFileExtension(): string { return 'json'; }
public function export(ExportableInterface $report): Response { ... }
}
// 2. Register in ReportExportService constructor
$this->registerExporter(app(JsonReportExporter::class));
Report Scheduling
Schedule automated report generation with flexible frequency options.
Creating a Schedule
- Navigate to Admin → Report Schedules
- Click "Create Schedule"
- Configure:
- Name: Schedule identifier
- Report Type: Select built-in report type
- Parameters: Report-specific parameters
- Frequency: Daily, Weekly, Monthly, Quarterly, or Custom
- Recipients: Email addresses for delivery
- Format: CSV, PDF, or Excel
- Click "Create"
Frequency Options
| Frequency | Schedule Time | Description |
|---|---|---|
| Daily | Configurable time | Runs every day |
| Weekly | Day of week + time | Runs once per week |
| Monthly | Day of month + time | Runs once per month |
| Quarterly | Month + day + time | Runs once per quarter |
| Custom | Cron expression | Full cron flexibility |
Custom Cron Expressions
For advanced scheduling, use cron expressions:
# Every Monday at 9 AM
0 9 * * 1
# First day of each month at midnight
0 0 1 * *
# Every weekday at 6 PM
0 18 * * 1-5
Schedule Actions
| Action | Description |
|---|---|
| Toggle | Enable/disable schedule |
| Run Now | Execute immediately |
| Preview | Preview next run data |
| Edit | Modify schedule |
| Delete | Remove schedule |
Managing Recipients
Schedules support multiple recipients:
- User-based: Select portal users by ID
- Email-based: Enter email addresses directly
- Mixed: Combine both methods
Report Sharing
Share reports with external users via secure token-based links.
Creating a Share Link
- Navigate to report (generated, custom, or scheduled)
- Click "Share" button
- Configure:
- Expires At: Optional expiration date
- Password: Optional password protection
- Max Views: Optional view limit
- Permissions: View-only or download enabled
- Copy generated link
Share Options
| Option | Description | Default |
|---|---|---|
expires_at | Expiration date/time | Never |
password | Access password | None |
max_views | Maximum view count | Unlimited |
max_downloads | Maximum download count | Unlimited |
permissions | Array of permissions | ['view'] |
Available Permissions
| Permission | Description |
|---|---|
view | View report data |
download | Download exports |
edit | Modify report |
Public Access URL
GET /r/{token}
- No authentication required
- Token validated against share record
- Password prompted if configured
- View/download counts tracked
Revoking Access
- Navigate to Admin → Shared Reports
- Find the share record
- Click "Revoke" to disable
Technical Architecture
Models
ReportSchedule
// app/Models/ReportSchedule.php
class ReportSchedule extends Model
{
protected $fillable = [
'name', 'report_type', 'parameters', 'frequency',
'schedule_time', 'schedule_day', 'cron_expression',
'recipients', 'format', 'is_active', 'last_run_at',
'next_run_at', 'created_by',
];
protected $casts = [
'parameters' => 'array',
'recipients' => 'array',
'is_active' => 'boolean',
'last_run_at' => 'datetime',
'next_run_at' => 'datetime',
];
// Key methods
public function calculateNextRunAt(): Carbon;
public function markAsRun(): void;
public function getAllRecipientEmails(): array;
public static function getFrequencies(): array;
}
CustomReport
// app/Models/CustomReport.php
class CustomReport extends Model
{
protected $fillable = [
'name', 'description', 'data_source', 'columns',
'filters', 'group_by', 'order_by', 'order_direction',
'aggregations', 'chart_config', 'is_public', 'created_by',
];
protected $casts = [
'columns' => 'array',
'filters' => 'array',
'aggregations' => 'array',
'chart_config' => 'array',
'is_public' => 'boolean',
];
// Key methods
public static function getAvailableDataSources(): array;
public function scopeAccessibleBy($query, User $user);
}
SharedReport
// app/Models/SharedReport.php
class SharedReport extends Model
{
protected $fillable = [
'reportable_type', 'reportable_id', 'token',
'expires_at', 'password', 'max_views', 'max_downloads',
'view_count', 'download_count', 'permissions',
'created_by',
];
// Key methods
public static function generateToken(): string;
public function canView(): bool;
public function canDownload(): bool;
public function recordView(): void;
}
Services
ReportRegistry
Central registry managing all built-in report types:
// app/Services/Reports/ReportRegistry.php
class ReportRegistry
{
public function getAvailable(): array; // All reports with metadata
public function getByCategory(): array; // Reports grouped by category
public function has(string $type): bool; // Check if type exists
public function get(string $type): string; // Get report class
public function run(string $type, array $params): array; // Execute report
public function register(string $type, string $class): void; // Add custom
}
CustomReportBuilder
Builds and executes custom report queries:
// app/Services/Reports/CustomReportBuilder.php
class CustomReportBuilder
{
public function build(CustomReport $report): array;
protected function buildQuery(CustomReport $report): Builder;
protected function applyFilter(Builder $query, array $filter): Builder;
protected function applyGrouping(Builder $query, CustomReport $report): Builder;
protected function applyAggregations(Builder $query, array $aggregations): void;
}
ChartBuilder
Transforms data into Chart.js configurations:
// app/Services/Reports/ChartBuilder.php
class ChartBuilder
{
public function getChartTypes(): array; // Available types
public function buildChart(string $type, array $data, array $options): array;
}
QueryOptimizer (New)
Analyzes and optimizes report queries for performance:
// app/Services/Reports/QueryOptimizer.php
class QueryOptimizer
{
public function analyze(CustomReport $report): array; // Analyze query complexity
public function optimize(Builder $query): Builder; // Apply optimizations
public function getCacheKey(CustomReport $report): string; // Generate cache key
public function cacheResult(string $key, array $data, int $ttl): void;
public function getCachedResult(string $key): ?array;
}
Query Analysis Features:
- Estimates execution time based on data source size
- Recommends async processing for large datasets
- Suggests index improvements
- Provides caching recommendations
- Warns about potentially slow operations
Report Progress Tracking
Large reports are processed asynchronously with real-time progress tracking:
// app/Jobs/GenerateReportJob.php
class GenerateReportJob implements ShouldQueue
{
public function __construct(
public readonly CustomReport $report,
public readonly string $jobId,
public readonly ?int $userId = null
) {}
}
Progress States:
queued- Job is waiting in queuerunning- Job is executingcompleted- Job finished successfullyfailed- Job encountered an error
Polling Endpoint:
GET /admin/custom-reports/progress/{jobId}
Returns:
{
"status": "running",
"progress": 45,
"message": "Processing records..."
}
Report Interface
All report types implement this contract:
// app/Services/Reports/Contracts/ReportInterface.php
interface ReportInterface
{
public static function getType(): string;
public static function getName(): string;
public static function getDescription(): string;
public static function getCategory(): string;
public static function getParameters(): array;
public function generate(array $parameters = []): array;
public function getDefaultChartConfig(): ?array;
}
Base Report Class
Abstract base with common functionality, now implements ExportableInterface:
// app/Services/Reports/BaseReport.php
abstract class BaseReport implements ReportInterface, ExportableInterface
{
protected array $generatedData = [];
protected array $generatedSummary = [];
public function generate(array $parameters = []): array
{
$normalized = $this->normalizeParameters($parameters);
$this->generatedData = $this->fetchData($normalized);
$this->generatedSummary = $this->calculateSummary($this->generatedData, $normalized);
return [
'data' => $this->generatedData,
'summary' => $this->generatedSummary,
'metadata' => [...],
];
}
// ExportableInterface implementation (overridable)
public function toExportArray(): array { return $this->generatedData; }
public function getExportHeaders(): array { /* auto-detect from data */ }
public function getExportFilename(): string { return static::getType() . '-' . now()->format('Y-m-d'); }
public function getExportMetadata(): array { /* title, description, etc. */ }
// Helper methods
protected function getStartDate(array $params): Carbon;
protected function getEndDate(array $params): Carbon;
protected function formatCurrency(float $amount): string;
protected function calculatePercentageChange(float $old, float $new): float;
}
API Reference
Report Types
GET /admin/reports/types # List all report types
GET /admin/reports/chart-types # List chart types
GET /admin/reports/type/{type} # Show report form
POST /admin/reports/preview # Preview report data
POST /admin/reports/generate # Generate and store report
GET /admin/reports/history # View report history
Custom Reports
GET /admin/custom-reports # List custom reports
GET /admin/custom-reports/create # Create form
POST /admin/custom-reports # Store new report
GET /admin/custom-reports/{id} # View/execute report
GET /admin/custom-reports/{id}/edit # Edit form
PUT /admin/custom-reports/{id} # Update report
DELETE /admin/custom-reports/{id} # Delete report
POST /admin/custom-reports/preview # Preview query results
POST /admin/custom-reports/{id}/duplicate # Duplicate report
GET /admin/custom-reports/fields/{source} # Get data source fields
GET /admin/custom-reports/{id}/export/{format} # Export results
Report Schedules
GET /admin/report-schedules # List schedules
GET /admin/report-schedules/create # Create form
POST /admin/report-schedules # Store schedule
GET /admin/report-schedules/{id} # View schedule
GET /admin/report-schedules/{id}/edit # Edit form
PUT /admin/report-schedules/{id} # Update schedule
DELETE /admin/report-schedules/{id} # Delete schedule
POST /admin/report-schedules/{id}/toggle # Toggle active status
POST /admin/report-schedules/{id}/run-now # Run immediately
POST /admin/report-schedules/{id}/preview # Preview next run
GET /admin/report-schedules/due # Get schedules due to run
Shared Reports
POST /admin/reports/share/generated/{id} # Share generated report
POST /admin/reports/share/custom/{id} # Share custom report
POST /admin/reports/share/schedule/{id} # Share scheduled report
PUT /admin/shared-reports/{id} # Update share settings
DELETE /admin/shared-reports/{id} # Revoke share
# Public access (no auth required)
GET /r/{token} # View shared report
GET /r/{token}/download # Download shared report
Database Schema
Table: report_schedules
| Column | Type | Description |
|---|---|---|
id | bigint | Primary key |
name | varchar | Schedule name |
report_type | varchar | Report type key |
parameters | json | Report parameters |
frequency | varchar | daily/weekly/monthly/quarterly/custom |
schedule_time | time | Execution time |
schedule_day | integer | Day of week/month |
cron_expression | varchar | Custom cron (nullable) |
recipients | json | Email/user IDs |
format | varchar | csv/pdf/excel |
is_active | boolean | Enabled status |
last_run_at | timestamp | Last execution |
next_run_at | timestamp | Next execution |
created_by | bigint | Owner user ID |
created_at | timestamp | Created date |
updated_at | timestamp | Updated date |
Table: custom_reports
| Column | Type | Description |
|---|---|---|
id | bigint | Primary key |
name | varchar | Report name |
description | text | Optional description |
data_source | varchar | Data source key |
columns | json | Selected columns |
filters | json | Filter conditions |
group_by | varchar | Grouping column |
order_by | varchar | Sort column |
order_direction | varchar | asc/desc |
aggregations | json | Aggregation config |
chart_config | json | Chart configuration |
is_public | boolean | Public visibility |
created_by | bigint | Owner user ID |
created_at | timestamp | Created date |
updated_at | timestamp | Updated date |
Table: shared_reports
| Column | Type | Description |
|---|---|---|
id | bigint | Primary key |
reportable_type | varchar | Polymorphic type |
reportable_id | bigint | Polymorphic ID |
token | varchar(64) | Unique share token |
expires_at | timestamp | Expiration (nullable) |
password | varchar | Hashed password (nullable) |
max_views | integer | View limit (nullable) |
max_downloads | integer | Download limit (nullable) |
view_count | integer | Current views |
download_count | integer | Current downloads |
permissions | json | ['view', 'download', 'edit'] |
created_by | bigint | Creator user ID |
created_at | timestamp | Created date |
updated_at | timestamp | Updated date |
Table: generated_reports
| Column | Type | Description |
|---|---|---|
id | bigint | Primary key |
name | varchar | Report name |
report_type | varchar | Report type key |
parameters | json | Generation parameters |
result_data | json | Report results |
file_path | varchar | Stored file path |
format | varchar | Export format |
generated_by | bigint | Generator user ID |
created_at | timestamp | Generation date |
updated_at | timestamp | Updated date |
Related Features
Dependencies
| Feature | Relationship |
|---|---|
| Authorization | Admin access required |
| Background Jobs | Scheduled generation |
| Notifications | Email delivery |
Complementary Features
| Feature | Description |
|---|---|
| Analytics | Dashboard analytics |
| Search Filtering | Filter report data |
| PDF Generation | PDF exports |
Best Practices
For Users
- Use date ranges appropriate to report type
- Filter large reports to relevant data
- Schedule recurring reports instead of manual generation
- Use PDF for sharing, CSV for analysis
- Set expiration on shared links for security
For Developers
- Queue large exports for performance
- Cache report data where appropriate
- Limit date ranges to prevent timeouts
- Index commonly filtered columns
- Implement ReportInterface for new report types
Troubleshooting
| Issue | Solution |
|---|---|
| Report times out | Reduce date range or add filters |
| Export fails | Check disk space and permissions |
| Scheduled not running | Verify scheduler and queue worker |
| Empty results | Check filter parameters |
| Chart not rendering | Verify data format matches chart type |
| Share link expired | Create new share with extended expiry |
See Also
- Analytics - Business intelligence
- PDF Generation - PDF exports
- Background Jobs - Async processing