Add framework module documentation #5

Merged
J.Schmidt92 merged 2 commits from feature/surrealdb-storage into master 2026-04-17 17:41:36 -05:00
5 changed files with 480 additions and 0 deletions

View File

@ -44,6 +44,13 @@ npm run build:webui
.\build-arma.ps1
```
## Documentation
- [Framework Documentation](./docs/README.md)
- [Framework Architecture](./docs/FRAMEWORK_ARCHITECTURE.md)
- [Module Reference](./docs/MODULE_REFERENCE.md)
- [Development Guide](./docs/DEVELOPMENT_GUIDE.md)
## Extension Status
```sqf

129
docs/DEVELOPMENT_GUIDE.md Normal file
View File

@ -0,0 +1,129 @@
# Development Guide
This guide covers the usual path for adding or changing a Forge module.
## Local Checks
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:
| Layer | Owns | Avoid |
| --- | --- | --- |
| `lib/models` | Data structures, serde defaults, validation helpers. | Database calls, SQF-specific context. |
| `lib/repositories` | Repository traits and in-memory stores. | SurrealDB-specific code. |
| `lib/services` | Business rules, workflow orchestration, structured results. | Arma engine calls, extension transport details. |
| `arma/server/extension` | Command parsing, context resolution, SurrealDB implementations, serialization to SQF. | Business rules that belong in services. |
| `arma/server/addons` | Server SQF lifecycle, game-object integration, calls into `forge_server`. | Direct database logic. |
| `arma/client/addons` | Client UI, keybinds, local UI events. | Authoritative persistence. |
## 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.

View File

@ -0,0 +1,133 @@
# Framework Architecture
Forge is organized around domain modules. A domain usually has SQF addon
entry points, Rust models, repository traits, service logic, extension command
handlers, and optional browser UI.
## Runtime Flow
```text
Arma client UI or SQF action
-> client addon bridge
-> server addon function
-> forge_server callExtension command
-> extension command group
-> forge-services domain service
-> forge-repositories trait
-> SurrealDB repository implementation
-> SurrealDB
```
For small payloads, server SQF calls `forge_server` directly through the
extension bridge. For large payloads, `arma/server/addons/extension` stages
request and response chunks through the extension transport module.
## Main Layers
### Client Addons
Client addons live under `arma/client/addons`. They own local player UX,
keybinds, browser UI dialogs, and UI-to-SQF event handling. When a client needs
durable or authoritative state, it routes work to the matching server addon
instead of touching persistence directly.
### Server Addons
Server addons live under `arma/server/addons`. They own server-side SQF
initialization, game-object integration, validation near the Arma runtime, and
calls into the Rust extension. The `extension` addon is the shared bridge for
`callExtension` and transport handling.
### Rust Extension
The server extension lives under `arma/server/extension`. It registers the
`forge_server` command groups, loads configuration, initializes SurrealDB, and
maps SQF command inputs into service calls.
The extension should stay thin:
- Parse and validate command arguments that arrive from SQF.
- Resolve Arma-specific context such as player UID when required.
- Call the matching service.
- Serialize the service result back to JSON or a simple string.
### Shared Rust Crates
The `lib` workspace contains reusable Rust crates:
- `forge-models`: shared domain structs and serialization rules.
- `forge-repositories`: storage-agnostic repository traits and in-memory
implementations used by tests and hot-state services.
- `forge-services`: domain behavior, validation, and mutation workflows.
- `forge-shared`: cross-crate helpers.
### Persistence
Durable storage is SurrealDB. Schema modules live under
`arma/server/extension/src/schema`, and concrete SurrealDB repository
implementations live under `arma/server/extension/src/storage`.
Repository traits stay in `lib/repositories` so service logic remains testable
without a database.
## Hot State
Several domains have `hot` command groups. Hot state keeps a runtime copy of
frequently accessed data in memory, then saves it back to durable storage when
requested. This is useful for player state that changes often during a session.
Typical hot-state flow:
```text
actor:hot:init
actor:hot:get
actor:hot:override
actor:hot:save
actor:hot:remove
```
Use hot state for session workflows. Use normal domain commands for direct
durable CRUD operations.
## Transport Layer
The transport layer exists because Arma extension calls have practical payload
size limits. It provides chunked request and response handling while still
routing to the same domain command groups.
Common direct command:
```sqf
"forge_server" callExtension ["status", []];
```
Common transport path:
```text
server addon fnc_extCall
-> transport:request:append
-> transport:invoke_stored
-> transport:response:get
```
## Configuration
The server extension reads `config.toml` next to the extension DLL. The current
persistence section is:
```toml
[surreal]
endpoint = "127.0.0.1:8000"
namespace = "forge"
database = "main"
username = "root"
password = "root"
connect_timeout_ms = 5000
```
Check persistence readiness before issuing commands that require storage:
```sqf
"forge_server" callExtension ["status", []];
"forge_server" callExtension ["surreal:status", []];
```

