Use Cases#
Business problems Palmyra solves#
Palmyra is built for organisations that need internal, data-heavy web applications delivered fast — and that keep needing more of them. The framework is not a product; it’s the machinery that makes products like these cheaper to build and maintain.
Beyond basic CRUD, Palmyra’s advanced patterns cover approval workflows, child-entity handlers with nested URLs, email notifications, row-level security, filterable dashboards, i18n, and in-app discussion threads — all documented with worked examples.
Healthcare — clinic / hospital management#
Patient registration, appointment scheduling, prescription tracking, pharmacy inventory, billing — every module is a master-data list plus transactional CRUD with a few reports. A clinic application (the framework’s own reference sample) ships Department, Product, Stock, Purchase, Supplier, and User Management screens on top of Palmyra with 24 handlers and 10 React pages.
Manufacturing / supply chain — ERP screens#
Bill of materials, purchase orders, goods-received notes, stock adjustments, vendor ledgers. Each entity is a table with foreign keys and audit trails; screens are grids with filter/sort and forms with lookups. Palmyra’s parentRef flattening and FetchConfig keep list payloads lean across multi-hop joins (part → vendor → country), and SaveHandler upserts simplify sync from barcode scanners or IoT feeds.
Education — student / course administration#
Student registration, course catalogues, enrolment, fee tracking, grade sheets. Every entity follows the same pattern: a master list, a detail view, an edit form, and an export. The CsvHandler / ExcelHandler stream reactive exports so a grade-sheet download for 50 000 students doesn’t stall the server.
Financial services — back-office operations#
Account opening, KYC document management, transaction ledgers, reconciliation dashboards, compliance reporting. Palmyra’s @Permission + the ACL extension enforce per-role visibility on the same handler (query = "TXN_VIEW", export = {"TXN_EXPORT"}), and DropMode.OUTGOING keeps PII out of API responses without shadow DTOs.
Government / public sector — citizen-facing portals#
Licence applications, permit tracking, inspection records, grievance management. Multi-tenant deployments scope every query by tenantId injected in applyQueryFilter; the NativeQueryHandler powers dashboard reports (application counts by district, average processing time) without leaving the handler ecosystem.
Retail / e-commerce — operations back-office#
Product catalogues, order management, inventory, promotions, customer records. The frontend’s MantineServerLookup drives a product picker that queries /product?name=... in real time; the grid’s FilterForm plugin auto-generates a filter panel from the column definitions so operators don’t need a separate search UI.
Human resources — employee management#
The My First Application walkthrough builds exactly this: department master data, employee records with FK lookup, status lifecycle, audit-stamped timestamps. Extend it with leave tracking, payroll stubs, and document uploads (via TusUploadHandler) and you have an HR module.
Multi-tenant SaaS platforms#
Any of the above, sold to multiple customers on shared infrastructure. Palmyra’s handler hooks inject tenant scoping without per-entity code:
@Override
public QueryFilter applyQueryFilter(QueryFilter filter, HandlerContext ctx) {
filter.addCondition(new SimpleCondition("tenantId", auth.getTenantId()));
return filter;
}Every query, every export, every upsert is tenant-isolated from one override in the base handler.
Technical problems Palmyra removes#
Backend#
| Problem | Without Palmyra | With Palmyra |
|---|---|---|
| New entity needs a controller + service + repository + SQL | 4+ files, 200+ lines | 1 annotated POJO + 1 handler component |
| Client wants different fields per screen | Multiple endpoints or GraphQL | Client passes _fields, server compiles SELECT |
| Flatten a parent attribute (e.g. department name on employee row) | Hand-written JOIN or DTO projector | @PalmyraField(parentRef = "department", attribute = "name") |
| Required on create, optional on update | Two DTOs or runtime if-checks | @PalmyraField(mandatory = Mandatory.CREATE) |
| Audit columns that clients shouldn’t set, hashes that shouldn’t leak | Shadow DTO | DropMode.INCOMING / DropMode.OUTGOING on the same model |
| Swap auth providers without changing handlers | Rewrite permission checks | @Permission resolves through Spring’s standard PermissionEvaluator — swap the bean, keep the annotations |
| Export millions of rows to CSV/Excel | Custom streaming code | CsvHandler / ExcelHandler stream reactively out of the box |
| Schema constraints not in the database | Validate in application code | @PalmyraMappingConfig declares unique / foreign keys; Palmyra honours them during upserts and lookups |
Frontend#
| Problem | Without Palmyra | With Palmyra |
|---|---|---|
| Per-entity HTTP fetch/update/delete | axios wrapper per resource | One PalmyraStoreFactory + an endpoint string |
| Grid paging, sort, search, refresh-after-save | Manual useState + query-string encoding |
SummaryGrid from a column-definition array |
| Form state + validation + submit to API | React Hook Form + axios + toast | PalmyraNewForm / PalmyraEditForm with attribute props |
| Foreign-key dropdown that queries a second API | Custom debounce + fetch + mapping | MantineServerLookup with an endpoint + label attribute |
| Swap MUI ↔ Mantine | Rewrite every component | Change the import path; data layer is identical |
| Filter panel for a grid | Build per-grid | FilterForm plugin auto-generates from column definitions |
Who benefits most#
| Team / organisation | What Palmyra gives them |
|---|---|
| Small teams building internal tools | Ship CRUD screens in days, not weeks — one developer can cover both stacks |
| Organisations with many similar entities | Each new entity = 1 POJO + 1 handler + 5 React files — not a new vertical slice |
| Teams that own their relational database | Raw JDBC, no ORM hiding the schema; responses under 50 ms on normal workloads |
| Backend teams that don’t want a separate API spec | The model IS the contract — no OpenAPI drift, no code generation |
| Frontend teams tired of per-entity boilerplate | One factory, one endpoint string, one attribute prop — done |
| Regulated industries | @Permission + ACL extension + DropMode enforce access control and data masking at the framework level, not scattered through business code |
What Palmyra is not designed for#
Honest boundaries — pick the right tool:
| Scenario | Better fit |
|---|---|
| Public GraphQL API | Hasura, Spring GraphQL |
| Document / NoSQL database | Mongoose, Spring Data MongoDB |
| Real-time / event-driven streaming | Kafka + Spring Cloud Stream, Socket.IO |
| Zero-config code generation with opinionated scaffolding | JHipster |
| Heavy client-side offline-first state | Redux Toolkit, TanStack Query with local persistence |
Palmyra shines when the problem is “we have relational tables and we need admin screens, fast, for a lot of entities” — and keeps shining as the entity count grows, because the cost per entity stays flat.
Where to start#
- Overview — framework positioning and capabilities.
- Comparison — honest side-by-side with similar frameworks.
- Concepts — plain-language primer on Palmyra’s moving parts.
- My First Application — build an Employee + Department app end-to-end.
- Tutorial — Advanced — 20+ recipes for workflows, dashboards, nested resources, email, ACL, i18n, and more.
- API Format — the full HTTP contract for mobile / third-party integrators.
- Reference — per-component API pages.