[LOADED_DOCS: 3 files, no new loads]

Add Rule #6, AUTH topic, ADRs, config & doc updates

- Codified Rule #6 (authority, rule scope, skill invocation) in all primary copilot-instructions.md files
- Clarified skill pre-load/lazy-load rules and LOADED_DOCS prefix
- Forbid skill/template version labels in Decision Log governance
- Scaffolded new AUTH topic with README, ISSUES, and TODO files
- Added repo/project ADR folders and templates; new ADR for AcBinaryHubProtocol decorator stack
- Migrated cross-cutting issues/TODOs to Closed with detailed resolution
- Made FruitBankHybrid.Shared/appsettings.json the canonical config source; suppressed Razor SDK auto-publish to avoid file collisions
- Updated protocol/wire format docs for AcBinaryHubProtocol
- Minor config: updated ports, WaitForFlush, and csproj content rules
This commit is contained in:
Loretta 2026-04-26 13:44:12 +02:00
parent 8f72593741
commit 0ad9250e4c
19 changed files with 422 additions and 31 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -64,13 +64,15 @@ If ambiguous, ask the user explicitly before proceeding.
Placement IS a real decision only when no `docs/adr/` exists yet in the relevant scope. Two sub-cases:
- **Fresh repo / first ADR ever**: default to `<repo>/docs/adr/` at the repo root. Propose creating it with `README.md` (2-3 lines explaining the convention) and `0000-TEMPLATE.md` (copy of `references/ADR_TEMPLATE.md`). User confirms (Rule #5) before creation.
- **Fresh repo / first ADR ever**: default to `<repo>/docs/adr/` at the repo root.
- **Multi-project repo, no `docs/adr/` anywhere yet**: match scope to placement —
- **Cross-cutting decision** (affects 2+ projects, framework↔consumer boundary, or repo-wide concerns such as auth, logging conventions, build infrastructure) → place at the **highest common ancestor** of affected scopes, typically `<repo>/docs/adr/` at the repo root.
- **Project-scoped decision** (one project's internal architecture only) → `<repo>/<project>/docs/adr/`.
- **Ambiguous scope** → ask the user explicitly. Suggested phrasing: *"this decision touches projects X and Y — should the ADR live at the repo-root `docs/adr/` (cross-cutting) or scoped to one of those projects?"*
**For any newly-created `docs/adr/` folder** (whether at repo root or project-scoped): propose creating `README.md` (2-3 lines explaining the ADR convention + an index table for new ADRs) and `0000-TEMPLATE.md` (a 1-paragraph pointer to the canonical `references/ADR_TEMPLATE.md` — single source of truth, avoids template drift). User confirms (Rule #5) before creation.
The chosen location persists in git history and inbound cross-references (other ADRs, code comments, docs); relocating later requires updating every cross-ref. Getting placement right at creation is cheaper than fixing it.
## Step 2 — Establish context (Socratic)

View File

@ -13,6 +13,7 @@ To make IDs like `LOG-I-5`, `SIG-B-2`, `XCUT-I-1` **globally unique strings**
| Code | Topic | Scope | Docs location (primary) |
|---------|-----------------------------|-----------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------|
| `LOG` | LOGGING | Logger system: levels, writers, config-reading vs DI factory | `AyCode.Core/AyCode.Core/docs/LOGGING/` (+ variants in `AyCode.Core.Server`, `AyCode.Services`, `Mango.Nop.Services`) |
| `AUTH` | AUTH | User authentication: bearer tokens, JWT, login flow, hub authorization | `AyCode.Core/docs/AUTH/` |
| `SIG` | SIGNALR | SignalR transport: tags, client base, dispatch, session | `AyCode.Core/AyCode.Services/docs/SIGNALR/` (+ variant in `AyCode.Services.Server`) |
| `SBP` | SIGNALR_BINARY_PROTOCOL | Binary wire protocol over SignalR: framing, chunking, argument read | `AyCode.Core/AyCode.Services/docs/SIGNALR_BINARY_PROTOCOL/` |
| `BIN` | BINARY | AcBinary serializer: features, format, writers, source generator | `AyCode.Core/AyCode.Core/docs/BINARY/` |

View File

@ -64,6 +64,13 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "docs", "docs", "{D4B2E9F1-A
docs\GLOSSARY.md = docs\GLOSSARY.md
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "adr", "adr", "{8D1B72D8-7145-4AAB-A216-1D4CC950E3AE}"
ProjectSection(SolutionItems) = preProject
docs\adr\0000-TEMPLATE.md = docs\adr\0000-TEMPLATE.md
docs\adr\0001-user-bearer-token-flow.md = docs\adr\0001-user-bearer-token-flow.md
docs\adr\README.md = docs\adr\README.md
EndProjectSection
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -466,6 +473,9 @@ Global
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{8D1B72D8-7145-4AAB-A216-1D4CC950E3AE} = {D4B2E9F1-A6C3-4F7E-8D5B-3E2A1C4F6B8D}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {E97347E0-52CA-4086-A3F4-CE65ABDE9964}
EndGlobalSection

View File

@ -147,4 +147,6 @@ A single instance must not use context + standalone modes simultaneously — buf
### XCUT-I-1: JSON-in-Binary request parameters — cross-ref
Canonical entry: **`../XCUT/XCUT_ISSUES.md#xcut-i-1`**. Summary: client→server request parameters currently use JSON inside a Binary envelope (`SignalPostJsonDataMessage<T>`); response path is already pure Binary. Planned migration is tracked in `BINARY_TODO.md#bin-t-1` but requires coordinated client+server+consumer changes. Do NOT attempt as a side-effect.
**Status:** Closed (2026-04-26, see canonical entry).
Canonical entry: **`../XCUT/XCUT_ISSUES.md#xcut-i-1`**. Summary: client→server request parameters previously used JSON inside a Binary envelope (`SignalPostJsonDataMessage<T>`); response path was already pure Binary. Migration landed in commits `cdd54d3` + `3b70070` via `SignalParams` (length-prefixed binary pack/unpack) — wire is now Binary in both directions. Migration plan tracked in `BINARY_TODO.md#bin-t-1` (also Closed).

View File

@ -6,12 +6,19 @@
---
## BIN-T-1: Replace JSON-in-Binary request parameters
**Priority:** P1 · **Type:** Refactor · **Related:** `../XCUT/XCUT_ISSUES.md#xcut-i-1` (canonical), `AyCode.Services/docs/SIGNALR/SIGNALR_TODO.md`
**Priority:** P1 · **Type:** Refactor · **Status:** Closed (2026-04-26, landed in commits `cdd54d3` 2026-04-05 + `3b70070` 2026-04-06) · **Related:** `../XCUT/XCUT_ISSUES.md#xcut-i-1` (canonical), `AyCode.Services/docs/SIGNALR/SIGNALR_TODO.md`
Migrate client→server request parameters from JSON-in-Binary envelope to direct Binary serialization (matching response path). Coordinated change across client, server, and all consuming projects. Do NOT attempt as side-effect of unrelated work.
**Acceptance:** `SignalPostJsonDataMessage<T>` replaced by a `SignalPostBinaryDataMessage<T>` (or equivalent); no JSON round-trip on the wire for request params; benchmarks confirm no regression.
### Resolution
- **What:** Length-prefixed, per-parameter binary format introduced via `SignalRSerializationHelper.SerializeParametersToBinary` / `DeserializeParametersFromBinary`; further unified into `SignalParams` (single `byte[]` carrying packed method parameters with `SetParameterValues` / `GetParameterValues`).
- **Where:** `AyCode.Services/SignalRs/AcSignalRClientBase.cs`, `AcWebSignalRHubBase.cs`, `ISignalParams.cs` (server + client dispatch); `IAcSignalRHubClient.cs` (legacy wrappers).
- **Equivalent (not literal `SignalPostBinaryDataMessage<T>`):** `SignalParams` was chosen over a 1:1 binary wrapper class — fewer indirections on the hot path, type-safe pack/unpack, and `DataSerializerType` field on `SignalReceiveParams` for response format indication.
- **Wire impact:** No JSON round-trip on the wire for request params; this is a **breaking change** vs. previous JSON-in-Binary clients/servers (see commit message).
- **Legacy types:** `SignalPostJsonMessage`, `SignalPostJsonDataMessage<T>`, `SignalPostMessage<T>`, `ISignalPostMessage<T>` all marked `[Obsolete]` in `IAcSignalRHubClient.cs`; deletion tracked separately in `AyCode.Services/docs/SIGNALR/SIGNALR_TODO.md#sig-t-6` (gated on consumer migration).
## BIN-T-2: Re-evaluate DiscountProductMapping SGen exclusion
**Priority:** P3 · **Type:** Investigation · **Related:** `BINARY_ISSUES.md#bin-i-11`

View File

@ -8,38 +8,33 @@ For planned cross-cutting work, see `XCUT_TODO.md`.
## XCUT-I-1: JSON-in-Binary request parameters
**Status:** Open
**Status:** Closed (2026-04-26, landed in commits `cdd54d3` 2026-04-05 + `3b70070` 2026-04-06)
**Affects:** BINARY serializer (wire format) ↔ SIGNALR transport (envelope) ↔ all consuming projects (caller code)
### Description
### Description (historical)
Client→server request parameters currently travel as JSON inside a Binary envelope:
- `SignalPostJsonDataMessage<T>` is the current envelope
- Response path already uses pure Binary (no JSON)
- Asymmetry: request is JSON-in-Binary, response is Binary
Client→server request parameters previously travelled as JSON inside a Binary envelope:
- `SignalPostJsonDataMessage<T>` was the original envelope
- Response path already used pure Binary (no JSON)
- Asymmetry: request was JSON-in-Binary, response was Binary
### Why it spans multiple topics
### Why it spanned multiple topics
- **BINARY side**: the serializer has to special-case JSON payloads inside a Binary stream; ideal Binary-only flow is broken on the request side.
- **SIGNALR side**: the transport carries the JSON-wrapped Binary payload; `SignalPostJsonDataMessage<T>` is a SignalR-level concept.
- **Consumer side**: every caller sends requests via this asymmetric path; changing the wire format requires coordinated client + server + all-consuming-project updates.
- **BINARY side**: the serializer had to special-case JSON payloads inside a Binary stream; ideal Binary-only flow was broken on the request side.
- **SIGNALR side**: the transport carried the JSON-wrapped Binary payload; `SignalPostJsonDataMessage<T>` was a SignalR-level concept.
- **Consumer side**: every caller sent requests via this asymmetric path; changing the wire format required coordinated client + server + all-consuming-project updates.
### Planned migration (tracked in TODO)
### Resolution
- `BINARY_TODO.md#bin-t-1` — "Replace JSON-in-Binary request parameters"
- Acceptance: `SignalPostJsonDataMessage<T>` replaced by `SignalPostBinaryDataMessage<T>` (or equivalent); no JSON round-trip on the wire for request params; benchmarks confirm no regression.
### Do NOT attempt as a side-effect
Any client or server change in isolation will break the other side. Requires:
1. Binary envelope for both request and response defined
2. Client code updated to serialize via Binary
3. Server code updated to deserialize via Binary
4. All consuming projects rebuilt against new API
5. Version bump coordinated
- **What:** Length-prefixed, per-parameter binary format introduced via `SignalRSerializationHelper.SerializeParametersToBinary` / `DeserializeParametersFromBinary`, then unified into `SignalParams` carrying packed parameters as a single `byte[]` with `SetParameterValues` / `GetParameterValues` for type-safe pack/unpack.
- **Where:** `AyCode.Services/SignalRs/``AcSignalRClientBase.cs`, `AcWebSignalRHubBase.cs`, `ISignalParams.cs`; legacy types in `IAcSignalRHubClient.cs` marked `[Obsolete]`.
- **Wire impact:** No JSON round-trip on the wire for request params. **Breaking change** vs. previous JSON-in-Binary clients/servers — version bump required.
- **Equivalent, not literal:** `SignalParams` (object[]-style packed payload) replaced `SignalPostJsonDataMessage<T>` instead of introducing a parallel `SignalPostBinaryDataMessage<T>`. Single unified envelope, fewer hot-path indirections.
- **Coordinated change:** client + server + consumer projects updated together in the two commits (BREAKING). All five steps from the original "Do NOT attempt as a side-effect" list completed.
- **Legacy cleanup outstanding (not blocking closure):** `[Obsolete]` wrappers can be deleted once external consumer projects stop referencing them — tracked in `../../../AyCode.Services/docs/SIGNALR/SIGNALR_TODO.md#sig-t-6` (separate from this canonical issue).
### Cross-references
- **BINARY_ISSUES.md** (`../BINARY/BINARY_ISSUES.md#xcut-i-1`): cross-ref pointing here
- **SIGNALR_ISSUES.md** (`../../../AyCode.Services/docs/SIGNALR/SIGNALR_ISSUES.md#xcut-i-1`): cross-ref pointing here
- **BINARY_TODO.md#bin-t-1**: migration plan
- **BINARY_TODO.md#bin-t-1**: migration plan (also marked Closed)

View File

@ -130,4 +130,6 @@ Hypothesis (unverified): `PostDataAsync<T>` awaiter's null-mapping path misroute
### XCUT-I-1: JSON-in-Binary request parameters — cross-ref
Canonical entry: **`../../../AyCode.Core/docs/XCUT/XCUT_ISSUES.md#xcut-i-1`**. Summary: SignalR transport carries `SignalPostJsonDataMessage<T>` (JSON inside a Binary envelope) for request params, while response path is pure Binary. Planned replacement is coordinated across BINARY serializer + SIGNALR transport + all consuming projects.
**Status:** Closed (2026-04-26, see canonical entry).
Canonical entry: **`../../../AyCode.Core/docs/XCUT/XCUT_ISSUES.md#xcut-i-1`**. Summary: SignalR transport previously carried `SignalPostJsonDataMessage<T>` (JSON inside a Binary envelope) for request params, while response path was pure Binary. Replacement landed in commits `cdd54d3` + `3b70070`: `SignalParams` (length-prefixed binary pack/unpack) replaces the JSON envelope, coordinated across BINARY serializer + SIGNALR transport + consumer projects. **Breaking change** for older clients.

View File

@ -73,3 +73,16 @@ services.AddSignalR(hubOptions => { /* unchanged */ })
### Why this belongs in AyCode.Services (framework layer) docs
The gap is consumer-level, but the canonical "server-side registration recipe" is a FRAMEWORK responsibility — LOGGING.md already shows it for the logger side. Adding a matching recipe to `../SIGNALR_BINARY_PROTOCOL/README.md#Registration in Program.cs → Server` would prevent the next consumer from making the same mistake. That doc update is part of this TODO's acceptance criteria.
## SIG-T-6: Delete legacy `[Obsolete]` JSON-in-Binary wrappers
**Priority:** P3 · **Type:** Cleanup · **Related:** `../../../AyCode.Core/docs/XCUT/XCUT_ISSUES.md#xcut-i-1` (closed canonical), `../../../AyCode.Core/docs/BINARY/BINARY_TODO.md#bin-t-1` (closed)
Now that XCUT-I-1 / BIN-T-1 have landed and the wire format no longer uses JSON-in-Binary, the `[Obsolete]` wrapper types in `IAcSignalRHubClient.cs:60-111` can be deleted:
- `SignalPostJsonMessage`
- `SignalPostJsonDataMessage<T>`
- `SignalPostMessage<T>`
- `ISignalPostMessage<T>`
**Gate:** verify external consumer projects no longer reference these types — compile-time scan across the workspace + dependent solutions before removal.
**Acceptance:** all four obsolete types deleted from `IAcSignalRHubClient.cs`; no CS0618 warnings in any consumer build; remaining doc/glossary mentions either deleted or rewritten as historical references.

View File

@ -43,7 +43,7 @@ WriteMessage(HubMessage, IBufferWriter<byte> output)
│ ├─ WriteStringUtf8(invocationId, target)
│ ├─ WriteVarUInt(argCount)
│ ├─ Per argument:
│ │ ├─ byte[] (AcBinary) → raw length + bytes (no tag, no VarUInt)
│ │ ├─ byte[] (AcBinary) → raw length + bytes (no 0x44 wrapper — first byte is AcBinary FormatVersion 0x01, no VarUInt)
│ │ ├─ byte[] (other) → tag (0x44) + raw bytes (no VarUInt — argLength implies size)
│ │ └─ object → FlushAndReset() → reserve INT32 arg prefix
│ │ → AcBinarySerializer.Serialize(value, output) → patch prefix
@ -63,7 +63,7 @@ var isAcBinary = byteArray.Length >= 2
&& (byteArray[1] & 0xF0) == BinaryTypeCode.HeaderFlagsBase; // 0x90
```
- **isAcBinary = true**: `[argLength=N][raw AcBinary bytes]` — no tag, reader deserializes directly
- **isAcBinary = true**: `[argLength=N][raw AcBinary bytes]` — no 0x44 wrapper tag; first byte is the AcBinary FormatVersion 0x01 (the discriminator the receiver uses), reader deserializes directly
- **isAcBinary = false**: `[argLength=1+N][0x44 tag][raw bytes]` — tag for type detection, no VarUInt (argLength implies size)
### Dual BWO Pattern

View File

@ -0,0 +1,5 @@
# ADR Template
The canonical template lives at [`AyCode.Core/.github/skills/adr-author/references/ADR_TEMPLATE.md`](../../../.github/skills/adr-author/references/ADR_TEMPLATE.md) — that's what the `adr-author` skill copies when authoring a new ADR.
This file exists only as a placeholder so `docs/adr/` numbering starts visibly at `0001`. Don't edit this file; edit the canonical template if the format needs to change.

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,25 @@
# Architecture Decision Records (ADRs)
Project-scoped Architecture Decision Records for `AyCode.Services` — design decisions specific to this project's internal architecture (binary hub protocol composition, SignalR client design, etc.). Repo-wide cross-cutting decisions live in [`AyCode.Core/docs/adr/`](../../../docs/adr/), not here.
See [`.github/skills/adr-author/SKILL.md`](../../../.github/skills/adr-author/SKILL.md) for the full authoring procedure (routing rules, Socratic interview, trade-off elicitation, draft → review → write).
## Convention
- **Format:** Nygard-style ADR; one file per decision.
- **Filename:** `NNNN-<slug>.md` — zero-padded 4-digit sequence + kebab-case slug derived from the title (e.g. `0001-acbinary-decorator-feature-stack-design.md`).
- **Numbering:** sequential, append-only. Derive next NNNN from `max(existing) + 1` at write time.
- **Template:** copy [`0000-TEMPLATE.md`](0000-TEMPLATE.md) when starting a new ADR.
- **Status field:** `Proposed (YYYY-MM-DD)``Accepted (YYYY-MM-DD)` / `Rejected (YYYY-MM-DD)` / `Superseded by ADR-XXXX (YYYY-MM-DD)`. Update in-place; entry body / ID / Decision text remain immutable.
## Index
| ID | Title | Status |
|-----------------------------------------------------------------|------------------------------------------------------------------------------------|-----------------------|
| [0001](0001-acbinary-decorator-feature-stack-design.md) | AcBinaryHubProtocol optional feature stack — decorator-based composition design | Proposed (2026-04-25) |
## Related
- Repo-wide cross-cutting decisions: [`AyCode.Core/docs/adr/`](../../../docs/adr/).
- Protocol-meta decisions (rule changes, skill additions, instruction-file structural shifts): [`.github/LLM_PROTOCOL_DECISIONS.md`](../../../.github/LLM_PROTOCOL_DECISIONS.md).
- Topic-level cross-references for `AcBinaryHubProtocol`-specific ADRs surface in [`SIGNALR_BINARY_PROTOCOL/README.md`](../SIGNALR_BINARY_PROTOCOL/README.md) under `## Related ADRs` (added in Step 8 of the `adr-author` skill — separate `mehet` round).

23
docs/AUTH/AUTH_ISSUES.md Normal file
View File

@ -0,0 +1,23 @@
# AUTH — Known Issues
Active known issues for user authentication (bearer tokens, JWT, login flow, hub authorization).
For planned/actionable work see [`AUTH_TODO.md`](AUTH_TODO.md).
For the architectural decision that scoped this topic, see [`../adr/0001-user-bearer-token-flow.md`](../adr/0001-user-bearer-token-flow.md).
## Active entries
*(No `AUTH-I-N` entries yet — topic just created. Currently-relevant security entries live as `LOG-I-9` and `LOG-I-10` in [`LOGGING_ISSUES.md`](../../AyCode.Core/docs/LOGGING/LOGGING_ISSUES.md), pre-migration. ADR 0001's "Status migration on AUTH topic creation" follow-up is the planned home transfer — separate user-approved task.)*
## Entry format
When adding the first entry, follow the standard `_ISSUES.md` shape used across topics (LOGGING, BINARY, SIGNALR), with `AUTH-I-N` ID format per [`TOPIC_CODES.md`](../../.github/skills/docs-check/references/TOPIC_CODES.md):
- ID line with `**Severity:** ... · **Status:** ... · **Area:** ...`
- `### Description` — concrete problem with quotable evidence
- `### Root cause` — what's actually wrong (optional)
- `### Fix direction` — proposed approach
- `### Resolution` — when Status moves to `Closed` (per `TOPIC_CODES.md` Status conventions): what / where / why / caveat
- `### Related` — sibling entries, cross-topic refs, ADR refs (`**Reference:** ADR-NNNN` for ADR pre-flight cross-refs per `adr-author/SKILL.md` Step 8 #3)
Status vocabulary (per `TOPIC_CODES.md`): `Open`, `InProgress`, `Closed (YYYY-MM-DD)`. Three values only — distinct from ADR Status (Proposed/Accepted/Superseded/Rejected).

22
docs/AUTH/AUTH_TODO.md Normal file
View File

@ -0,0 +1,22 @@
# AUTH — TODO
Planned work for user authentication (bearer tokens, JWT, login flow, hub authorization).
For known issues, see [`AUTH_ISSUES.md`](AUTH_ISSUES.md).
For the architectural authority, see [`../adr/0001-user-bearer-token-flow.md`](../adr/0001-user-bearer-token-flow.md) — its Follow-up sections ("Implementation", "Consumer wiring") are the master plan for what should populate this file.
## Priority legend
- **P0** blocker · **P1** important · **P2** nice-to-have · **P3** idea
## Active entries
*(No `AUTH-T-N` entries yet — topic just created. ADR 0001 Follow-up "Implementation" + "Consumer wiring" lists the master plan; granular `AUTH-T-N` entries will populate this file as implementation phases kick off and break the high-level plan into trackable units.)*
## Entry format
When adding the first entry, follow the standard `_TODO.md` shape used across topics (LOGGING, SIGNALR, BINARY), with `AUTH-T-N` ID format per [`TOPIC_CODES.md`](../../.github/skills/docs-check/references/TOPIC_CODES.md):
- ID line with `**Priority:** P1/P2/P3 · **Type:** Feature/Refactor/Bug fix/etc. · **Related:** <cross-refs>`
- Short rationale (1-2 sentences)
- Optional sections: Acceptance criteria, Migration plan, Consequences/checklist

54
docs/AUTH/README.md Normal file
View File

@ -0,0 +1,54 @@
# AUTH — User Authentication
Bearer-token user authentication: JWT issuance, client-side token storage, HTTP + SignalR transport bindings, per-tag SignalR dispatch authorization, and security hardening.
> **Architectural authority:** [`../adr/0001-user-bearer-token-flow.md`](../adr/0001-user-bearer-token-flow.md). This README is the consumer-facing recipe; the ADR captures rationale and decision history.
## Status
⚠️ **Pre-implementation.** ADR 0001 specifies the architecture; the framework code has not yet landed. This README is a scaffold — the "Consumer recipe" section is a placeholder for content that fills in as the implementation progresses (per ADR 0001 Follow-up "Implementation" series).
## Scope
| Concern | Decision |
|---|---|
| Token issuance | JWT (HS256, 24h fixed lifetime, configurable per consumer); refresh-flow deferred to ADR 0002 |
| Client-side storage | `IAcTokenStore` framework abstraction; consumer-supplied platform impls (MAUI / WASM) |
| HTTP transport | Framework-provided delegating handler injects bearer header automatically |
| SignalR transport | Framework hub-builder extension wires access-token provider; WASM uses query-string fallback |
| Server-side validation | Standard ASP.NET Core JwtBearer pipeline via framework DI bundle |
| Per-tag authorization | Hub-class `[Authorize]` default + explicit allowlist attribute for unauth tags (login, ping) |
| Security hardening | Startup options validation (key length, issuer/audience), HTTPS metadata required outside Development |
## Out of scope (per ADR 0001)
Refresh-token flow (→ ADR 0002), role/claims authorization, multi-tenant claims, OAuth2 / external IdP, token revocation, logout server-side invalidation.
## Files in this folder
- [`README.md`](README.md) — this file (scope + consumer recipe).
- [`AUTH_ISSUES.md`](AUTH_ISSUES.md) — known issues, security observations, edge cases.
- [`AUTH_TODO.md`](AUTH_TODO.md) — planned work derived from ADR 0001 Follow-ups.
## Consumer recipe
> Placeholder — populated as implementation progresses.
Sections to come (mirrors ADR 0001 Follow-up "Implementation" + "Consumer wiring"):
- DI registration bundle examples (MAUI + WASM + Server)
- `IAcTokenStore` consumer implementation skeletons
- Hub allowlist attribute usage
- `appsettings.json` `AyCode:Jwt` section reference
- HTTPS / Kestrel / proxy notes (especially WASM `access_token` URL-param redaction)
## Security: Never log secrets
JWT signing keys, access tokens, refresh tokens, password hashes, and OAuth client secrets MUST NEVER appear in log output. Logged secrets leak via the same channels as the logs themselves (file system, retention archives, screenshots, bug reports). For diagnostics, log only metadata (user ID, expiry, issuer) or hash prefixes — never the raw value.
This guideline emerged from `LOG-I-9` and `LOG-I-10` (both `Closed (2026-04-25)` via `#if DEBUG` gating per ADR 0001 pre-flight). Pending `LOG-T-12` proposes adding a generalized framework-level guideline section to [`LOGGING/README.md`](../../AyCode.Core/docs/LOGGING/README.md); when that lands, it becomes the canonical home and this section trims to a cross-ref.
## Cross-references
- **ADR**: [`../adr/0001-user-bearer-token-flow.md`](../adr/0001-user-bearer-token-flow.md) — architectural decision.
- **Topic registry**: `AUTH` row in [`TOPIC_CODES.md`](../../.github/skills/docs-check/references/TOPIC_CODES.md) (added in `LLMP-DEC-49`).
- **Sibling pre-migration**: `LOG-I-9` / `LOG-I-10` in [`LOGGING_ISSUES.md`](../../AyCode.Core/docs/LOGGING/LOGGING_ISSUES.md) — currently homed in LOGGING; ADR 0001 Follow-up "Status migration on AUTH topic creation" lists these as candidates for relocation here as `AUTH-I-N` with `Superseded by` cross-refs in LOGGING. Migration NOT yet performed — separate user-approved follow-up.

View File

@ -2,7 +2,7 @@
## Status
Proposed (2026-04-25)
Accepted (2026-04-25)
## Context
@ -99,6 +99,7 @@ Adopt a layered bearer-token authentication architecture across all client and s
- **Hub-class-only `[Authorize]` without per-tag allowlist** (rejected): login + ping tags would also require auth → bootstrap deadlock.
- **Per-tag DI policy registry** (rejected): too much complexity for Layer 0; mixes consumer-specific tag lists into framework.
- **Custom token middleware from scratch** (rejected): non-standard, no `[Authorize]` interop, no out-of-the-box JWT validation.
- *Future flexibility:* locks us out of standard OAuth2 / external-IdP integration when ADR `0002+` extends scope; the chosen `JwtBearer` pipeline keeps that door open.
- *Future flexibility:* locks out standard OAuth2 / external-IdP integration when ADR `0002+` extends scope; the chosen `JwtBearer` pipeline keeps that door open.
## Related

View File

@ -16,7 +16,7 @@ See [`.github/skills/adr-author/SKILL.md`](../../.github/skills/adr-author/SKILL
| ID | Title | Status |
|-------------------------------------------------|------------------------------------------------------------------------|-----------------------|
| [0001](0001-user-bearer-token-flow.md) | User bearer-token authentication flow (HTTP + SignalR + tag dispatch) | Proposed (2026-04-25) |
| [0001](0001-user-bearer-token-flow.md) | User bearer-token authentication flow (HTTP + SignalR + tag dispatch) | Accepted (2026-04-25) |
## Related