App Structure
A ZeyOS app is the unit of packaging, sync, and deployment. Understanding app structure is essential because iXML behavior depends on where code is executed within the app.
Directory layout
A typical ZeyOS app contains:
app-name/
├── zeyos.app.json # App metadata and identity
├── services/ # Entry points: API, background tasks, hooks
├── resources/ # Reusable domain logic and helpers
├── weblets/ # UI-linked iXML integrations
└── settings/ # Per-instance configuration
├── defaultsettings.json
└── settings.<instance>.json
A useful mental model: services orchestrate requests, resources encapsulate logic, and settings provide runtime variability.
Runtime contexts
Service context
Files in services/ are invoked as runtime entry points. This is where you:
- Parse inbound payloads
- Enforce auth and guard clauses
- Call reusable resource logic
- Shape final response payloads
Services are registered in zeyos.app.json with types like remotecall (HTTP API endpoint), timing (scheduled job), or before_modification / after_modification (entity lifecycle hooks).
Resource context
Files in resources/ are consumed via include, call, or expand. This context should hold reusable logic that is independent from a specific transport boundary.
Weblet context
Files in weblets/ are linked to UI action flows. They compose resource functions and app settings to produce user-facing behavior.
App settings and APPSETTINGS
Settings under settings/ are the preferred place for tenant-specific values and environment toggles. Avoid hardcoding instance-specific values directly into service logic.
Use APPSETTINGS for values such as:
- External endpoint URLs
- Credentials references and key aliases
- Feature toggles and rollout switches
- Integration mode flags
This allows one codebase to run against multiple instances with different behavior per instance, without branching code.
Context switching and scope behavior
When iXML enters function/class/include/resource boundaries, it creates local execution context. Variable visibility follows the precedence rules explained in the Introduction.
Key implications:
- Local variables are context-bound.
- Globals (
<global var="..." />) should be explicit and rare. - Free variables (
<use>) should be intentional and readable.
Recommended service-to-resource flow
<!-- services/account.api.ixml -->
<include id=".AccountController" />
<rest:server>
<rest:resource route="/accounts/:id" method="GET">
<call func="AccountController.getById" var="payload">
<param name="id">$id</param>
</call>
<header>Content-Type: application/json</header>
<output><encode:json var="payload" /></output>
</rest:resource>
</rest:server>
This pattern keeps transport details local to services/ while maintaining reusable, testable logic in resources/.
Common mistakes
- Treating
resources/as route handlers instead of reusable modules. - Hardcoding instance-specific values instead of using
settings/andAPPSETTINGS. - Using globals as implicit data transport between unrelated contexts.
- Mixing UI-specific behavior into shared domain modules.