180
docs/MODULE_REFERENCE.md Normal file
View File

@ -0,0 +1,180 @@
# Module Reference
This reference lists the main Forge modules and where each layer lives.
## Directory Map
```text
arma/client/addons/ Client-side Arma addons and browser UIs
arma/server/addons/ Server-side Arma addons and extension bridge
arma/server/extension/ Rust arma-rs extension and SurrealDB adapters
bin/icom/ Interprocess communication helper
lib/models/ Shared domain data models
lib/repositories/ Repository traits and in-memory stores
lib/services/ Domain services and workflow logic
lib/shared/ Cross-crate helpers
tools/ Web UI build tooling
docs/ Framework-level documentation
```
## Gameplay Domains
| Domain | Purpose | Client addon | Server addon | Service/model layer | Extension group |
| --- | --- | --- | --- | --- | --- |
| Actor | Player identity, loadout, position, status, contact identifiers, and persistent character data. | `arma/client/addons/actor` | `arma/server/addons/actor` | `lib/models/src/actor.rs`, `lib/services/src/actor.rs` | `actor:*` |
| Bank | Player accounts, cash/bank balances, PIN validation, transfers, checkout charging, and transaction context. | `arma/client/addons/bank` | `arma/server/addons/bank` | `lib/models/src/bank.rs`, `lib/services/src/bank.rs` | `bank:*`, `bank:hot:*` |
| CAD | Dispatch requests, assignments, orders, activity stream, profiles, groups, and hydrated dispatcher views. | `arma/client/addons/cad` | `arma/server/addons/cad` | `lib/models/src/cad.rs`, `lib/services/src/cad.rs` | `cad:*` |
| Garage | Player vehicle storage with plate IDs, fuel, damage, and hit point state. | `arma/client/addons/garage` | `arma/server/addons/garage` | `lib/models/src/garage.rs`, `lib/services/src/garage.rs` | `garage:*`, `garage:hot:*` |
| Locker | Player item storage keyed by classname with category and amount. | `arma/client/addons/locker` | `arma/server/addons/locker` | `lib/models/src/locker.rs`, `lib/services/src/locker.rs` | `locker:*`, `locker:hot:*` |
| Organization | Player organizations, membership, treasury, credit lines, shared assets, and fleet data. | `arma/client/addons/org` | `arma/server/addons/org` | `lib/models/src/org.rs`, `lib/services/src/org.rs` | `org:*`, `org:hot:*` |
| Phone | Contacts, messages, and email state. | `arma/client/addons/phone` | `arma/server/addons/phone` | `lib/models/src/phone.rs`, `lib/services/src/phone.rs` | `phone:*` |
| Store | Store catalog checkout workflows and checkout charging integration. | `arma/client/addons/store` | `arma/server/addons/store` | `lib/models/src/store.rs`, `lib/services/src/store.rs` | `store:checkout` |
| Task | Mission/task catalog, ownership, status, reward context, and task counters. | none | `arma/server/addons/task` | `lib/models/src/task.rs`, `lib/services/src/task.rs` | `task:*` |
| Owned Garage | Organization or owner-scoped vehicle storage. | via garage/org UI | server extension only | `lib/models/src/v_garage.rs`, `lib/services/src/v_garage.rs` | `owned:garage:*` |
| Owned Locker | Organization or owner-scoped item storage. | via locker/org UI | server extension only | `lib/models/src/v_locker.rs`, `lib/services/src/v_locker.rs` | `owned:locker:*` |
## Infrastructure Modules
| Module | Purpose | Location |
| --- | --- | --- |
| `common` | Shared SQF helpers, base stores, utility functions, and shared UI bridge pieces. | `arma/client/addons/common`, `arma/server/addons/common` |
| `extension` | Server SQF bridge around `forge_server` extension calls and chunked transport. | `arma/server/addons/extension` |
| `main` | Mod-level configuration, pre-init wiring, and server/client startup glue. | `arma/client/addons/main`, `arma/server/addons/main` |
| `economy` | Server-side economy store initialization and economy-specific state helpers. | `arma/server/addons/economy` |
| `notifications` | Client notification UI, sounds, and UI event handling. | `arma/client/addons/notifications` |
| `icom` | Rust helper for interprocess communication and event broadcasting. | `bin/icom`, `arma/server/extension/src/icom.rs` |
| `terrain` | Extension-side terrain export helper. | `arma/server/extension/src/terrain.rs` |
| `transport` | Chunked request/response handling for large extension payloads. | `arma/server/extension/src/transport.rs` |
| `surreal` | SurrealDB connection lifecycle and status reporting. | `arma/server/extension/src/surreal.rs` |
## Extension Command Groups
Commands are invoked with:
```sqf
"forge_server" callExtension ["group:command", [_arg1, _arg2]];
```
Nested groups use additional `:` separators, for example
`bank:hot:deposit`.
### Core
| Command | Purpose |
| --- | --- |
| `version` | Return the extension version string. |
| `status` | Return SurrealDB connection state. |
| `surreal:status` | Return SurrealDB connection state directly from the Surreal module. |
### Actor
| Command | Purpose |
| --- | --- |
| `actor:get` | Fetch actor data for a resolved player UID. |
| `actor:create` | Create actor data from JSON. |
| `actor:update` | Apply actor JSON updates. |
| `actor:exists` | Return `true` or `false`. |
| `actor:delete` | Delete actor data. |
| `actor:hot:init`, `actor:hot:get`, `actor:hot:keys`, `actor:hot:override`, `actor:hot:save`, `actor:hot:remove` | Manage actor hot state. |
### Bank
| Command | Purpose |
| --- | --- |
| `bank:get`, `bank:create`, `bank:update`, `bank:exists`, `bank:delete` | Durable bank CRUD. |
| `bank:hot:init`, `bank:hot:get`, `bank:hot:override`, `bank:hot:patch`, `bank:hot:save`, `bank:hot:remove` | Manage bank hot state. |
| `bank:hot:deposit`, `bank:hot:withdraw`, `bank:hot:deposit_earnings`, `bank:hot:transfer` | Mutate hot bank balances with operation context. |
| `bank:hot:charge_checkout` | Charge a checkout against hot bank state. |
| `bank:hot:validate_pin` | Validate a PIN for bank operations. |
### Garage
| Command | Purpose |
| --- | --- |
| `garage:create`, `garage:get`, `garage:add`, `garage:update`, `garage:patch`, `garage:remove`, `garage:delete`, `garage:exists` | Durable player garage operations. |
| `garage:hot:init`, `garage:hot:get`, `garage:hot:override`, `garage:hot:add`, `garage:hot:remove_vehicle`, `garage:hot:save`, `garage:hot:remove` | Manage player garage hot state. |
See [Garage Usage Guide](./GARAGE_USAGE_GUIDE.md) for examples.
### Locker
| Command | Purpose |
| --- | --- |
| `locker:create`, `locker:get`, `locker:add`, `locker:update`, `locker:patch`, `locker:remove`, `locker:delete`, `locker:exists` | Durable player locker operations. |
| `locker:hot:init`, `locker:hot:get`, `locker:hot:override`, `locker:hot:save`, `locker:hot:remove` | Manage player locker hot state. |
See [Locker Usage Guide](./LOCKER_USAGE_GUIDE.md) for examples.
### Organization
| Command | Purpose |
| --- | --- |
| `org:get`, `org:create`, `org:update`, `org:exists`, `org:delete` | Durable organization CRUD. |
| `org:assets:get`, `org:assets:update` | Manage organization assets. |
| `org:fleet:get`, `org:fleet:update` | Manage organization fleet entries. |
| `org:members:get`, `org:members:add`, `org:members:remove` | Manage organization membership. |
| `org:hot:*` | Runtime organization workflows including registration, invites, credit lines, checkout charging, assets, fleet, leave, disband, save, and remove. |
### Phone
| Command | Purpose |
| --- | --- |
| `phone:init` | Initialize phone state for a UID. |
| `phone:contacts:list`, `phone:contacts:add`, `phone:contacts:remove` | Manage contacts. |
| `phone:messages:list`, `phone:messages:thread`, `phone:messages:send`, `phone:messages:mark_read`, `phone:messages:delete` | Manage messages. |
| `phone:emails:list`, `phone:emails:send`, `phone:emails:mark_read`, `phone:emails:delete` | Manage emails. |
| `phone:remove` | Remove phone state for a UID. |
### CAD
| Command Group | Purpose |
| --- | --- |
| `cad:activity:append`, `cad:activity:recent` | Append and read recent activity. |
| `cad:assignments:list`, `cad:assignments:assign`, `cad:assignments:acknowledge`, `cad:assignments:decline`, `cad:assignments:upsert`, `cad:assignments:delete` | Manage dispatch assignments. |
| `cad:orders:list`, `cad:orders:create`, `cad:orders:create_from_context`, `cad:orders:close`, `cad:orders:upsert`, `cad:orders:delete` | Manage orders. |
| `cad:requests:list`, `cad:requests:submit`, `cad:requests:submit_from_context`, `cad:requests:close`, `cad:requests:upsert`, `cad:requests:delete` | Manage requests. |
| `cad:profiles:list`, `cad:profiles:update_from_context`, `cad:profiles:upsert`, `cad:profiles:delete` | Manage profiles. |
| `cad:groups:build` | Build grouped CAD state. |
| `cad:view:hydrate` | Build the dispatcher view model. |
### Task
| Command Group | Purpose |
| --- | --- |
| `task:reset` | Reset task state. |
| `task:catalog:active`, `task:catalog:get`, `task:catalog:upsert`, `task:catalog:delete` | Manage task catalog entries. |
| `task:ownership:bind`, `task:ownership:release`, `task:ownership:accept`, `task:ownership:reward_context` | Manage task ownership and rewards. |
| `task:status:set`, `task:status:get`, `task:status:clear` | Manage task status. |
| `task:defuse:increment`, `task:defuse:get` | Manage defuse counters. |
| `task:clear` | Clear task state. |
### Owned Storage
| Command Group | Purpose |
| --- | --- |
| `owned:garage:create`, `owned:garage:fetch`, `owned:garage:get`, `owned:garage:add`, `owned:garage:remove`, `owned:garage:delete`, `owned:garage:exists` | Owner-scoped vehicle storage. |
| `owned:garage:hot:*` | Owner-scoped vehicle hot state. |
| `owned:locker:create`, `owned:locker:fetch`, `owned:locker:get`, `owned:locker:add`, `owned:locker:remove`, `owned:locker:delete`, `owned:locker:exists` | Owner-scoped item storage. |
| `owned:locker:hot:*` | Owner-scoped item hot state. |
### Other Extension Groups
| Command Group | Purpose |
| --- | --- |
| `store:checkout` | Run store checkout behavior. |
| `icom:connect`, `icom:broadcast`, `icom:send_event` | ICom connection and event forwarding. |
| `terrain:exportSVG` | Export terrain data as SVG. |
| `transport:invoke`, `transport:invoke_stored` | Invoke commands through transport. |
| `transport:request:append`, `transport:request:clear` | Manage stored request chunks. |
| `transport:response:get`, `transport:response:clear` | Manage stored response chunks. |
## Rust Crates
| Crate | Role |
| --- | --- |
| `forge-models` | Domain models and validation. Keep these serializable and free of persistence details. |
| `forge-repositories` | Repository traits and in-memory implementations. Keep these storage-agnostic. |
| `forge-services` | Business rules and workflows. Depend on repository traits, not concrete databases. |
| `forge-shared` | Cross-crate helpers. Keep dependencies light. |
| `forge-server` | Arma extension crate. Owns command registration, SurrealDB runtime wiring, and concrete storage adapters. |
| `forge-icom` | ICom helper binary and client library. |

