docs(ws-6): RFC-WS-6 v1.1 addenda + ARCH-BINDINGS §6.4 alignment
Promote RFC-WS-6 to v1.1 with two §3 addenda capturing the post-session-2
cleanup decisions; align ARCH-BINDINGS.md §6.4 (Person provisioning)
with the v1.1 text. No architectural reversals — corrections + one
schema addition.
§3 Q8 v1.1 addendum — Person provisioning is scoped by `event_id`:
- Q8 v1.0 said `Person::firstOrCreate(['email', 'organisation_id'], ...)`.
That is incorrect against the actual model: `Person::$organisationScopeColumn`
is `event_id`. The provisioner looks up and creates by `(email, event_id)`.
- Same email registering across two events in the same org → two distinct
Person rows. Cross-event identity reconciliation remains the job of
`PersonIdentityService` (out of scope WS-6).
- Failsafe: `PersonProvisioningException('no_event', ...)` when
`submission.event_id` is null on event_registration; publish guard
`SchemaHasLinkedEvent` blocks at config time.
§3 Q9 v1.1 addendum — `form_schemas.default_crowd_type_id` replaces
`CrowdType::oldest()`:
- Session 2's PersonProvisioner used a silent oldest()-in-org heuristic
for the new Person's `crowd_type_id` (NOT NULL). Fragile, undocumented,
cross-org broken.
- v1.1 adds `form_schemas.default_crowd_type_id` (nullable ULID) as the
explicit, versioned schema attribute. `RequiresDefaultCrowdType` publish
guard wires into `EventRegistrationGuards`. Runtime failsafe in
`PersonProvisioner::resolveCrowdTypeId()` throws
`PersonProvisioningException('no_default_crowd_type', ...)` when null.
- Schema-level FK omitted intentionally (SQLite cascade-delete on
ALTER TABLE ADD FOREIGN KEY observed in WS-5b/c backfill tests).
Application-level integrity (publish guard + runtime failsafe +
Eloquent `belongsTo`) is sufficient because writes always go through
`FormSchemaService::publish()`.
- Snapshot impact: none. Provisioning reads from live FormSchema by
FK; audit replay uses whatever the schema's current
`default_crowd_type_id` is at retry time.
ARCH-BINDINGS.md §6.4:
- Now references "RFC Q8 + Q9, v1.1" in the heading.
- Default-crowd-type bullet replaces "first active CrowdType in the org"
(the session-2 oldest() heuristic) with the schema attribute lookup.
- Multi-tenancy paragraph clarified for cross-event scoping.
Cross-references touched up:
- `PersonProvisioner::resolveCrowdTypeId()` docblock: §3 Q8 → §3 Q9.
- `RequiresDefaultCrowdType` class docblock: §3 Q8 → §3 Q9.
- `SCHEMA.md` v2.7 changelog and `default_crowd_type_id` column note:
§3 Q8 → §3 Q9.
Document history entry added in §10 documenting v1.1 + the snapshot
dual-key cleanup and route-model-binding fix landed in earlier commits
on this branch.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -155,7 +155,7 @@ final readonly class PersonProvisioner
|
||||
* Person.crowd_type_id is NOT NULL on the migration; the schema
|
||||
* declares its target CrowdType explicitly via `default_crowd_type_id`.
|
||||
*
|
||||
* RFC-WS-6 v1.1 §3 Q8 addendum (was: silent oldest() fallback in
|
||||
* RFC-WS-6 v1.1 §3 Q9 addendum (was: silent oldest() fallback in
|
||||
* session 2). The RequiresDefaultCrowdType publish guard prevents
|
||||
* misconfigured event_registration schemas from publishing; this
|
||||
* runtime throw is a failsafe for live-table edits between publish
|
||||
@@ -211,7 +211,7 @@ final readonly class PersonProvisioner
|
||||
array $bindings,
|
||||
array $identityBinding,
|
||||
): array {
|
||||
$personFillable = (new Person())->getFillable();
|
||||
$personFillable = (new Person)->getFillable();
|
||||
$attributes = [];
|
||||
|
||||
foreach ($bindings as $entry) {
|
||||
|
||||
@@ -7,7 +7,7 @@ namespace App\FormBuilder\Publishing;
|
||||
use App\Models\FormBuilder\FormSchema;
|
||||
|
||||
/**
|
||||
* RFC-WS-6 v1.1 §3 Q8 addendum — event_registration schemas must
|
||||
* RFC-WS-6 v1.1 §3 Q9 addendum — event_registration schemas must
|
||||
* declare a default_crowd_type_id so PersonProvisioner can land
|
||||
* new registrants in the right CrowdType. Replaces the silent
|
||||
* oldest() heuristic from session 2.
|
||||
|
||||
Reference in New Issue
Block a user