2026-05-23 09:23:12 -05:00

244 lines
5.6 KiB
Markdown

# Development Guide
This guide covers the usual path for adding or changing a Forge module.
## Local Checks
Before running storage-backed workflows locally, complete
[SurrealDB Setup](/getting-started/surrealdb-setup).
Run these before pushing Rust or extension changes:
```powershell
cargo fmt --check
cargo check
cargo test
cargo build
cargo clippy --all-targets --all-features -- -D warnings
```
Run this after changing browser UI sources:
```powershell
npm run build:webui
```
Build Arma packages with:
```powershell
.\build-arma.ps1
```
## Module Boundaries
Keep each layer responsible for one kind of work:
<table>
<thead>
<tr>
<th>
Layer
</th>
<th>
Owns
</th>
<th>
Avoid
</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<code>
lib/models
</code>
</td>
<td>
Data structures, serde defaults, validation helpers.
</td>
<td>
Database calls, SQF-specific context.
</td>
</tr>
<tr>
<td>
<code>
lib/repositories
</code>
</td>
<td>
Repository traits and in-memory stores.
</td>
<td>
SurrealDB-specific code.
</td>
</tr>
<tr>
<td>
<code>
lib/services
</code>
</td>
<td>
Business rules, workflow orchestration, structured results.
</td>
<td>
Arma engine calls, extension transport details.
</td>
</tr>
<tr>
<td>
<code>
arma/server/extension
</code>
</td>
<td>
Command parsing, context resolution, SurrealDB implementations, serialization to SQF.
</td>
<td>
Business rules that belong in services.
</td>
</tr>
<tr>
<td>
<code>
arma/server/addons
</code>
</td>
<td>
Server SQF lifecycle, game-object integration, calls into <code>
forge_server
</code>
.
</td>
<td>
Direct database logic.
</td>
</tr>
<tr>
<td>
<code>
arma/client/addons
</code>
</td>
<td>
Client UI, keybinds, local UI events.
</td>
<td>
Authoritative persistence.
</td>
</tr>
</tbody>
</table>
## Adding a Domain Module
1. Add the model in `lib/models/src/<module>.rs`.
2. Export the model from `lib/models/src/lib.rs`.
3. Add repository traits in `lib/repositories/src/<module>.rs`.
4. Add in-memory repository support if the service needs tests or hot state.
5. Export the traits from `lib/repositories/src/lib.rs`.
6. Add service logic in `lib/services/src/<module>.rs`.
7. Add focused unit tests for service behavior.
8. Export the service from `lib/services/src/lib.rs`.
9. Add a SurrealDB schema module under `arma/server/extension/src/schema`.
10. Add the concrete storage adapter under `arma/server/extension/src/storage`.
11. Register the storage adapter in `arma/server/extension/src/storage.rs`.
12. Add an extension command group under `arma/server/extension/src/<module>.rs`.
13. Register the command group in `arma/server/extension/src/lib.rs`.
14. Add server addon functions under `arma/server/addons/<module>` if SQF needs a module-level API.
15. Add client addon or browser UI files under `arma/client/addons/<module>` if the module has player-facing UI.
16. Add documentation in `docs/` and module-level READMEs.
## Extension Command Rules
Commands should return one of these forms:
- JSON string for structured results.
- `"true"` or `"false"` for simple existence and boolean operations.
- `"OK"` for successful destructive operations with no response body.
- `"Error: <message>"` for failures.
Prefer stable JSON shapes over ad hoc strings. SQF callers should always check
for the `"Error:"` prefix before parsing JSON.
Example:
```sqf
private _result = "forge_server" callExtension ["actor:get", [getPlayerUID player]];
private _payload = _result select 0;
if (_payload find "Error:" == 0) exitWith {
systemChat format ["Actor request failed: %1", _payload];
};
private _actor = fromJSON _payload;
```
## Persistence Rules
SurrealDB is the durable store. Keep database-specific mapping in the extension
storage adapters, not in services or repository traits.
When changing persisted data:
- Update or add the matching `.surql` schema module.
- Update the concrete storage adapter.
- Preserve existing records when possible through serde defaults or migration
logic.
- Add tests at the service level for behavior, and add storage tests only when
database mapping is the risk.
## Hot-State Rules
Use hot state for data that is read or mutated frequently during a player
session. Hot-state modules usually provide:
- `init` to load durable state into memory.
- `get` to read the runtime copy.
- `override` or focused mutation commands to update the runtime copy.
- `save` to write the runtime copy back to SurrealDB.
- `remove` to evict the runtime copy.
Do not assume hot state is durable until `save` succeeds.
## Web UI Rules
Browser UI source files live under each client addon. Built assets usually land
under that addon's `ui/_site` directory.
Use the existing common bridge in `arma/client/addons/common` when a UI needs
to send events back to SQF. Keep UI state and rendering in JavaScript, and keep
server-authoritative decisions in server SQF or Rust services.
## Documentation Checklist
When adding or changing a module, update:
- `docs/MODULE_REFERENCE.md` for framework-level inventory.
- A module-specific README in the addon directory when SQF or UI usage changes.
- `arma/server/docs/api-reference.md` when extension commands change.
- Existing usage guides when payload shapes or workflows change.