AshReports
A comprehensive, declarative reporting framework for the Ash ecosystem
AshReports provides a powerful DSL for defining reports with hierarchical band structures, chart generation, streaming data processing, multiple output formats (HTML, PDF, JSON, HEEX), and full internationalization support.
Quick Links
- π Feature Status Matrix - What's ready for production
- π Quick Start - Get started in 5 minutes
- π Documentation - Comprehensive guides
- π Security - Security policy and best practices
- πΊοΈ Roadmap - What's coming next
- π€ Contributing - How to contribute
What is AshReports?
AshReports is a declarative reporting framework built on the Ash Framework that allows you to define complex reports using a DSL, then generate them in multiple formats with full internationalization support.
Key Features
- π Declarative DSL - Define reports using Spark-powered DSL
- π Band-Based Layout - Report/page headers/footers, detail, group sections
- π Chart Generation - Bar, line, pie, area, scatter charts with Contex
- π Streaming Data - Memory-efficient processing via Ash.stream!
- π Internationalization - CLDR-based formatting for numbers, dates, currencies
- π Multiple Formats - HTML, PDF (Typst), JSON, HEEX/LiveView output
- β‘ LiveView Integration - Real-time interactive reports
- π Security Hardened - Safe against atom exhaustion attacks
Feature Status
Quick overview of what's production-ready:
| Feature | Status | Notes |
|---|---|---|
| Core DSL | β Production-Ready | 75 passing tests |
| Band System | β Production-Ready | Full hierarchy support |
| Chart Generation | β Production-Ready | SVG output via Contex |
| Streaming | β Production-Ready | Ash.stream! with keyset pagination |
| Data Loading | β Production-Ready | Ash query integration |
| Internationalization | β Production-Ready | CLDR formatting |
| HTML Renderer | β Production-Ready | Full HTML output support |
| PDF Renderer | β Production-Ready | Typst-based PDF generation |
| JSON Renderer | β Production-Ready | Structured data export |
| LiveView | β οΈ Partial | Basic integration working |
For detailed feature breakdown and roadmap, see IMPLEMENTATION_STATUS.md
Quick Start
Installation
Add ash_reports to your dependencies in mix.exs:
def deps do
[
{:ash_reports, "~> 0.1.0"}
]
endThen run:
mix deps.get
Define Your First Report
defmodule MyApp.Reports.SalesReport do
use Ash.Domain,
extensions: [AshReports.Domain]
reports do
report :monthly_sales do
title("Monthly Sales Report")
description("Sales report with totals")
driving_resource(MyApp.Sales.Order)
# Define parameters
parameter :start_date, :date do
required(true)
end
parameter :end_date, :date do
required(true)
end
# Define variable for totals
variable :grand_total do
type :sum
expression :total_amount
reset_on :report
end
# Define report header
band :report_header do
type :title
label :title do
text("Monthly Sales Report")
style(font_size: 24, font_weight: :bold)
end
end
# Define detail section
band :detail do
type :detail
field :order_id do
source :order_id
end
field :customer_name do
source :customer_name
end
field :order_date do
source :order_date
format :date
end
field :total_amount do
source :total_amount
format :currency
end
end
# Define report footer with totals
band :report_footer do
type :summary
label :total_label do
text("Grand Total:")
style(font_weight: :bold)
end
expression :grand_total_value do
expression :grand_total
format :currency
style(font_weight: :bold)
end
end
end
end
endGenerate the Report
# Generate HTML report
{:ok, result} = AshReports.generate(
MyApp.Reports.SalesReport,
:monthly_sales,
%{start_date: ~D[2024-01-01], end_date: ~D[2024-01-31]},
:html
)
html_content = result.content
# Generate PDF report
{:ok, result} = AshReports.generate(
MyApp.Reports.SalesReport,
:monthly_sales,
%{start_date: ~D[2024-01-01], end_date: ~D[2024-01-31]},
:pdf
)
pdf_content = result.content
# Generate JSON export
{:ok, result} = AshReports.generate(
MyApp.Reports.SalesReport,
:monthly_sales,
%{start_date: ~D[2024-01-01], end_date: ~D[2024-01-31]},
:json
)
json_content = result.contentDocumentation
User Guides
- Getting Started - Installation and first report
- Report Creation - Parameters, grouping, variables, formatting
- Graphs and Visualizations - Adding charts to reports
- Integration - Phoenix and LiveView integration
- Advanced Features - Formatting and current advanced capabilities
- ROADMAP.md - Planned features and development timeline
API Documentation
Generate API docs locally:
mix docs
open doc/index.html
Demo Application
For a complete working example with reports, charts, and a Phoenix LiveView interface, see the AshReportsDemo repository.
Advanced Features
Grouped Reports with Aggregations
report :sales_by_category do
title("Sales by Category")
driving_resource(MyApp.Sales.Order)
# Define group
group :by_category do
level 1
expression :category_name
sort :asc
end
# Define variable for category totals
variable :category_total do
type :sum
expression :amount
reset_on :group
reset_group 1
end
# Group header
band :group_header do
type :group_header
group_level(1)
field :category_name do
source :category_name
style(font_weight: :bold)
end
end
# Detail records
band :detail do
type :detail
field :order_id do
source :order_id
end
field :product_name do
source :product_name
end
field :amount do
source :amount
format :currency
end
end
# Group footer with subtotal
band :group_footer do
type :group_footer
group_level(1)
label :total_label do
text("Category Total:")
style(font_weight: :bold)
end
expression :category_total_value do
expression :category_total
format :currency
style(font_weight: :bold)
end
end
endBand Padding and Spacing
Control the spacing within bands using the padding option. This is particularly useful for indenting detail rows in grouped reports or adding vertical spacing to section headers.
report :sales_by_region do
title("Sales by Region")
driving_resource(MyApp.Sales.Order)
group :region do
level 1
expression :region_name
end
# Group header - no padding
band :group_header do
type :group_header
group_level(1)
field :region_name do
source :region_name
style(font_weight: :bold, font_size: 14)
end
end
# Detail records - indented 20pt from left
band :detail do
type :detail
padding left: "20pt" # Indent detail rows
field :order_id do
source :order_id
end
field :customer_name do
source :customer_name
end
field :amount do
source :amount
format :currency
end
end
# Group footer with subtotal - moderate indent
band :group_footer do
type :group_footer
group_level(1)
padding left: "10pt", top: "5pt" # Slight indent and top spacing
label :total_label do
text("Region Total:")
style(font_weight: :bold)
end
expression :region_total do
expression :region_total_var
format :currency
end
end
endPadding Options:
- Directional padding:
padding left: "20pt", right: "10pt", top: "5pt", bottom: "5pt" - Uniform padding:
padding "15pt"(applies to all sides) - Unspecified sides default to "5pt"
Common use cases:
- Indent detail rows under group headers
- Add vertical spacing between sections
- Create visual hierarchy in reports
Charts in Reports
Charts use a two-level architecture: define charts at the reports level, then reference them in bands.
defmodule MyApp.Reports do
use Ash.Domain,
extensions: [AshReports.Domain]
reports do
# Define reusable chart at reports level
bar_chart :sales_by_month do
data_source expr(aggregate_monthly_sales())
config do
width 800
height 400
title "Monthly Sales"
type :grouped
data_labels true
colours ["4285F4", "34A853", "FBBC04"]
end
end
# Use chart in report
report :sales_report do
title "Sales Report"
driving_resource MyApp.Sales.Order
bands do
band :analytics do
type :detail
elements do
# Reference the chart by name
bar_chart :sales_by_month
end
end
end
end
end
endStreaming Large Datasets
# AshReports has streaming infrastructure for large datasets
# using Ash.stream! with keyset pagination for memory efficiency
{:ok, result} = AshReports.generate(
MyApp.Reports.HugeReport,
:all_transactions, # Could be millions of records
%{},
:html
)
html_content = result.content
# Note: Streaming configuration DSL is planned.
# See ROADMAP.md Phase 4 for details.Implementation Roadmap
AshReports is currently undergoing a comprehensive improvement process:
β Stage 1: Critical Blockers (Current - Week 1)
- [x] Fix broken test suite (DSL tests now passing)
- [x] Patch security vulnerabilities (atom exhaustion fixed)
- [ ] Document implementation status (in progress)
β³ Stage 2: Test Infrastructure & Coverage (Weeks 2-3)
- Add renderer test coverage (0% β 70%)
- Add interactive engine tests
- Security hardening (remove process dictionary usage)
β³ Stage 3: Code Quality & Refactoring (Weeks 4-5)
- Reduce code duplication (25% β <10%)
- Standardize patterns across modules
β³ Stage 4-6: Architecture, Docs, Performance (Months 2-3)
- Template engine abstraction
- Comprehensive documentation
- Performance optimization
- Production hardening
For detailed roadmap, see IMPLEMENTATION_STATUS.md
Security
AshReports takes security seriously. We have:
- β Fixed atom table exhaustion vulnerabilities (HIGH severity)
- β Implemented whitelist-based validation for user input
- β Created comprehensive security documentation
- π Ongoing process dictionary removal (MEDIUM severity)
To report security vulnerabilities, see SECURITY.md
System Requirements
- Elixir: 1.14 or later
- Erlang/OTP: 25 or later
- Ash Framework: 3.0 or later
- PostgreSQL: 13+ (if using AshPostgres)
Troubleshooting
Common Issues
Q: Test compilation errors
- Ensure all dependencies are installed:
mix deps.get - Compile dependencies:
mix deps.compile - Try cleaning:
mix clean && mix compile
Q: Atom exhaustion warnings
- Update to latest version (fixed in v0.1.1+)
- See SECURITY.md for details
Q: Charts not rendering
- Verify chart configuration DSL
- Check data format matches chart type
- Review chart type support (bar, line, pie, area, scatter)
Q: Memory issues with large reports
- Use streaming for datasets >10,000 records (automatic)
- Adjust batch_size in streaming configuration
- Consider using keyset pagination for optimal performance
For more troubleshooting help, see user guides or open an issue.
Testing
Run the test suite:
# Run all tests
mix test
# Run specific test file
mix test test/ash_reports/dsl_test.exs
# Run tests with coverage
mix test --cover
# Run tests excluding slow integration tests
MIX_ENV=test mix test --exclude integration
Current test status:
- DSL & Entity Tests: β 75/75 passing
- Chart Tests: β Passing
- Renderer Tests: β 0% coverage (Stage 2 priority)
Performance
Expected performance characteristics:
| Dataset Size | Memory Usage | Generation Time | Notes |
|---|---|---|---|
| <1,000 records | <50 MB | <1 second | Direct processing |
| 1K-10K records | <100 MB | 1-5 seconds | Efficient batching |
| 10K-100K records | <200 MB | 5-30 seconds | Streaming |
| >100K records | <300 MB | 30s-5min | Streaming + chunks |
Note: PDF generation uses Typst for high-quality output. JSON is fastest format.
Contributing
We welcome contributions! However, the project is currently undergoing major refactoring:
Current Status: Stage 1 of 6-stage improvement plan Timeline: 3-4 months for full completion Coordination: Required to avoid merge conflicts
How to Contribute Now
- Report Issues - Bug reports are always welcome
- Documentation - Help improve docs and examples
- Wait for CONTRIBUTING.md - Full contributor guide coming in Stage 5
Contribution Guidelines (Preliminary)
- Follow Elixir style guide
- Add tests for all new features
- Update documentation
- Keep commits focused and atomic
- Write clear commit messages
Full CONTRIBUTING.md coming in Stage 5 (Month 2)
Community & Support
- Issues: GitHub Issues
- Discussions: GitHub Discussions
- Ash Community: Ash Framework Discord
License
Copyright 2024 Accountex Organization
Licensed under the MIT License. See LICENSE for details.
Acknowledgments
Built with:
- Ash Framework - Declarative resource framework
- Spark - DSL creation library
- Contex - Chart generation
- CLDR - Internationalization
- Typst - Document typesetting for PDF generation
Project Status
Current: Stage 1.3 (Implementation Status Documentation) Grade: B+ (Production-capable with gaps) Target: A (Production-ready) ETA: 3-4 months
See IMPLEMENTATION_STATUS.md for complete details.