Change Log: SaaS Architecture Policy & Annex A
Tracks what changed as a direct result of each review, and who to credit for it. Only useful, adopted changes are listed — points raised and not adopted are not tracked here. Full technical detail lives in the policy and Annex A themselves; this page is the condensed index.
:::tip Adding a new entry Add a new version block at the top (newest first) with the reviewer's name filled in. If a change came from a document/tool review rather than a named person, credit it as "Source:" instead of "Reviewer:". :::
v1.11 — 2026-10-17
Source: Direct request — correct errors in the Action Items file
| # | Change | Where |
|---|---|---|
| 1 | Corrected: ACT-001 referred to withTenantScope(), renamed to withTenant() to match the shipped API and Annex A.10 | actions.md (ACT-001) |
| 2 | Corrected: ACT-004 status "Decided — mirrored" is not a defined status; now Closed | actions.md (ACT-004, tracking table) |
| 3 | Corrected: ACT-004 link to Annex A.10 used the pre-rename heading anchor; updated to the current one | actions.md (ACT-004) |
v1.10 — 2026-10-17
Source: Direct request — record the Search Engine integration decisions (PRs #375 and #376 of rarit-saas-kernel)
| # | Change | Where |
|---|---|---|
| 1 | Added: the Search Engine package (@raritllc/search), merged to dev | rarit-saas-kernel, packages/search |
| 2 | Decided: platform tenant discovery through SECURITY DEFINER reader functions, one reader role per table (A) | ADR platform-enumeration-under-rls |
| 3 | Decided: the resolver hook supplies row-scope values only; permissions are asked of IAM once per key per request and never cached (B) | packages/search/src/v1/access.ts |
| 4 | Decided: manifest rowScope accepts the string and the object form (C) | packages/search/src/core/manifest/schema.ts |
| 5 | Decided: SearchError extends AppError (D); catalogs in locales/ (E) | packages/search |
| 6 | Decided: search in npm-packages.mjs (F); no reason or sensitive actions for search.* (G) | scripts/npm-packages.mjs |
| 7 | Decided: boolean entitlement search.enabled, never metered; query audit without query text | packages/search |
| 8 | Added: ACT-012 to ACT-016 (defects found in IAM and platform-core) and ACT-017 (decision record) | actions.md (new) |
v1.9 — 2026-08-28
Source: Direct request — formalize code review process as its own policy, separate from the SaaS Architecture Policy (broader scope: covers independent mobile apps too, not just kernel + verticals)
| # | Change | Where |
|---|---|---|
| 1 | Added: new sibling policy, "RaR-IT Code Review & Pull Request Policy" v1.0 — PR requirements, Claude Code Review configuration, REVIEW.md governance, merge-enforcement limits under GitHub Free | code-review-policy.md (new) |
| 2 | Closed: ACT-005, outcome is the new policy | actions.md |
| 3 | Added: ACT-006 — REVIEW.md drift-prevention across repos, no design chosen yet | actions.md (new) |
| 4 | Added: ACT-007 — roll out PR template + branch-naming convention platform-wide, including mobile apps with no prior rollout plan | actions.md (new) |
v1.8 — 2026-08-28
Source: Direct request — configure Claude Code Review now that a Team plan is active
| # | Change | Where |
|---|---|---|
| 1 | Added: ACT-005 — configure Claude Code Review on rarit-saas-kernel and all five vertical repos; trigger set to "Once after PR creation" | actions.md (new entry) |
| 2 | Added: REVIEW.md — repo-facing file translating Policy §4, §5/A.10, A.7, and A.11.3 into explicit Code Review rules, distinct from CLAUDE.md's general project context | REVIEW.md (new, per repo) |
v1.7 — 2026-08-27
Source: Direct request — reproduce and mirror two older ADRs referenced but never previously published in this collection
| # | Change | Where |
|---|---|---|
| 1 | Added: ADR "Fastify for Shared Engines (Not NestJS)" reconstructed in full (9 sections, 12-criterion scoring matrix) from the original conversation's actual content and mirrored as a versioned page | adr/fastify-vs-nestjs-decision.md (new, EN + AR) |
| 2 | Added: "Node.js vs. PHP Laravel" weighted comparison study reconstructed (7 of 9 criteria fully recovered; 2 minor criteria, 10% combined weight, honestly flagged as not recovered rather than guessed) | adr/nodejs-vs-laravel-study.md (new, EN only — AR pending) |
| 3 | Added: versioned PDFs for both, placed in signed-records/adr/ alongside the existing DB-access-pattern ADR | signed-records/adr/ |
| 4 | Restructured: the three ADRs now sit under a nested "Architecture Decision Records" sidebar category, ordered chronologically (Fastify-vs-NestJS → DB access pattern → Node-vs-Laravel) | sidebars.ts |
v1.6 — 2026-08-27
Source: Direct request — the external ADR source became unavailable; mirror it locally instead
| # | Change | Where |
|---|---|---|
| 1 | Added: db-access-pattern-decision.md reproduced verbatim as a versioned page (v1.0) | adr/db-access-pattern-decision.md (new) |
| 2 | Decided: ACT-004 resolved — mirror, not pin-and-link, given the source became unavailable | actions.md |
| 3 | Fixed: all four references to the external github.com/rarit/rarit-saas-kernel URL replaced with the local mirror link | Policy §5, §6; Annex A.1, A.10 |
v1.5 — 2026-08-27
Source: Direct request — centralize open items into a dedicated tracker
| # | Change | Where |
|---|---|---|
| 1 | Added: new Action Items tracker, four open items (ACT-001–ACT-004) with type, status, owner placeholder | actions.md (new) |
| 2 | Added: full withPlatformAdminScope() proposal — separate function, read-only default, per-table opt-in, mandatory audit reason — with the concrete TEN-DASH-01 blocker it resolves | A.11.2 (expanded from open question to proposed design) |
| 3 | Added: pointer to ACT-003 (event bus durability) — content unchanged, now tracked centrally | A.7 |
| 4 | Added: pointer to ACT-002 (Data Ownership Matrix) — content unchanged, now tracked centrally | Policy §9 |
| 5 | Added: ACT-004 — recommendation against mirroring rarit-saas-kernel's ADRs into this repo; pin GitHub links to a commit instead | actions.md (new) |
v1.4 — 2026-08-27
Reviewer: _____________ Type: Formal written review (13 findings, High/Medium/Low priority)
| # | Change | Where |
|---|---|---|
| 1 | Fixed: "Clinical Templates Engine" → "Clinical Templates Module" (contradicted the five-engine limit in Section 4) | A.4, summary table |
| 2 | Fixed: broken lint:cycles script — legacy ESLint flags incompatible with the flat config specified one step earlier | A.9 Step 3 |
| 3 | Added: eslint-plugin-boundaries rule for one-way vertical-to-vertical imports — a real gap no-cycle cannot cover | A.9 Step 9 (new) |
| 4 | Added: RLS stated as the primary, non-bypassable boundary; app-layer filter as secondary, not equivalent | A.10 |
| 5 | Added: set_config(..., true) = SET LOCAL, and why that's what makes the pattern connection-pool-safe | A.10 |
| 6 | Added: audit rows are stored per-vertical, not centrally — a direct consequence of Section 3.2, now stated explicitly | A.10 |
| 7 | Added: event-bus delivery guarantee flagged as unresolved; transactional-outbox recommended if in-process only | A.7 |
| 8 | Added: concrete criteria for when a vertical may adopt NestJS, anchored to real examples | Policy §6.1 |
| 9 | Added: full request lifecycle — Auth → Tenant Resolution → RBAC → Entitlement → RLS → Business logic | Policy §4 |
| 10 | Added: Data Ownership Matrix logged as a standing Architecture Review Board action item | Policy §9 |
| 11 | Added: proxy-hop specified as the standard remediation over a duplicated guard, if this pattern is ever approved | A.6 |
| 12 | Added: commission-rate configuration ownership clarified (lives in Payment/Entitlements, not Transport) | A.2 |
| — | Removed: A.11.5 (PostgREST-role note) — judged low value, not a real risk any RaR-IT code was at risk of | Requested directly, not part of this review |
v1.3 — 2026-08-27
Source: Prior-art evaluation — sascdb.sql (an old, unrelated PostgreSQL system's RLS setup, submitted for review)
| # | Change | Where |
|---|---|---|
| 1 | Added: RLS pattern for a child table with no direct tenant_id column (subquery-scoped policy) | A.11.1 (new) |
| 2 | Added: cross-tenant admin-read shape flagged as an open proposal for platform-core — not yet an accepted pattern | A.11.2 (new) |
| 3 | Added: real anti-example — ENABLE ROW LEVEL SECURITY without FORCE, found in the old system as-is | A.11.3 (new) |
| 4 | Added: real anti-example — notification/audit logic embedded in a DB trigger instead of the service layer | A.11.4 (new) |
v1.2 — 2026-08-27
Reviewer: _____________ Type: Informal review comment, pre-sign-off
| # | Change | Where |
|---|---|---|
| 1 | Fixed: A.1, A.3, A.4, A.5 were calling fastify.db directly inside route handlers, contradicting db-access-pattern-decision.md | A.1, A.3, A.4, A.5 |
| 2 | Added: repository → service → route three-layer split adopted as the reference shape in every example | A.1, A.3, A.4, A.5 |
| 3 | Added: getDb() / withTenantScope() documented as the mandatory tenant-scoped access pattern | A.10 (new), Policy §5 |
| 4 | Added: fastify.decorate('db', ...) and an explicit transaction parameter formally rejected, with reasons | Policy §6 |
| 5 | Added: audit write shown explicitly joining the same transaction as its triggering mutation | A.1, A.10 |
v1.1 — 2026-08-27
Source: Circular_Dependency_Problems.pdf (npm/Node.js circular-dependency reference, submitted for evaluation)
| # | Change | Where |
|---|---|---|
| 1 | Added: engine-to-engine dependencies must be acyclic — real IAM↔Notifications and Entitlements↔Notifications risk identified | Policy §4 |
| 2 | Added: the same acyclic rule applied explicitly to vertical-to-vertical imports | Policy §4 |
| 3 | Added: eslint-plugin-import's no-cycle rule mandated in CI across the whole workspace | Policy §5 |
| 4 | Added: worked example — IAM↔Notifications cycle fixed via published events instead of a reverse import | A.7 (new) |
| 5 | Added: worked example — AMAAR↔Tourism vertical cycle fixed by promoting shared logic to a kernel package | A.8 (new) |
| 6 | Added: full 8-step CI implementation walkthrough (install → configure → CI job → branch protection → pre-commit → safe rollout → verify) | A.9 (new) |
v1.0 — 2026-08-25
Initial policy and Annex A. Status: Proposed, pending Architecture Review Board sign-off.