# NexusCRM Project Analysis Report v1

**Date**: 2026-03-31
**Scope**: 221 GitHub issues + full architecture audit (backend, frontend, metadata, API compat, testing)

---

## Executive Summary

NexusCRM is a metadata-driven Salesforce-compatible CRM (~147K LOC) with a mature architecture foundation. However, **systemic issues across 5 categories** block production readiness:

1. **Page Layout / Form Rendering** — the #1 blocker. Most objects render flat alphabetical fields instead of configured layouts
2. **Metadata Quality** — field labels, picklist values, record types have bootstrap data gaps causing cascading UI issues
3. **API Response Gaps** — UI API ObjectInfo missing critical fields (`childRelationships`, `picklistValues`, `custom`)
4. **Feature Completeness** — Activity tab, Lead Conversion, Approval Actions are missing or broken
5. **Testing/CI** — 18.3% persistence coverage, no lint in CI, no coverage gates, deploy not gated on CI

---

## Part 1: Issues Analysis (221 Issues)

### Distribution by Type

| Type | Count | % |
|------|-------|---|
| Bug | 139 | 63% |
| Missing Feature | 47 | 21% |
| Refactor Needed | 12 | 5% |
| Design Gap | 8 | 4% |
| Architecture Issue | 3 | 1% |
| Testing (missing tests) | 12 | 5% |

### Distribution by Module

| Module | Open | Closed | Total | Key Issues |
|--------|------|--------|-------|------------|
| frontend/form | 18 | 4 | 22 | Layout rendering, field inputs, validation feedback |
| frontend/detail-page | 16 | 2 | 18 | Missing sections, raw HTML, status bars |
| backend/metadata | 15 | 5 | 20 | Labels, pluralization, layout generation, cache |
| backend/api | 12 | 3 | 15 | Approval deploy, flow versions, describe gaps |
| frontend/list-view | 7 | 1 | 8 | Columns, filtering, navigation |
| backend/records | 6 | 3 | 9 | Validation, boolean types, soft delete |
| backend/auth | 5 | 2 | 7 | bcrypt, CSRF, admin password, OAuth creds |
| testing | 18 | 1 | 19 | Missing unit tests across all layers |
| backend/search | 6 | 0 | 6 | SOQL parser gaps, injection risks |
| frontend/approvals | 5 | 0 | 5 | Reassign, hydration, state sync |
| infrastructure | 3 | 3 | 6 | CI failures, deploy, migrations |
| database/metadata | 3 | 1 | 4 | Picklist typos, missing columns |

### Distribution by Priority

| Priority | Count | Examples |
|----------|-------|---------|
| **P0** | 11 | #156 (test OAuth creds in prod), #286 (Quote edit blocked), #300 (Campaign Name missing), #219 (Lead creation blocked), #221 (Lead conversion broken), #264 (Approval creation blocked) |
| **P1** | 72 | Layout rendering, boolean type validation, approval hydration, test failures on main, missing Activity tab |
| **P2** | 94 | Label polish, deduplication, refactoring, SOQL parser edge cases, missing tests |
| Unrated | 44 | Older issues without labels |

---

## Part 2: Issue Clusters (Root Cause Analysis)

### Cluster 1: "Smart Layout" Generator Produces Wrong Layouts (32 issues)

**Root Cause**: `generateSmartLayout()` in `metadata_layouts.go` creates only 4-5 generic sections (Key Info, Address, Description, Details, System) and dumps all fields alphabetically. It does not read configured `_System_PageLayout` entries, producing wrong sections for every object.

