# Conventions ## Naming - **Prefix:** All framework types use `Ac` prefix (e.g., `AcDalBase`, `AcBinarySerializer`, `AcLoggerBase`). - **Interfaces:** Standard `I` prefix + `Ac` (e.g., `IAcDbContextBase`, `IAcUserDbSetBase`). - **Extensions:** `{Domain}Extensions.cs` (e.g., `StringExtensions`, `CollectionExtensions`, `AcDbSessionExtension`). - **Test bases:** `Ac{Domain}TestBase` or `AcBase_{TestName}` for inherited test methods. ## Patterns - **Extension methods over instance methods** for CRUD operations. Keeps interfaces clean, implementations composable. - **Session/Transaction pattern** in DataLayers: `Session()` for reads, `Transaction()` for writes. Both are mutex-protected. - **Generic interface hierarchy** for entities: Interface → Abstract Entity → Concrete (in consuming project). - **Partial classes** for large serializers (AcBinarySerializer, AcToonSerializer split across 10+ files). - **Source generation** for hot-path serialization. Runtime reflection only as fallback. ## Serialization Conventions - Binary serializer properties are written in **alphabetical order** (matches source generator output). - String interning is opt-in via `[AcStringIntern]` attribute or `enableInternString` flag. - Chain API for multi-type deserialization with cross-reference resolution. - Feature flags on `[AcBinarySerializable]` eliminate dead code from generated output. ## SignalR Conventions See `AyCode.Services/docs/SIGNALR/README.md` for full architecture documentation. - **Single dispatch method** — all communication goes through `OnReceiveMessage(int messageTag, int? requestId, SignalParams signalParams, object data)`. Do not add new hub methods. - **Tag-based routing** — associate methods with integer tags via `[SignalR(tag)]` (server) or `[SignalRSendToClient(tag)]` (client). Tags must be unique across the entire system. - **CRUD bundles** — entities use `SignalRCrudTags(getAllTag, getItemTag, addTag, updateTag, removeTag)` with 5 independent tag integers. Tags must be unique across the system. See `AyCode.Services.Server/docs/SIGNALR/SIGNALR_DATASOURCE.md`. - **Binary protocol** — `AyCodeBinaryHubProtocol` (derived from `AcBinaryHubProtocol`) is the transport protocol. Zero-copy write: `AcBinarySerializer.Serialize(value, output)` directly to pipe. Zero-copy read: `SequenceReader` + type-aware deserialization via `SignalParams.SignalDataType`. Three read paths: byte[] fast-path (0x44 tag), IsRawBytesData (raw byte[]), typed deserialization. ### ⚠️ Temporary: JSON-in-Binary Request Parameters Client→server request parameters currently use a JSON-inside-Binary envelope — a cross-cutting tech debt planned for migration to pure Binary. Canonical entry: `AyCode.Core/AyCode.Core/docs/XCUT/XCUT_ISSUES.md#accore-xcut-i-x8q1`. Cross-refs: `BINARY_ISSUES.md#accore-xcut-i-x8q1` (serializer side) and `SIGNALR_ISSUES.md#accore-xcut-i-x8q1` (transport side). Migration is tracked in `BINARY_TODO.md#accore-bin-t-s8p4`. Do NOT attempt as a side-effect of unrelated work — requires coordinated client+server+consuming-project changes. ## Testing - **MSTest** framework across all test projects. - **Abstract test bases** with `AcBase_` prefixed methods for reusable test logic. - **TestDataFactory** for centralized test data creation with ID sequencing. - **Testable infrastructure** for SignalR: `TestableSignalRClient2`, `TestableSignalRHub2` bypass real connections. ## Framework-First Placement Every new type/feature requires asking: *generic or consumer-specific?* | Trait | Verdict | |-------|---------| | Contains a consumer's product name, tenant, or URL | **REJECT** from framework | | Same pattern appears in 2+ consumers | **PROMOTE** to framework | | Abstract/virtual hooks for consumer customization | **ACCEPT** in framework | | Requires a specific concrete type from a consumer | **REDESIGN** — use generic/options/extension pattern | Before committing any type to this framework: - No consumer-name string in any identifier, namespace, docstring, or doc - No hardcoded consumer-specific values - Extension methods / base classes / options classes cover the N-consumer use case Full doctrine: `ARCHITECTURE.md#framework-vs-consumer-boundary`