Writing Your First IFS Cloud Projection from Scratch
A step-by-step guide to modeling a new entity in IFS Developer Studio, writing the projection, and surfacing it in Aurena — covering Marble syntax, entity keys, and deployment.
Projections are the bridge between IFS Cloud's powerful back-end logic and the modern IFS Cloud Web/Aurena client. They publish modelled business services through IFS's OData-based REST API, making approved data and operations accessible to pages and integrations. In this guide, we'll walk through creating your first projection from the ground up—from modeling an entity in Developer Studio to deploying it in a dev environment.
Understanding IFS Projections
Before we dive into code, let's clarify what a projection does and where it fits in the IFS architecture.
What is a Projection?
A projection is a model that exposes functional business logic from IFS Cloud as a RESTful web service. It acts as an abstraction layer between the database (where your core entities live) and the client UI. The projection:
- Shields the client from direct database access
- Enriches the data with runtime logic and calculated fields
- Enforces business rules at the service layer
- Defines entry points via entitysets that clients consume
- Optionally includes PL/SQL logic for server-side operations
Think of it as a carefully curated view of your entity that includes only what the UI needs, plus any derived or computed fields.
The Layered Architecture
IFS Cloud uses a Layered Application Architecture (LAA) to keep customizations separate from the core product. IFS-delivered components can contain Base/Core source, while extension/customer layers are used according to the solution ownership and development model:
- Core Layer – IFS-provided standard functionality
- Extension (Ext) Layer – For extensions and enhancements
- Customization (Cust) Layer – For customer-specific modifications
When you write your own projection, you typically work in the Cust or Ext layer. This keeps the change separate from IFS-delivered Core source and makes upgrade analysis and conflict handling much clearer.
Project Structure: File Types and Dependencies
IFS Aurena development involves four interconnected source areas:
1. Entity and Enumeration Models (.entity and .enumeration)
The persistent business object is modelled first. These are Developer Studio server-model files: use the entity and enumeration editors to define keys, attributes, references, persistence and state. The projection consumes the generated entity; it does not redefine the table model inline.
2. Projection File (.projection)
The projection file defines the data structure and operations. It contains:
- Entitysets – Which generated entities or queries to publish
- Datasources – Entity, query, summary, structure, and virtual definitions exposed by the service
- References – Related entities that can be fetched
- Arrays – Collections of child records
- Actions & Functions – Operations the client can invoke
- Calculated data items – Projection-specific fetched or virtual values
- Enumeration references – Domain values already defined in the model
3. Projection Service and Entity PL/SQL (.plsvc and .plsql)
Developer Studio generates the projection's _SVC package and the implementation signatures for declared operations. Depending on the release and development workflow, projection-specific implementations are exposed as PL/SQL service (.plsvc) source or as a generated service implementation scaffold. Entity-owned rules and reusable business APIs remain in the owning entity's layered .plsql source. Together they cover:
- Custom action logic
- Function implementations
- Method overrides
- Server-side validation
Generate after declaring an action or function, then implement the exact scaffold produced for the target release. Do not hand-create an _SVC package or assume that an Apps 10, early Cloud, and current Cloud workspace will present the service source in exactly the same way.
4. Client File (.client)
The client file defines the UI structure (pages, lists, dialogs). For this guide, we'll focus on projections, but the client depends on the projection for its data source.
Dependencies
When you commit a projection:
- The projection depends on entities – You must reference existing database entities
- If entities have enumerations, the projection depends on those
- The client depends on the projection – The UI binds to projection data
- During build, the code generator traverses these dependencies to validate everything is in place
Source grammar and generated extension points can vary between released IFS Cloud versions. Keep examples that are valid for the release you support, and always validate them with that release's Developer Studio.
Step 1: Understand Your Entity Model
Before writing the projection, you need to know your underlying entity. In this example, we'll create a projection for a hypothetical EmployeeBonus entity.
Typical Entity Structure
An entity in IFS Cloud has:
- Primary Keys – Unique identifiers (often composite)
- Attributes – Data fields with types
- References – Links to parent entities
- Derived Values – Calculated or fetched fields
For our EmployeeBonus example, create these attributes in the entity model rather than in the projection:
| Attribute | Model type | Purpose |
|---|---|---|
| BonusId | TEXT | Stable business key |
| EmployeeId | TEXT | Reference to Employee entity |
| DepartmentId | TEXT | Reference to Department entity |
| BonusAmount | NUMBER | The bonus value |
| TaxAmount | NUMBER | Tax withheld from the bonus |
| BonusDate | DATE | When the bonus was awarded |
| ApprovedBy | TEXT | Manager who approved it |
| Notes | TEXT | Additional details |
| Status | Enumeration model | Draft, Approved, Paid |
Step 2: Create the Projection File in Developer Studio
Open IFS Developer Studio and follow these steps:
Create a New Projection
- Right-click on the registered customer component that owns the feature
- New > Projection
- Name:
EmployeeBonus(descriptive, globally unique) - Layer: Use the layer appropriate to that component and customer solution; do not modify IFS-delivered Core source
- Component: Select the real owning component (the examples use the placeholder
BONUS) - Description: "Projection for managing employee bonuses"
Set the Category and Dependency
Step 3: Write the Projection Marble Code
Now, let's build out the projection structure. Here's a complete example:
Understanding Entitysets
An entityset is the REST endpoint exposed by your projection. It maps to a specific entity and defines how it's queried:
@DynamicComponentDependency COMPONENT has a narrower purpose: it conditionally includes decorated source when an optional component is installed. It does not load arbitrary entities at runtime. Use a normal component dependency when the projection cannot function without the referenced component.
Attribute Types and Annotations
Marble supports several attribute types and modifiers:
| Type | Usage | Example |
|---|---|---|
| Text | Text values | attribute Name Text; |
| Integer | Whole numbers | attribute Count Integer; |
| Number | Numeric values | attribute Amount Number; |
| Date | Calendar dates | attribute BonusDate Date; |
| Timestamp | Date and time values | attribute CreatedAt Timestamp; |
| Boolean | True/False | attribute IsActive Boolean; |
| Enumeration | Fixed domain value | attribute Status Enumeration(BonusStatus); |
Key modifiers:
required = [true]– Marks a projection data item as requiredupdatable = [false]– Prevents the projection item being updatedlabel = "Display Name"– Supplies a human-readable labelfetch = "..."– Supplies a database expression for a calculated item
Entity keys and mandatory persistent attributes are defined in the entity model, not invented with inline is key syntax in the projection.
Key Marble Syntax Explained
@DynamicComponentDependency – Makes a section conditional on an optional installed component.
entity – Alters or enriches the generated projection entity when explicitly declared.
attribute – A field from the underlying database entity or a computed value.
reference – A link to another entity. This creates a relationship that can be navigated from the client.
array – A collection of child records (similar to a one-to-many relationship).
virtual or fetched attribute – Projection data calculated at runtime; not stored directly.
action – A server-side operation the client can invoke (like "ApproveBonus").
function – A callable operation that returns a value.
enumeration – A fixed domain modelled separately and referenced by the entity or projection.
structure – A complex data type returned by functions, not a main entity.
Step 4: Using @Override for Customizations
When you're working in the Cust layer and customizing an existing projection, you use @Override to modify only the parts you're changing.
Example: Adding a Field to an Existing Projection
That example assumes the entity customization has already added the corresponding company_bonus_code persistence. For a calculated item, use a supported SQL expression or API call in fetch instead.
Key Points:
- Only include the attributes/actions you're adding or modifying
- Use
@Overrideon the entity itself - Use the target release's documented
@Overridegrammar for individual model elements - The generator merges the customer layer with the lower layer during code generation
- Never modify Core-layer files directly
Step 5: Working with References and Arrays
Projections aren't isolated—they often reference other entities. Understanding how to properly define and use references is critical.
One-to-One References
When a client requests an EmployeeBonus, they can expand the EmployeeRef to get the full Employee record:
GET /EmployeeBonuses(BonusId='B123')?$expand=EmployeeRef
This returns the bonus plus all Employee attributes in one response.
One-to-Many Arrays
Arrays represent child collections:
If the same projection also publishes entityset Employees for Employee;, you can include the bonuses when querying an employee:
GET /Employees(EmployeeId='E001')?$expand=Bonuses
Lazy Loading vs. Eager Loading
By default, references and arrays use lazy loading – they're not included unless explicitly requested via $expand. This improves performance for large datasets.
Use $expand only where the published relationship and use case justify it:
Avoid expanding a high-cardinality child collection for every row in a large list. Fetch the detail collection when the user opens the record instead.
Step 6: Define Entity Keys and Search Predicates
Entity keys are critical for REST operations. They uniquely identify records and form the URL path.
Simple vs. Composite Keys
Simple Key (one attribute) is defined on BonusId in the entity model. Inspect $metadata to see its projection property name and OData type.
Composite Key (multiple attributes):
For a composite key, mark both EmployeeId and BonusYear as keys in the entity model and preserve their generated order.
When composite, the URL would look like:
/EmployeeBonuses(EmployeeId='E001',BonusYear=2025)
Search Predicates
You can define how records are filtered:
The predicate is a server-side database expression. Confirm the stored enumeration value and generated column name. Apply user-specific date filters and ordering through supported OData query options rather than embedding $today or an order by clause in this block.
Step 7: Implement the Generated Server Extension Point
When an action or function needs custom logic, generate the affected model and inspect the exact implementation scaffold produced for that release. In Developer Studio workflows that provide projection PL/SQL service source, implement the generated method in the .plsvc source. Keep entity-owned validation and reusable business behaviour in the entity's layered .plsql source or a published IFS API. Never edit the generated database package body directly.
The approval implementation should:
- Load the selected record using its generated key.
- Lock or apply optimistic-concurrency handling as the entity pattern requires.
- Confirm the caller is allowed to perform the business transition.
- Reject a record that is no longer in Draft state.
- Apply the state change through the generated entity logic or a supported IFS API.
- Record the approval note and audit data through the same business transaction.
Use the IFS error framework for a business validation, for example inside the generated package context:
The surrounding procedure name and parameters must come from the generated action scaffold. Do not guess them from the REST action name.
When overriding an existing generated method, layered PL/SQL uses super to retain lower-layer behaviour:
That example shows the layering pattern, not the approval action itself. A new generated action implementation will have its own signature.
Transaction Ownership
Projection actions run inside a framework-managed transaction. On success the service transaction commits; on failure it rolls back. Do not place COMMIT or ROLLBACK inside the action implementation. Manual transaction control can make part of a failed business operation permanent and can break retry behaviour.
Avoid Direct Table DML
Do not update a standard _TAB table or create a hand-made approval log as a shortcut. Direct DML bypasses entity validation, state events, history, accounting, integrations, and other side effects. Use the generated entity methods and published business APIs. For a customer-owned entity, model required audit attributes or a related audit entity so they are generated and delivered with the feature.
Actions and Functions
An action may change database state. A function must not. A net-amount calculation can be a fetched attribute or a function if several clients need it; approval must be an action. Bound operations are preferred. An unbound operation should specify an initialcheck so authorisation is established before execution.
Step 8: Code Generation and Compilation
Build and Generate
- Save your projection file (
.projection) - Save the affected entity, enumeration, projection, client, projection-service implementation, and layered
.plsqlsource - In Developer Studio: Right-click your component > Build or Generate Code
The build process creates:
- Generated database and projection implementation artefacts
- OData service metadata for the projection
- Client metadata consumed by IFS Cloud Web
Monitor the Build Log
Check Developer Studio validation first, then the authoritative Build Place and delivery logs for the target environment. Log names differ across releases and build arrangements.
Common issues:
- Entity not found – Check the referenced entity exists
- Syntax errors – Verify Marble syntax (matching brackets, semicolons)
- Package compile errors – Check the generated log and the affected layered
.plsqlsource
Step 9: Build and Deliver to a Development Environment
Once local validation is successful, the source must be built and delivered through the customer's supported IFS Cloud lifecycle.
Deployment Steps
- Commit the complete source change – Include the models and layered server source in the customer solution repository.
- Create a build – Use IFS Lifecycle Experience/Build Place for the release-aligned customer solution.
- Review failures and warnings – Resolve generation, dependency, compile, and static-analysis issues.
- Create a delivery – Promote the immutable build through the agreed non-production delivery stages.
- Apply change control – Record permissions, configuration, test evidence, and rollback/recovery planning with the delivery.
Verify Deployment
For IFS-managed Cloud environments, verify deployment through build and delivery logs, API Explorer, the projection's $metadata, page behaviour, and supported logs. Customers do not normally connect as the application owner to query USER_OBJECTS. Some remote or customer-managed arrangements provide database access, but a database object check is not a substitute for testing the published service and permissions.
In Apps 10 or a customer-managed development environment where application-owner database access is explicitly supported, a read-only object check can supplement those tests:
Use the actual generated package name from the build output; do not infer it solely from the projection display name.
Step 10: Surfacing the Projection in Aurena
Now that your projection is available in the development environment, the final build step is creating a Client file to expose it in Aurena.
Create a Client File
EmployeeBonus.client:
Pages and Navigation
- The page contains all UI elements for a business process
- Selectors let users choose a record or context
- Groups display a single record's detailed information
- Commands call projection operations or perform supported client navigation and dialog behaviour
- Fields bind to projection attributes
The client names its projection explicitly. Add the approval command only after the action is present in generated metadata; calls use the parameters and binding produced for the target release, not a JavaScript or SQL block embedded in the client.
Step 11: Testing and Validation
Test via Aurena UI
- Log into your Aurena environment
- Navigate to the entry you added for the page; the projection category does not create a navigator entry by itself
- Verify you can:
- List bonuses
- View details
- Invoke the Approve action
- See calculated fields update
Test via REST API
You can also test directly via the OData endpoint:
Obtain the short-lived access token through an approved IFS IAM client and OAuth flow; do not put a username and password in source or shell history. Keep shell tracing disabled while handling the token. Passing the generated authorization header through stdin keeps the token out of curl's process arguments. Replace Approved with the literal exposed by the deployed enumeration contract. A bound action is called with POST, but its namespace-qualified path, body, key syntax, and ETag requirements must come from $metadata for the deployed release.
Validate the Published Contract, Not Just the Happy Path
The page working for an administrator is only the first test. Before promoting the projection, exercise the contract with a user who has exactly the intended permission set and record access:
- Read
$metadataand retain it with the test evidence. Check entity-set names, key order/types, nullability, operation binding, return structure, and enumeration values. - Query one page with
$selectand a bounded$top; then follow every server-provided@odata.nextLinkuntil the test set is complete. - Test an allowed filter, sort, reference expansion, and composite key using the exact property casing in metadata.
- Create or update a test record only in an approved non-production data set. Send the concurrency token/ETag required by that entity and prove that a stale update is rejected.
- Invoke the action as an authorised user, an unauthorised user, and against a record in the wrong lifecycle state.
- Confirm that a failed action leaves no partial business update or outbound side effect.
- Verify that fields excluded for security are absent from metadata/response, rather than merely hidden on the page.
- Repeat the core tests through the intended integration identity; an interactive administrator token can conceal missing grants.
A compact promotion record might look like this:
| Contract area | Evidence |
|---|---|
| Service identity | Projection name, versioned base URL, build/delivery ID |
| Data shape | Captured $metadata and approved response sample with sensitive values removed |
| Authorisation | Permission-set grant plus allowed/denied test results |
| Business access | Company/site/user data-scope tests |
| Concurrency | Current ETag succeeds; stale ETag fails without overwrite |
| Transaction | Validation failure produces no partial state change |
| Performance | Representative $select, $filter, $expand, and paging timings |
This evidence becomes especially valuable after an IFS update. If metadata, generated operation signatures, or enumeration literals change, you can see the contract delta before a client or integration fails in production.
Best Practices and Key Takeaways
1. Keep Projections Lean
Don't expose every attribute of an entity. Include only what the UI needs. This improves performance and security.
2. Use References Wisely
References are powerful but can cause performance issues if overused. Prefer explicit selection over automatic fetching.
3. Separate Core and Customization
Use Cust when extending IFS-delivered source, and the owning layer defined for a registered customer component when developing new customer-owned source. Keep the ownership boundary explicit so upgrades can analyse it.
4. Test Early and Often
Generate and build frequently during development. Catch syntax errors before they accumulate.
5. Document Your Marble
Add descriptions and comments:
6. Validate on the Server
Put authoritative business rules in the entity or service layer and raise a meaningful IFS business error, ensuring consistency across all clients. A client enabled expression is not enforcement.
7. Version and Track Changes
Use clear naming and comments in your projection files. When you create a new version, increment version numbers or add timestamps.
Treat these comments as human-readable context; the customer solution repository and immutable build/delivery identifiers remain the source of truth.
Conclusion
Creating a projection is the gateway to modern IFS Cloud development. By following this step-by-step guide, you've learned how to:
- Model an entity in IFS terminology
- Write Marble syntax for projection definitions
- Use @Override for customizations in the Cust layer
- Implement business logic in the generated projection-service extension point and supported layered
.plsqlsource - Generate and build your projection
- Deploy to dev and test in Aurena
Projections are the bridge between database and UI. Master them, and you unlock the full power of IFS Cloud customization. The patterns you've learned here—entity modeling, layered architecture, action and function definitions—apply to every projection you'll create.
Now it's your turn. Start with a simple entity, build your projection, and watch it come to life in Aurena. Happy coding!
Further Reading
- IFS Developer Studio projection source reference
- IFS Developer Studio client source reference
- IFS Cloud technical documentation
- IFS Developer Studio: built-in completion, validation, and generated-source views for your target release
Need support building your first IFS Cloud projection?
Syrett Consultancy can help your team model entities, structure projections, and avoid the common first-project mistakes.