**Affected Objects**: Account (#201, #202, #205), Opportunity (#231, #232, #235, #236, #237), Campaign (#296, #301), Quote (#289), Lead (#250), Contract (#84), all others with custom sections.

**Impact**: Every detail page and edit form for every object shows wrong layout. This is the single highest-impact issue cluster.

**Fix Direction**: Ensure configured layouts in `_System_PageLayout` are returned by the layout API. The 3-tier resolution (profile-assigned -> default -> auto-generated) exists but Tier 1/2 are falling through to Tier 3.

### Cluster 2: Field Labels Show Raw API Names (18 issues)

**Root Cause**: Multiple cascading failures:
1. `system_tables.json` has 416 fields missing `label` property (#89)
2. `discover_tables.go` sets Label = ApiName for auto-discovered fields (#88)
3. Frontend has no fallback when `field.label` is empty (#90)
4. Naive `splitCamelCase` produces wrong labels for PascalCase names

**Affected**: #42, #60, #70, #88, #89, #90, #206, #207, #233, #235, #236, #293, #304

**Fix Direction**: Fix label generation in bootstrap (camelCase -> "Camel Case"), add frontend fallback humanizer, backfill `system_tables.json` labels.

### Cluster 3: Boolean/Type Validation Blocks Record Saves (6 issues)

**Root Cause**: `SchemaValidator.validateType()` strictly requires Go `bool` but JSON deserializes `0`/`1` as `float64`. Also `int64` not handled.

**Affected**: #119 (Campaign IsActive), #248 (Opportunity booleans), #252 (Order booleans), #267 (schema_validator)

**Fix Direction**: Add float64/int64 -> bool coercion in `validateType()`. Partially fixed in #248 (CLOSED) but same bug persists for other code paths.

### Cluster 4: Related List Deduplication Missing (6 issues)

**Root Cause**: `augmentLayoutWithRelatedLists()` includes every object with any lookup to the parent without deduplication or system object filtering.

**Affected**: #195 (Account 57 links), #204 (Account duplicates), #232 (Opportunity 23 entries), #238 (Opportunity duplicates)

**Fix Direction**: Add deduplication by target object, filter system objects (Share, FieldHistory, Feed), sort by business relevance.

### Cluster 5: Approval Process Incomplete (14 issues)

**Root Cause**: Approval wizard lacks Actions configuration, step-level criteria, and edit-mode hydration.

**Affected**: #265 (missing Actions), #266 (missing step criteria), #273 (criteria not hydrated), #274 (no validation), #275 (delete bugs), #276-277 (N+1 patterns), #186 (wrong approver field), #290-291 (not pre-populated)

**Fix Direction**: Complete the approval wizard with Initial Submission/Final Approval/Rejection/Recall actions. Fix hydration mapping for edit mode.

### Cluster 6: Quote Workflow Broken End-to-End (9 issues)

**Root Cause**: Quote objects have bootstrap data issues (missing Name, wrong labels, broken validation rules) plus frontend form rendering failures.

**Affected**: #40, #41, #42, #100, #249, #282-289

**Fix Direction**: Fix Quote `_System_PageLayout`, remove/fix broken validation rules, fix AutoNumber exclusion from PATCH payload.

### Cluster 7: Lead Conversion Blocked (5 issues)

**Root Cause**: Frontend sends flat JSON but backend expects `inputs[]` wrapper (#221). Convert button URL case-sensitive (#222). Missing mandatory fields (#223). Approval processes have 0 steps (#225).

**Fix Direction**: Fix request format to match Salesforce Invocable Actions spec. Case-insensitive route matching. Add mandatory fields to Convert modal.

---

## Part 3: Architecture Audit Summary

### Backend Architecture

**Strengths**:
- Fully metadata-driven: no per-object Go structs, all operations flow through generic `PersistenceService`
- Clean hexagonal architecture with port interfaces (12+ repository interfaces)
- COW atomic metadata cache for lock-free reads
- Comprehensive Salesforce REST API route coverage (~85-90% of what frontend needs)

**Critical Issues**:
1. **ServiceManager God Object** — 31 public fields, every handler gets all services
2. **O(N) Record Type Resolution** — `GetRecordType()` scans all objects sequentially
3. **Dual Error Systems** — `pkg/errors` vs `pkg/apierr` inconsistently used
4. **Non-deterministic SQL** — Map iteration in query builder produces different column order
5. **Full metadata cache reload** — Any field change rebuilds entire cache

### Frontend Architecture

**Strengths**:
- Mature metadata-driven rendering (list/detail/form all generic)
- Well-designed UIRegistry plugin pattern for field renderers
- Dual-mode API client (NexusCRM backend + direct Salesforce)
- Smart two-tier data fetching (composite record-ui vs standard REST)

**Critical Issues**:
1. **Field Input Rendering Duplication** — 3 independent switch statements (MetadataRecordForm, UIRegistry, BulkEditModal)
2. **ObjectView God Component** — 427 lines handling list/detail/create/edit for all objects
3. **Incomplete UIRegistry Adoption** — Form layer not migrated to registry pattern
4. **Layout Resolution Untested** — 55-line compatibility memo embedded in component, no unit tests

### Metadata System

**Strengths**:
- `system_tables.json` SSoT with code-generated constants
- Comprehensive `describe` API (40+ field attributes, Salesforce wire format)
- 3-tier layout resolution (profile -> default -> auto-generated)

**Critical Issues**:
1. **Picklist values embedded in JSON** — No first-class entity, no per-RecordType filtering
2. **RecordType-to-Layout mapping rudimentary** — All RTs map to same layout
3. **Dependent picklist always false** — Infrastructure exists but not wired to API
4. **Missing compact layout endpoint** — URL advertised but no handler

### API Compatibility

**Implemented (working)**:
- SObject CRUD, Describe, Layouts, List Views
- SOQL Query, SOSL Search
- Composite, Batch, Tree, Collections
- UI API (record-ui, object-info, layout, record-defaults)
- Approvals, Flows, Analytics, Bulk API
- Tooling API (CustomObject, CustomField, ValidationRule, Flow)
- OAuth 2.0, CometD streaming

**Missing APIs (frontend expects but backend lacks)**:
| API | Impact |
|-----|--------|
| `GET /search/suggestions` | Blocks typeahead search |
| `GET /ui-api/nav-items` | Blocks dynamic navigation |
| `GET /theme` | Blocks object icons/colors |
| Recycle Bin REST routes | Blocks restore/purge (listing works) |
| Chatter Connect API (5 endpoints) | Blocks user profiles, followers |

**Response Format Gaps**:
| Gap | Impact |
|-----|--------|
| UI API ObjectInfo missing `childRelationships` | Affects relationship navigation everywhere |
| UI API ObjectInfo missing `feedEnabled`, `custom` | Frontend feature detection broken |
| UI API FieldInfo missing `picklistValues` | Picklist rendering from UI API broken |
| UI API FieldInfo missing `calculated`, `filterable`, `sortable` | Field behavior flags unavailable |

### Testing & Quality

| Metric | Current | Target |
|--------|---------|--------|
| Backend unit test coverage | Variable (0%-100%) | >70% for critical paths |
| Frontend test coverage | 11.6% file coverage | >30% |
| `infrastructure/persistence` | 18.3% | >50% (highest risk) |
| `pkg/formula` | 34.9% (23 importers) | >70% |
| `interfaces/rest` | 46.4% | >60% |
| CI lint enforcement | None | golangci-lint in CI |
| Coverage tracking | None | Codecov + thresholds |
| Deploy gate | Not gated on CI | Require CI pass |

---

## Part 4: Priority Ranking

### Tier 0: Blocks Everything (Fix This Week)

| # | Issue | Why It Blocks |
|---|-------|---------------|
| 1 | **Fix layout resolution** (Cluster 1) | Every object renders wrong. Smart layout fallback should be last resort, not default. Issues: #201, #231, #250, #289, #296, #301 |
| 2 | **Enrich UI API ObjectInfo** | Missing `childRelationships`, `picklistValues`, `custom`, `feedEnabled` breaks metadata-driven rendering for all objects |
| 3 | **Fix boolean type validation** (Cluster 3) | Blocks saves for Campaign, Order, Opportunity, any object with checkboxes. Issues: #119, #248, #252, #267 |
| 4 | **P0 Security: test OAuth creds in prod** (#156) | `system_data.go` seeds hardcoded `test-gosf-client`/`test-gosf-secret-123` in ALL environments |

### Tier 1: Blocks Key Workflows (Fix in 2 Weeks)

| # | Issue | Why It Blocks |
|---|-------|---------------|
| 5 | **Fix field label generation** (Cluster 2) | 416+ fields show raw API names. Fix bootstrap + add frontend fallback |
| 6 | **Complete Lead Conversion** (Cluster 7) | End-to-end lead workflow blocked. Fix request format, URL casing, mandatory fields |
| 7 | **Fix Quote workflow** (Cluster 6) | Quote create/edit/list all broken. Fix validation rules, layout, AutoNumber exclusion |
| 8 | **Add Activity tab** (#183, #194) | Missing from Opportunity and Contact, blocks entire engagement workflow |
| 9 | **Fix related list deduplication** (Cluster 4) | 57 duplicated links on Account, 23 on Opportunity |
| 10 | **Fix error feedback** (#168, #220) | No toast/message when saves fail. Users see no feedback on any 400 error |

### Tier 2: Blocks Feature Completeness (Fix in 1 Month)

| # | Issue | Why It Blocks |
|---|-------|---------------|
| 11 | **Complete Approval Wizard** (Cluster 5) | Missing Actions config, step criteria, edit hydration |
| 12 | **Add RecordType-to-Layout mapping** | All RTs share same layout, blocking business process customization |
| 13 | **Create `_System_PicklistValue` table** | Embedded JSON blocks per-RT filtering, deactivation, Global Value Sets |
| 14 | **Fix Form rendering via UIRegistry** | Unify 3 duplicate switch statements into single registry |
| 15 | **Add missing API endpoints** | Search suggestions, nav-items, theme, recycle bin REST |

### Tier 3: Engineering Health (Ongoing)

| # | Issue | Why It Matters |
|---|-------|---------------|
| 16 | **Add golangci-lint to CI** | Config exists, not enforced |
| 17 | **Add coverage reporting** | No visibility into regression |
| 18 | **Gate deploy on CI** | Broken builds can deploy |
| 19 | **Split ServiceManager** | 31-field god object hurts testability |
| 20 | **Unify error handling** | Dual error systems cause silent 500s |
| 21 | **Adopt mock generation** | Hand-rolled mocks in 30+ files |
| 22 | **Add versioned migration framework** (#182) | Bootstrap fixups accumulate |
| 23 | **Increase persistence test coverage** | 18.3% on largest, most critical package |

---

## Part 5: Full Issues Table

### Batch 1: Issues #33-63

| Issue # | Title | State | Module | Type | Priority | Summary |
|---------|-------|-------|--------|------|----------|---------|
| 33 | Approval Step 'Specific User' approver field is not selectable | CLOSED | frontend/form | bug | P0 | Approver Name field is plain text, no user lookup integration |
| 34 | 4 bugs in LeadQuicklySet - V3 flow replica vs Salesforce | CLOSED | backend/flow-executor | bug | bug | IsNull operator inverted, wrong casing, null as string, snake_case value |
| 36 | IsNull operator missing boolean Value input in Flow Condition Builder | CLOSED | frontend/flow-builder | bug | P1 | IsNull classified as unary, Value input hidden |
| 37 | Remove or rebrand Salesforce logo/badge from top nav | CLOSED | frontend/navigation | design-gap | P2 | Salesforce badge shown in Backend mode |
| 38 | Data sync mismatches - Campaign_Member_Key_Message_Update flow | CLOSED | frontend/flow-builder | bug | P0 | Wrong Optimize value, wrong Condition Requirements, empty panel |
| 39 | Opportunity detail page shows 'No page layout assigned' | CLOSED | backend/metadata | bug | P1 | No fields or related lists rendered |
| 40 | Quote list view shows 0 records despite 882 in analytics | CLOSED | frontend/list-view | bug | P1 | Default columns are system fields |
| 41 | Quote record title shows raw UUID instead of Quote Number | CLOSED | backend/records | bug | P1 | Auto-numbering not working |
| 42 | Quote form displays raw API field names | CLOSED | backend/metadata | bug | P1 | Underscored names instead of labels |
| 43 | Approval Chain fails to load - 'expected FROM' SOQL error | CLOSED | backend/soql-parser | bug | P0 | Subquery parsing fails silently |
| 44 | Approval Queue badge count does not sync | CLOSED | frontend/approvals | bug | P1 | Separate state systems for badge vs page |
| 45 | No 'Create Quote' button on Opportunity detail | CLOSED | frontend/detail-page | missing-feature | P1 | Key Salesforce workflow gap |
| 46 | Missing modules analysis - 11 open issues | CLOSED | architecture | architecture-issue | P0 | 6 root-cause gaps identified |
| 47 | Lead Status path/progress bar missing | OPEN | frontend/detail-page | missing-feature | P2 | No pipeline stage visualization |
| 55 | Approver picker chip shows raw Username | OPEN | frontend/approvals | bug | P2 | Email shown instead of display name |
| 56 | processAction has no ActorId authorization | CLOSED | backend/auth | bug | P0 | Any user can approve any WorkItem |
| 58 | Wrap Recall mutations in RunInTransaction | OPEN | backend/approvals | refactor-needed | P2 | 3 mutations without transaction |
| 59 | Fix indentation in approval_handler.go | OPEN | backend/approvals | refactor-needed | P2 | Cosmetic indentation mismatch |
| 60 | Flow Label column displays API Name instead of MasterLabel | OPEN | backend/api | bug | P1 | MasterLabel not mapped correctly |
| 61 | Campaign Edit Form layout does not match Salesforce | OPEN | frontend/form | bug | P1 | Flat alphabetical grid, no sections |
| 63 | List view filters do not filter records | OPEN | backend/api | bug | P1 | Malformed SOQL, silent failure |

### Batch 2: Issues #70-105

| Issue # | Title | State | Module | Type | Priority | Summary |
|---------|-------|-------|--------|------|----------|---------|
| 70 | Sidebar nav shows API names instead of object labels | CLOSED | frontend/sidebar | bug | P2 | Raw API names in navigation |
| 73 | Validation rule fails with unknown INCLUDES function | CLOSED | backend/formula-engine | bug | P0 | INCLUDES not merged to main |
| 77 | Trigger and Object columns blank in Flows list | OPEN | backend/api | bug | P2 | Fields not queried/mapped |
| 78 | Flow List -- Filter Panel missing | OPEN | frontend/flows | missing-feature | P2 | No filter panel like Salesforce |
| 81 | Contract record title displays raw UUID | OPEN | backend/records | bug | P1 | Auto-numbering not working for Contract |
| 82 | New Contract: Missing Record Type dialog | CLOSED | frontend/form | bug | P0 | Must type Record Type ID manually |
| 83 | New Contract saves with all fields empty | OPEN | backend/records | bug | P1 | No required field validation |
| 84 | Contract detail missing status progress bar | OPEN | frontend/detail-page | missing-feature | P1 | No status bar, no upload buttons |
| 86 | Account list 500 error when sorting by CreatedDate | CLOSED | backend/api | bug | P1 | camelCase vs snake_case column mapping |
| 87 | Contact edit form doesn't save changes | CLOSED | frontend/form | bug | P1 | Changes not persisted |
| 88 | Field discovery sets Label = API Name | CLOSED | backend/metadata | bug | P1 | Raw column names in UI |
| 89 | 416 fields missing 'label' in system_tables.json | CLOSED | backend/metadata | bug | P2 | Fallback derivation fails for PascalCase |
| 90 | Frontend has no fallback when field label is empty | OPEN | frontend/form | bug | P2 | Blank headers and form labels |
| 91 | Flow Save As New Version does not generate new version | OPEN | backend/api | bug | P1 | No version created, no deactivation |
| 100 | Quote creation blocked by broken validation rule | CLOSED | backend/metadata | bug | P0 | References non-existent Partner_Margin__c |
| 101 | Frontend version.json not bumped in deployment | CLOSED | infrastructure | bug | P2 | Version polling broken |
| 102 | Quote fixes pass locally but fail on staging | CLOSED | infrastructure | design-gap | P0 | DB changes not promoted |
| 104 | Add unit tests for Sidebar component | OPEN | testing/frontend | missing-feature | P2 | Zero test coverage |
| 105 | Add unit tests for ConditionValuePill | OPEN | testing/frontend | missing-feature | P2 | Zero test coverage |

### Batch 3: Issues #106-131

| Issue # | Title | State | Module | Type | Priority | Summary |
|---------|-------|-------|--------|------|----------|---------|
| 106 | Add tests for Sidebar badge count and usePendingApprovals | OPEN | testing/frontend | missing-feature | P2 | Zero test coverage |
| 110 | Display picklist label instead of raw value in ConditionValuePill | OPEN | frontend/form | bug | P2 | Raw values shown in flow builder |
| 112 | Validate RecordTypeId on record creation endpoint | OPEN | backend/records | missing-feature | P2 | No validation of RecordTypeId |
| 113 | Add cache invalidation for ObjectInfo record type data | OPEN | backend/metadata | bug | P2 | Stale data until server restart |
| 114 | Update DescribeLayouts to return real record types | OPEN | backend/api | missing-feature | P2 | Only Master RT mapped |
| 115 | Clean up duplicate Contract field records | OPEN | backend/metadata | bug | P2 | ID mismatch causes duplicates |
| 118 | Campaign: Name field missing from New/Edit form | OPEN | frontend/form | missing-feature | P1 | Campaigns created without names |
| 119 | Campaign: Edit fails - IsActive sends float64 | OPEN | backend/records | bug | P1 | Boolean type mismatch |
| 120 | Campaign: Duplicate Edit/Delete buttons, Owner shows UUID | OPEN | frontend/detail-page | bug | P2 | Duplicate buttons, raw UUID |
| 121 | Campaign Member Status: Form title shows object description | OPEN | backend/metadata | bug | P2 | Wrong label fallback |
| 125 | Populate RecordType.IsDefault from database | OPEN | backend/metadata | missing-feature | P2 | Dead code in describe |
| 126 | Map record types to distinct page layouts | OPEN | backend/api | missing-feature | P2 | All RTs share same layout |
| 127 | Add unit tests for bootstrap reconciliation | OPEN | testing/backend | missing-feature | P2 | Zero coverage for DDL/DELETE ops |
| 128 | Extract duplicated splitCamelCase | OPEN | backend/metadata | refactor-needed | P2 | Identical logic in 2 files |
| 129 | Replace hardcoded "_System_Field" with constant | OPEN | backend/metadata | bug | P2 | Violates SSoT principle |
| 130 | Fix naive PluralLabel computation | OPEN | backend/metadata | bug | P2 | "CampaignMemberStatuss" |
| 131 | Add unit tests for label-fallback logic | OPEN | testing/backend | missing-feature | P2 | Root cause of #121 untested |

### Batch 4: Issues #132-158

| Issue # | Title | State | Module | Type | Priority | Summary |
|---------|-------|-------|--------|------|----------|---------|
| 132 | Harden bcrypt detection heuristic | OPEN | backend/auth | bug | P2 | Too-broad prefix check |
| 134 | Filter auto-generated layouts in addFieldToLayout | OPEN | backend/metadata | bug | P2 | Custom fields added to wrong layout |
| 135 | Add unit tests for recordUtils.ts | OPEN | frontend/util | missing-feature | P2 | 6 functions, zero tests |
| 138 | Enforce minimum bcrypt cost factor | OPEN | backend/auth | bug | P1 | Low-cost hash bypass |
| 139 | Verify authorization gate on password field writes | OPEN | backend/auth | design-gap | P1 | Relies on middleware only |
| 142 | Add aggregate function allowlist for ORDER BY | OPEN | backend/search | missing-feature | P2 | No function validation |
| 143 | Extract shared ORDER BY parser | OPEN | backend/search | refactor-needed | P2 | Duplicated parsing logic |
| 144 | Add unit tests for ensureStandardAutoNumbers | OPEN | backend/metadata | missing-feature | P2 | Zero coverage for DB ops |
| 145 | Parameterize table name in discover_tables.go | OPEN | backend/metadata | bug | P2 | fmt.Sprintf for table name |
| 146 | Clean up dead SQL pluralization logic | CLOSED | backend/metadata | refactor-needed | P2 | Dead code after PR #410 |
| 147 | Fix naive pluralization in buildObjectMetadata | OPEN | backend/metadata | bug | P2 | "Addresss", "Activitys" |
| 148 | Document SQL/Go pluralization equivalence | CLOSED | backend/metadata | refactor-needed | P2 | Implicit case handling |
| 149 | Support consonant doubling (Quiz -> Quizzes) | OPEN | backend/metadata | bug | P2 | "Quizes" instead of "Quizzes" |
| 150 | Campaign Name field: wrong IsSystem, missing Required | CLOSED | database/metadata | bug | P2 | Hidden field, no validation |
| 151 | Subquery SELECT does not parse function calls | OPEN | backend/search | bug | P2 | COUNT(Id) in subquery fails |
| 152 | Extend function allowlist to WHERE clauses | OPEN | backend/search | missing-feature | P2 | No validation in WHERE |
| 156 | Gate test Connected App credentials behind env check | OPEN | backend/auth | bug | P0 | Hardcoded creds in all envs |
| 157 | CSRF token returns empty string on rand failure | OPEN | backend/auth | bug | P2 | Violates fail-fast |
| 158 | Add max-depth guard for nested SOQL functions | OPEN | backend/search | bug | P2 | Unbounded recursion |

### Batch 5: Issues #159-185

| Issue # | Title | State | Module | Type | Priority | Summary |
|---------|-------|-------|--------|------|----------|---------|
| 159 | Inconsistent error types in SOQL subquery parser | OPEN | backend/api | bug | P2 | fmt.Errorf vs NewValidationError |
| 160 | Parameterize ORDER BY to prevent SQL injection | OPEN | backend/records | bug | P1 | Direct interpolation in SQL |
| 161 | Add DISTANCE/GEOLOCATION to SOQL function allowlist | OPEN | backend/api | missing-feature | P2 | Geo queries rejected |
| 162 | Surface DB errors from GetRecordTypes | OPEN | backend/records | bug | P2 | Swallowed errors, misleading 400s |
| 163 | Hoist validatePolymorphicLookups outside BulkInsert loop | OPEN | backend/records | bug | P1 | O(N) redundant DB round-trips |
| 164 | parseFunctionCall doesn't validate nested functions | OPEN | backend/api | bug | P2 | Nested bypass of allowlist |
| 165 | Add depth guard to parseCallExpression | OPEN | backend/api | bug | P2 | Recursive descent, no limit |
| 166 | Flip admin password gate from denylist to allowlist | CLOSED | backend/auth | bug | P1 | Unknown env uses seed password |
| 167 | Add unit tests for InitializeSystemData | OPEN | testing | missing-feature | P2 | Zero coverage |
| 168 | 'Create Quote' button fails silently | OPEN | frontend/detail-page | bug | P1 | No error toast on 400 |
| 169 | Quote detail page missing status progress bar | OPEN | frontend/detail-page | missing-feature | P2 | No visual status indicator |
| 170 | TestMetadataService_GetLayout returns wrong layout ID | OPEN | testing | bug | P1 | Test fixture drift |
| 171 | TestMetadataService_GetLayout includes system field | OPEN | testing | bug | P1 | CreatedDate in fallback layout |
| 172 | TestRecordRepository_Integration fails: Unknown column | OPEN | testing | bug | P1 | Missing migration |
| 173 | Externalize hardcoded test Connected App credentials | OPEN | backend/auth | design-gap | P2 | Security smell |
| 174 | Hard-fail admin password in production when env var unset | OPEN | backend/auth | bug | P1 | Seed password in prod |
| 175 | Contract tests fail: Unknown column CreatedDate | OPEN | database | bug | P1 | Missing column in Notification table |
| 176 | 8 frontend test files fail on main | OPEN | testing | bug | P1 | Tailwind v4, missing deps |
| 177 | Add GetAllAutoNumbers stub to test mocks | OPEN | testing | bug | P2 | go vet compile errors |
| 178 | Replace deprecated VALUES() syntax in bootstrap | OPEN | database | bug | P2 | Deprecated in MySQL 8.0.20 |
| 179 | ChangePasswordModal sends lowercase `password` key | OPEN | frontend/form | bug | P2 | Field name mismatch |
| 180 | Add UNIQUE constraint on flow versions | OPEN | database | bug | P2 | Duplicate versions possible |
| 181 | Add GetMaxVersionNumber repo method | OPEN | backend/metadata | refactor-needed | P2 | Full-row fetch for max |
| 182 | Add versioned migration framework | OPEN | infrastructure | design-gap | P2 | No migration tracking |
| 183 | Opportunity/Contact missing 'Activity' tab | OPEN | frontend/detail-page | missing-feature | P0 | Blocks engagement workflow |
| 184 | Flow Builder canvas does not render nodes | OPEN | frontend/detail-page | bug | P1 | Empty canvas |
| 185 | Flow list search does not filter results | OPEN | frontend/list-view | bug | P2 | Search has no effect |

### Batch 6: Issues #186-210

| Issue # | Title | State | Module | Type | Priority | Summary |
|---------|-------|-------|--------|------|----------|---------|
| 186 | Approval hydration uses Name instead of Username for XML | OPEN | frontend/form | bug | P2 | Wrong field in XML generation |
| 187 | Add unit tests for approval wizard components | OPEN | frontend/form | missing-feature | P2 | Zero coverage |
| 188 | Add unit tests for flow condition builder | OPEN | frontend/form | missing-feature | P2 | Zero coverage |
| 189 | Add FlowMapper test for IsNull with false | OPEN | frontend/form | missing-feature | P2 | Missing test path |
| 190 | Non-deterministic SQL column ordering in upsert | OPEN | backend/records | bug | P2 | Map iteration order |
| 191 | BatchUpsertProfiles includes no-op Id self-update | CLOSED | backend/metadata | bug | P2 | Unnecessary self-assignment |
| 192 | Replace LOWER() with case-insensitive collation | OPEN | backend/records | refactor-needed | P2 | Prevents index usage |
| 193 | Add integration tests for multi-RT DescribeLayouts | CLOSED | backend/metadata | missing-feature | P1 | Zero coverage |
| 194 | Missing Activity tab on Opportunity/Contact | OPEN | frontend/detail-page | missing-feature | P0 | Blocks engagement workflow |
| 195 | Account Quick Links: 57 unsorted links with duplicates | OPEN | backend/metadata | bug | P2 | Massive duplication |
| 196 | Add unit tests for BatchUpsert SQL generation | OPEN | backend/metadata | missing-feature | P2 | Zero coverage |
| 197 | Add component tests for MetadataRecordDetail | OPEN | frontend/detail-page | missing-feature | P2 | Zero coverage (470 lines) |
| 198 | Remove or wire up dead standard_layouts.json | OPEN | backend/metadata | refactor-needed | P2 | Dead code |
| 199 | E2E/Integration CI suites fail on main | CLOSED | infrastructure | bug | P1 | Backend health check fails |
| 200 | Fix trailing space in ActionConditionBuilder label | OPEN | frontend/form | bug | P2 | Whitespace in labels |
| 201 | Account Layout: Missing custom sections | OPEN | backend/metadata | bug | P1 | Only 5 generic sections |
| 202 | Account Layout: ~70 custom fields not in system_tables.json | OPEN | backend/metadata | design-gap | P1 | Fields lost on schema recreation |
| 203 | Account Files related list shows entity error | OPEN | backend/records | bug | P2 | AttachedContentDocument not registered |
| 204 | Account Quick Links: Duplicates and system objects | OPEN | backend/metadata | bug | P1 | No deduplication or filtering |
| 205 | Account Custom fields misclassified into wrong sections | OPEN | backend/metadata | bug | P2 | Pattern-based classifier wrong |
| 206 | Field label '*AnnualRevenue' displays with asterisk | OPEN | backend/metadata | bug | P2 | Asterisk in label |
| 207 | 'S1/S2/S3/S4 Response in' labels truncated | OPEN | backend/metadata | bug | P2 | Missing 'Hours' |
| 208 | Approval Queue Record column shows "Unknown" | OPEN | backend/api | bug | P1 | No record name hydration |
| 209 | Approval Queue Object column shows "Record" | OPEN | backend/api | bug | P1 | No object type resolution |
| 210 | Approval Queue Comments shows "---" | OPEN | backend/api | bug | P2 | Comments not returned |

### Batch 7: Issues #211-237

| Issue # | Title | State | Module | Type | Priority | Summary |
|---------|-------|-------|--------|------|----------|---------|
| 211 | Reassign dialog does not open in Approval Queue | OPEN | frontend/approvals | bug | P1 | User picker never appears |
| 212 | ApprovalProcessSetupWizard tests fail on main | OPEN | testing/frontend | bug | P1 | Async rendering issues |
| 213 | Contract test scripts missing Origin header | OPEN | testing/contract | bug | P1 | Cascading 403 failures |
| 214 | DescribeObject demotes Master default before filtering | OPEN | backend/metadata | bug | P2 | Zero defaults possible |
| 215 | Fix rows field in layout sections | OPEN | backend/metadata | bug | P2 | Wrong metadata value |
| 216 | Add warning log when GetAllLayouts fails | OPEN | backend/metadata | bug | P2 | Silently swallowed error |
| 217 | Parameterize SQL in contract test scripts | OPEN | testing/contract | bug | P2 | SQL interpolation |
| 218 | Move contract test scripts to proper directory | OPEN | testing/contract | refactor-needed | P2 | Wrong location |
| 219 | Lead creation blocked by validation rule | CLOSED | backend/records | bug | P0 | IsConverted unavailable on INSERT |
| 220 | Lead creation form fails silently | OPEN | frontend/form | bug | P1 | No error toast on 400 |
| 221 | Lead conversion fails: flat object vs inputs array | OPEN | frontend/api | bug | P0 | Request format mismatch |
| 222 | Convert button missing due to URL casing | OPEN | frontend/detail-page | bug | P1 | /lead/ vs /Lead/ |
| 223 | Convert Lead modal missing mandatory fields | OPEN | frontend/form | missing-feature | P1 | Only 3 fields shown |
| 224 | Lead Status picklist typo: 'No Enagement' | OPEN | database/metadata | bug | P2 | Missing 'g' |
| 225 | Lead Convert Approval processes have 0 steps | OPEN | database/metadata | missing-feature | P1 | No Ops/Legal review |
| 226 | Add unit tests for approvalsAPI.reassign/reject | OPEN | testing/frontend | missing-feature | P2 | Zero coverage |
| 227 | Add component tests for ReassignModal | OPEN | testing/frontend | missing-feature | P2 | Zero coverage |
| 228 | TestSystemHandler_DescribeLayouts fails on main | OPEN | testing/backend | bug | P1 | Consistent CI failure |
| 229 | ReassignModal user search missing IsActive filter | OPEN | frontend/approvals | bug | P1 | Inactive users shown |
| 230 | ReassignModal doesn't reset search state on close | OPEN | frontend/approvals | bug | P2 | Stale state on reopen |
| 231 | Opportunity Layout: Missing 15 custom sections | CLOSED | backend/metadata | bug | P1 | Fields dumped into 4 buckets |
| 232 | Opportunity Quick Links: 23 entries with duplicates | OPEN | backend/metadata | bug | P1 | System objects exposed |
| 233 | Opportunity: Raw HTML tags in rich text fields | OPEN | frontend/detail-page | bug | P1 | `<p>Eddy</p>` shown literally |
| 234 | CreateFlowVersion INSERT omits MasterLabel | OPEN | backend/api | bug | P2 | Label silently dropped |
| 235 | Opportunity: Asterisk-prefixed field labels | OPEN | backend/metadata | bug | P2 | *EvaluatioDwellTime |
| 236 | Opportunity: Non-humanized field labels | OPEN | backend/metadata | bug | P2 | OriginalOpportunity |
| 237 | Opportunity: Duplicate fields displayed | OPEN | backend/metadata | bug | P2 | Forecast Category x2 |

### Batch 8: Issues #238-265

| Issue # | Title | State | Module | Type | Priority | Summary |
|---------|-------|-------|--------|------|----------|---------|
| 238 | Opportunity Related Lists: Duplicates | OPEN | backend/metadata | bug | P2 | No deduplication |
| 239 | UpdateFlowVersion omits MasterLabel | OPEN | backend/api | bug | P2 | Label changes dropped |
| 240 | Add tests for FlowVersion Hydrate/Serialize | OPEN | testing | missing-feature | P1 | Critical pure functions untested |
| 241 | Add happy-path handler tests for Flow Tooling API | OPEN | testing | missing-feature | P2 | Only 401 paths tested |
| 242 | escapeSoqlValue doesn't escape LIKE wildcards | OPEN | frontend/form | bug | P2 | Broader-than-intended matches |
| 243 | ShareRecordModal missing IsActive filter on Groups | OPEN | frontend/form | bug | P2 | Deactivated groups shown |
| 244 | Raw backend error messages displayed to users | OPEN | frontend/form | bug | P2 | Stack traces in toasts |
| 245 | Profile-ObjectPermissions association broken | OPEN | backend/auth | bug | P1 | Non-admin users DENY ALL |
| 247 | Case-insensitive table name lookup missing | OPEN | backend/metadata | bug | P2 | Missed columns |
| 248 | Boolean fields reject numeric values on update | CLOSED | backend/api | bug | P1 | float64 vs bool |
| 249 | Quote creation blocked by validation rule | CLOSED | backend/metadata | bug | P0 | Partner_Margin__c missing |
| 250 | Lead Page Layouts API returns null | OPEN | backend/metadata | bug | P1 | Setup UI broken |
| 251 | Lead Validation Rules API returns null | OPEN | backend/metadata | bug | P1 | Setup UI broken |
| 252 | Order Edit form fails - boolean float64 | OPEN | backend/api | bug | P1 | Same as #248 |
| 253 | Order Status not updated after approval | OPEN | backend/api | bug | P2 | Approval has no effect |
| 254 | Approval Chain history cleared after approval | OPEN | frontend/detail-page | bug | P2 | Audit trail lost |
| 255 | OP order contract not Effective after approval | OPEN | backend/api | bug | P2 | Wrong lifecycle transition |
| 256 | 'Upload Archived OF' button missing from Order | OPEN | frontend/detail-page | missing-feature | P2 | Archiving workflow blocked |
| 257 | Order Type picklist shows 'Metadata Error' | OPEN | backend/metadata | bug | P2 | No picklist values defined |
| 258 | Validation rules crash on unrelated stage changes | CLOSED | backend/api | bug | P1 | LEN/UPPER/LOWER crash on null |
| 259 | Lead List View column picker shows Selected(0) | OPEN | frontend/list-view | bug | P2 | State desync |
| 260 | Add chunking for Composite API 25-subrequest limit | OPEN | frontend/api | missing-feature | P2 | Exceeds limit for 50+ objects |
| 261 | Missing encodeURIComponent on record Id in Composite | OPEN | frontend/api | bug | P2 | No defense-in-depth |
| 262 | ProfileManager doesn't refetch after save | OPEN | frontend/detail-page | bug | P2 | Manual refresh needed |
| 263 | Add unit tests for users API module | OPEN | testing | missing-feature | P2 | Zero coverage |
| 264 | Approval Process creation fails - AllowComments missing | CLOSED | backend/metadata | bug | P0 | Columns missing from schema |
| 265 | Approval wizard missing Actions configuration | OPEN | frontend/form | missing-feature | P1 | No Initial/Final/Recall actions |

### Batch 9: Issues #266-290

| Issue # | Title | State | Module | Type | Priority | Summary |
|---------|-------|-------|--------|------|----------|---------|
| 266 | Approval Step form missing step-level Entry Criteria | CLOSED | frontend/form | missing-feature | P1 | No conditional routing |
| 267 | Boolean type switch missing int/int64 inputs | OPEN | backend/metadata | bug | P2 | Inconsistent with ValidationService |
| 268 | Add int64 test for boolean coercion | OPEN | testing | missing-feature | P2 | Untested branch |
| 269 | coerceForFormulaEval mutates caller's record map | OPEN | backend/metadata | bug | P2 | In-place mutation, synthetic key injection |
| 270 | regexp.MatchString recompiles regex every call | OPEN | backend/metadata | refactor-needed | P2 | Unnecessary overhead |
| 271 | Add happy-path tests for approval deploy handler | OPEN | testing | missing-feature | P1 | Zero happy-path coverage |
| 272 | Add enum validation for RejectBehavior field | OPEN | backend/metadata | missing-feature | P2 | Accepts arbitrary strings |
| 273 | Approval step criteria not hydrated in edit mode | OPEN | frontend/form | bug | P1 | Criteria silently dropped |
| 274 | No validation for incomplete criteria in wizard | OPEN | frontend/form | bug | P2 | Empty XML tags generated |
| 275 | ProcessNode delete: silent skip + unchecked assertion | OPEN | backend/api | bug | P1 | Can panic on nil |
| 276 | N+1 delete in approval deploy ProcessNode cleanup | OPEN | backend/api | refactor-needed | P2 | Individual DELETE per row |
| 277 | N+1 user resolution in approval deploy | OPEN | backend/api | refactor-needed | P2 | SELECT per step |
| 278 | Add test for _has_prior_=false validation path | OPEN | testing | missing-feature | P2 | New-record path untested |
| 279 | Add unit tests for searchSingleObject | OPEN | testing | missing-feature | P1 | Zero coverage |
| 280 | ApprovalProcessDetailPage tests fail on main | OPEN | testing | bug | P1 | Outdated mock |
| 281 | REST integration tests fail on main | OPEN | testing | bug | P1 | Consistent CI failure |
| 282 | Quote Number column appears twice | OPEN | frontend/list-view | bug | P2 | Duplicate column |
| 283 | Quote Columns button produces no dialog | OPEN | frontend/list-view | bug | P1 | Column picker broken |
| 284 | Quote Record Type "Next" button has no effect | OPEN | frontend/form | bug | P1 | Blocks creation |
| 285 | Quote row click doesn't navigate to detail | OPEN | frontend/list-view | bug | P1 | List-view infra issue |
| 286 | Quote Edit Save fails - AutoNumber in payload | OPEN | frontend/form | bug | P0 | Completely blocks editing |
| 287 | Quote Name blank, Account not linked after creation | OPEN | backend/records | bug | P1 | Data integrity broken |
| 288 | Quote 'Upload Files' button missing | OPEN | frontend/detail-page | missing-feature | P1 | Attachment workflow blocked |
| 289 | Quote Edit form: 100+ fields alphabetically | OPEN | frontend/form | bug | P1 | Root cause of #286 |
| 290 | Edit Approval: Approvers not pre-populated | OPEN | frontend/form | bug | P1 | Must re-enter all approvers |

### Batch 10: Issues #291-304

| Issue # | Title | State | Module | Type | Priority | Summary |
|---------|-------|-------|--------|------|----------|---------|
| 291 | Edit Approval: Description/Entry Criteria not loaded | OPEN | frontend/form | bug | P1 | Risk of silent data loss |
| 292 | Edit Approval: Approver shows raw Chatter ID | CLOSED | backend/api | bug | P2 | Internal ID instead of name |
| 293 | Campaign Detail: Raw API names for labels | OPEN | backend/metadata | bug | P2 | DB fix not taking effect |
| 294 | Campaign Detail: Raw email for Owner/Created By | OPEN | backend/records | bug | P1 | RelationshipName fix not applied |
| 295 | Campaign Detail: Highlights panel not rendered | OPEN | frontend/detail-page | bug | P1 | Compact layout missing |
| 296 | Campaign Detail: Missing PLANNING/STATISTICS sections | OPEN | frontend/detail-page | bug | P2 | Collapsed into generic section |
| 297 | Campaign Detail: Currency shows USD instead of CNY | CLOSED | frontend/detail-page | bug | P2 | Hardcoded USD |
| 298 | Campaign Detail: Clone action missing | OPEN | frontend/detail-page | missing-feature | P2 | Share shown instead |
| 299 | searchSingleObject missing try/catch | OPEN | frontend/search | bug | P2 | Inconsistent error contract |
| 300 | New Campaign: Name field missing | OPEN | frontend/form | bug | P0 | Nameless campaigns, UUID titles |
| 301 | New Campaign: Ignores page layout | OPEN | frontend/form | bug | P1 | Auto-generated flat form |
| 302 | New Campaign: Owner not pre-populated | OPEN | frontend/form | bug | P1 | Empty instead of current user |
| 303 | New Campaign: Status/Type have no defaults | OPEN | frontend/form | bug | P1 | Null Status/Type allowed |
| 304 | New Campaign: Labels don't match SFDC | OPEN | backend/metadata | bug | P2 | Raw labels, same as #293 |

---

## Appendix: Architecture Audit Details

Full architecture audit reports from 5 specialized agents are available. Key references:

- **Backend Architecture**: ServiceManager god object (31 fields), O(N) record type resolution, dual error systems, non-deterministic SQL, full cache reload
- **Frontend Architecture**: Field input duplication (3 switch statements), ObjectView god component (427 lines), incomplete UIRegistry adoption, untested layout resolution
- **Metadata System**: Embedded picklist JSON, rudimentary RT-to-layout mapping, dependent picklist always false, missing compact layout endpoint
- **API Compatibility**: 85-90% endpoint coverage, 6 missing endpoint groups, UI API ObjectInfo missing 5+ critical fields
- **Testing & Quality**: 18.3% persistence coverage, no lint in CI, no coverage gates, deploy not gated on CI, hand-rolled mocks in 30+ files