31
docs/README.md Normal file
View File

@ -0,0 +1,31 @@
# Forge Documentation
Forge is split into Arma client addons, Arma server addons, a Rust server
extension, shared Rust domain crates, and web UI build tooling. This directory
collects framework-level documentation for those pieces.
## Start Here
- [Framework Architecture](./FRAMEWORK_ARCHITECTURE.md): how SQF, web UIs,
Rust services, repositories, and SurrealDB fit together.
- [Module Reference](./MODULE_REFERENCE.md): module inventory for gameplay
domains, extension command groups, client addons, server addons, and Rust
crates.
- [Development Guide](./DEVELOPMENT_GUIDE.md): how to add or change a module
without breaking the framework boundaries.
## Existing Usage Guides
- [Garage Usage Guide](./GARAGE_USAGE_GUIDE.md)
- [Locker Usage Guide](./LOCKER_USAGE_GUIDE.md)
## Related Documentation
- [Server Extension Docs](../arma/server/docs/README.md)
- [Server Extension API Reference](../arma/server/docs/api-reference.md)
- [Server Extension Usage Examples](../arma/server/docs/usage-examples.md)
- [Client Addon Docs](../arma/client/docs/README.md)
- [Shared Rust Libraries](../lib/README.md)
- [Repository Crate](../lib/repositories/README.md)
- [Service Crate](../lib/services/README.md)
- [Model Crate](../lib/models/README.md)