Some checks are pending
Bidi Control Character Guard / bidi-control-guard (push) Waiting to run
Circular Dependency Check / Check for new circular dependencies (push) Waiting to run
Citus Migration Smoke / Combined migrations on single-node Citus (push) Waiting to run
E2E Fresh Install Tests / fresh-install-e2e (push) Waiting to run
ext-v2 guardrails / Run ext-v2 guard and ESLint (push) Waiting to run
Integration Tests / Check for relevant changes (push) Waiting to run
Integration Tests / ${{ (github.event_name == 'schedule' || github.event.inputs.suite == 'full') && 'Full integration suite' || 'Tier-1 integration subset' }} (push) Blocked by required conditions
Mobile checks / Mobile lint + typecheck (push) Waiting to run
Mobile checks / Mobile unit tests (push) Waiting to run
Mobile checks / Mobile dependency audit (report) (push) Waiting to run
Mobile checks / Mobile reproducibility checks (push) Waiting to run
Secrets guard (env backups) / Ensure no tracked env backup files (push) Waiting to run
Temporal Readiness / fast-readiness (push) Waiting to run
Temporal Readiness / docker-parity (push) Waiting to run
TypeScript Type Check / Nx affected typecheck (push) Waiting to run
Unit Tests / Skipped-test budget (push) Waiting to run
Unit Tests / Nx affected unit tests (push) Waiting to run
Unit Tests / Server unit coverage (informational) (push) Waiting to run
Validate Tenant Management Schema / Check for relevant changes (push) Waiting to run
Validate Tenant Management Schema / Validate Tenant Management Schema (push) Blocked by required conditions
EE Workflows Build Guard / ee-workflows-build-guard (push) Waiting to run
Excluded: .git, node_modules, secrets/, compose.env, assemblyscript tgz Source: /opt/alga-psa on psa.joliet.tech
214 lines
16 KiB
Markdown
214 lines
16 KiB
Markdown
# Scratchpad: Stale Code Quick Wins
|
|
|
|
## Key Discoveries
|
|
|
|
### Media package exists for a reason that no longer applies
|
|
|
|
The `@alga-psa/media` package was created to break the cycle `documents -> users -> media -> documents`. This cycle was resolved and removed from the known-cycles baseline. The media package's dynamic import workarounds (`getStorageServiceAsync()`, `deleteDocumentAsync()`, `getDocumentTypeIdAsync()`) are no longer needed -- the canonical `documents/lib/entityImageService.ts` uses direct imports to `@alga-psa/storage/StorageService` and internal `documentActions`.
|
|
|
|
### Three copies of avatarUtils exist
|
|
|
|
1. `@alga-psa/formatting/avatarUtils.ts` (228 LOC) -- uses `getImageUrlInternal` from `./imageUrl.ts`
|
|
2. `@alga-psa/user-composition/lib/avatarUtils.ts` (~95 LOC) -- has its own `getImageUrlInternalLite` inline
|
|
3. `@alga-psa/media/lib/avatarUtils.ts` (87 LOC) -- uses dynamic import from documents
|
|
|
|
This PR deletes #3. Consolidating #1 and #2 is a separate future task.
|
|
|
|
### `getTeamAvatarUrl` only exists in media
|
|
|
|
The formatting package's `EntityType` already includes `'team'`, and `getEntityImageUrl` works for any entity type. But there's no `getTeamAvatarUrl` convenience function. Adding one is a trivial 4-line wrapper.
|
|
|
|
### documents version of EntityImageService is the canonical one
|
|
|
|
The `@alga-psa/documents` version:
|
|
- Uses direct `StorageService` import (not dynamic)
|
|
- Uses direct `deleteDocument`/`getDocumentTypeId` calls
|
|
- Has `isActionPermissionError` handling
|
|
- Already used by 4 other packages (`clients`, `client-portal`, `tenancy`, documents-internal)
|
|
|
|
The media version:
|
|
- Uses dynamic imports to break cycles (no longer needed)
|
|
- Less robust error handling (no permission error check)
|
|
- Only used by 3 callers (users x2, teams x1)
|
|
|
|
### Cross-package violations trade-off
|
|
|
|
Adding `users -> documents` creates 2 new lint warnings. But:
|
|
- 4 other packages already do this exact import
|
|
- We delete an entire package (8 files) in exchange
|
|
- `teams -> documents` creates NO warning (teams not in VERTICAL_PACKAGES)
|
|
|
|
### Test file reads source files via fs.readFileSync
|
|
|
|
`server/src/test/teams-v2-improvements.test.ts` does string-content assertions on source files:
|
|
```typescript
|
|
const mediaAvatarUtils = read('packages/media/src/lib/avatarUtils.ts');
|
|
```
|
|
This must be updated to point at the formatting file, and assertions T085/T089 need adjustment.
|
|
|
|
### Avatar Bug 1: Client portal user avatars on MSP user list
|
|
|
|
Root cause chain:
|
|
1. Client portal user uploads avatar via `uploadContactAvatar(user.contact_id, formData)` in `clientUserActions.ts:289`
|
|
2. This stores `entity_type='contact'`, `entity_id=contact_id` in `document_associations`
|
|
3. MSP UserList fetches via `getUserAvatarUrlAction(user.user_id)` which queries `entity_type='user'`, `entity_id=user_id`
|
|
4. No match → null → no avatar displayed
|
|
|
|
Fix: Branch on `user.user_type` in `UserList.tsx` avatar fetch loop. Use `getContactAvatarUrlAction(user.contact_id)` for client users.
|
|
|
|
### Avatar Bug 2: Contact avatar '?' fallback
|
|
|
|
Root cause chain:
|
|
1. `ContactAvatarUpload.tsx:38` passes `entityName=""` to `EntityImageUpload`
|
|
2. `EntityImageUpload` renders `UserAvatar` with `userName=""`
|
|
3. `ContactAvatar.getContactInitials` returns `'?'` when `!name` (line 12 of `ContactAvatar.tsx`)
|
|
|
|
Fix: Add `contactName: string` prop to `ContactAvatarUpload`, pass it as `entityName`. Update 2 callers (`ContactDetails.tsx`, `ContactDetailsEdit.tsx`) to pass the contact's `full_name`.
|
|
|
|
## Build Command
|
|
|
|
Use instead of `npm run build`:
|
|
```bash
|
|
NODE_OPTIONS=--max-old-space-size=32768 npx nx run-many -t build --maxParallel=4
|
|
```
|
|
|
|
## File Inventory
|
|
|
|
### Files to delete (10 total)
|
|
- `server/src/lib/posthog.ts` (7 LOC)
|
|
- `server/src/lib/actions/tenant-secret-actions.ts` (222 LOC)
|
|
- `packages/media/src/index.ts` (3 LOC)
|
|
- `packages/media/src/lib/avatarUtils.ts` (87 LOC)
|
|
- `packages/media/src/lib/documentsHelpers.ts` (32 LOC)
|
|
- `packages/media/src/services/EntityImageService.ts` (296 LOC)
|
|
- `packages/media/package.json`
|
|
- `packages/media/project.json`
|
|
- `packages/media/tsconfig.json`
|
|
- `packages/media/tsup.config.ts`
|
|
|
|
### Files to edit (15 total)
|
|
- `server/src/components/settings/secrets/SecretsManagement.tsx` (import path)
|
|
- `server/src/components/settings/secrets/SecretDialog.tsx` (import path)
|
|
- `packages/formatting/src/avatarUtils.ts` (add getTeamAvatarUrl)
|
|
- `packages/users/src/services/UserService.ts` (import paths)
|
|
- `packages/users/src/actions/user-actions/userActions.ts` (import path)
|
|
- `packages/users/package.json` (dependencies)
|
|
- `packages/teams/src/actions/team-actions/avatarActions.ts` (import paths)
|
|
- `packages/teams/package.json` (dependencies)
|
|
- `server/next.config.mjs` (remove media alias)
|
|
- `server/tsconfig.json` (remove media paths)
|
|
- `ee/server/tsconfig.json` (remove media paths)
|
|
- `services/workflow-worker/Dockerfile` (remove media workspace)
|
|
- `server/src/test/teams-v2-improvements.test.ts` (update file paths + assertions)
|
|
- `server/src/components/settings/general/UserList.tsx` (avatar fetch branch)
|
|
- `packages/clients/src/components/contacts/ContactAvatarUpload.tsx` (add contactName prop)
|
|
- `packages/clients/src/components/contacts/ContactDetails.tsx` (pass contactName)
|
|
- `packages/clients/src/components/contacts/ContactDetailsEdit.tsx` (pass contactName)
|
|
|
|
## Execution Order
|
|
|
|
1. Task 1: Delete posthog.ts (independent, no deps)
|
|
2. Task 2: Redirect tenant-secret-actions callers, delete server copy (independent)
|
|
3. Task 3: Media deletion (depends on nothing, but do in sub-steps):
|
|
a. Add `getTeamAvatarUrl` to formatting
|
|
b. Update 3 caller files (import paths)
|
|
c. Update 2 package.json files (dependencies)
|
|
d. Update test file
|
|
e. Update config files (next.config, tsconfig x2, Dockerfile)
|
|
f. Delete `packages/media/` directory
|
|
g. `npm install` to update lock file
|
|
4. Task 4: Fix UserList.tsx avatar fetch for client portal users
|
|
5. Task 5: Fix ContactAvatarUpload.tsx and its 2 callers
|
|
6. Build verification
|
|
|
|
## Gotchas
|
|
|
|
- The `teams-v2-improvements.test.ts` test does string matching on file content -- it will ENOENT if media files are deleted before the test path is updated.
|
|
- `server/next.config.mjs` has media referenced in 3 separate places (aliases object, transpilePackages array, resolve.alias). All 3 must be removed.
|
|
- `package-lock.json` will have stale entries for `@alga-psa/media` until `npm install` is run.
|
|
- The Dockerfile `--workspace=@alga-psa/media` line is in a `COPY` instruction context -- verify the line can be cleanly removed without breaking the multi-line command.
|
|
- T102 in `teams-v2-improvements.test.ts` checks that `@alga-psa/media` is in teams package.json deps -- must update to check for `@alga-psa/documents` and `@alga-psa/formatting` instead.
|
|
|
|
## Progress Log
|
|
- F001: Deleted `server/src/lib/posthog.ts` after validating the deprecated wrapper path had no remaining imports.
|
|
- F002: Pointed `SecretsManagement.tsx` at `@alga-psa/tenancy/actions` so it uses the canonical tenant secret actions barrel.
|
|
- F003: Updated `SecretDialog.tsx` to import secret CRUD helpers from the canonical `@alga-psa/tenancy/actions` barrel.
|
|
- F004: Deleted `server/src/lib/actions/tenant-secret-actions.ts` once both settings callers had been redirected to `@alga-psa/tenancy/actions`.
|
|
- F005: Added `getTeamAvatarUrl` to `packages/formatting/src/avatarUtils.ts` as the canonical wrapper over `getEntityImageUrl('team', ...)`.
|
|
- F006: Repointed `packages/users/src/services/UserService.ts` to import avatar URL lookup from formatting and image mutations from documents.
|
|
- F007: Updated `packages/users/src/actions/user-actions/userActions.ts` to consume entity image mutations from `@alga-psa/documents`.
|
|
- F008: Split `packages/teams/src/actions/team-actions/avatarActions.ts` imports across canonical documents and formatting packages.
|
|
- F009: Replaced the stale `@alga-psa/media` dependency in `packages/users/package.json` with canonical `documents` and `formatting` package dependencies.
|
|
- F010: Replaced the teams package dependency on `@alga-psa/media` with the canonical documents and formatting packages.
|
|
- F011: Removed all `@alga-psa/media` alias and transpilation wiring from `server/next.config.mjs`.
|
|
- F012: Removed the `@alga-psa/media` path mappings from `server/tsconfig.json`.
|
|
- F013: Removed the stale `@alga-psa/media` path mappings from `ee/server/tsconfig.json`.
|
|
- F014: Dropped the deleted `@alga-psa/media` workspace from `services/workflow-worker/Dockerfile`.
|
|
- F015: Updated `server/src/test/teams-v2-improvements.test.ts` to read formatting avatar utilities and assert the new canonical package dependencies.
|
|
- F016: Deleted `packages/media/` entirely after migrating its three callers, config references, and the source-reading regression test.
|
|
- F017: Ran `npm install` to refresh `package-lock.json` after removing `@alga-psa/media` and adding canonical package dependencies.
|
|
- F018: Imported `getContactAvatarUrlAction` into `UserList.tsx` to support client-user avatar lookup via contact records.
|
|
- F019: Updated the `UserList.tsx` avatar lookup loop to fetch contact avatars for client users, preserve user avatars for internal users, and fall back to `null` when a client user lacks `contact_id`.
|
|
- F020: Added a required `contactName` prop to `ContactAvatarUploadProps` and plumbed it into the component signature.
|
|
- F021: Replaced the hardcoded empty `entityName` in `ContactAvatarUpload` with the new `contactName` prop so initials render correctly.
|
|
- F022: Updated `ContactDetails.tsx` to pass `editedContact.full_name` into `ContactAvatarUpload`.
|
|
- F023: Updated `ContactDetailsEdit.tsx` to pass `contact.full_name` into `ContactAvatarUpload`.
|
|
- Discovery: the first full build after F023 failed because `server/src/app/api/secrets/route.ts` and `server/src/app/api/secrets/[name]/route.ts` still imported the deleted server duplicate. Added follow-up items `F023A`/`F023B` and `T041A`/`T041B` so the plan matches the real remaining work.
|
|
- F023A: Repointed `server/src/app/api/secrets/route.ts` to `@alga-psa/tenancy/actions` to remove the hidden stale import found by the build.
|
|
- F023B: Repointed `server/src/app/api/secrets/[name]/route.ts` to `@alga-psa/tenancy/actions` so the build no longer looks for the deleted server duplicate.
|
|
- F024: Re-ran `NODE_OPTIONS=--max-old-space-size=32768 npx nx run-many -t build --maxParallel=4` after fixing the hidden secrets API imports; the full build completed successfully.
|
|
- Discovery: added `T042A` because the PRD explicitly requires `server/src/test/teams-v2-improvements.test.ts` to pass after the media cleanup.
|
|
- T001: Confirmed the deprecated `@/lib/posthog` wrapper path has zero remaining imports anywhere outside docs and lockfiles.
|
|
- T002: Verified `server/src/lib/posthog.ts` is absent on disk after F001.
|
|
- T003: Verified `SecretsManagement.tsx` imports tenant secret helpers from `@alga-psa/tenancy/actions`.
|
|
- T004: Verified `SecretDialog.tsx` imports its secret helpers from `@alga-psa/tenancy/actions`.
|
|
- T005: Verified the deleted server-side `tenant-secret-actions.ts` duplicate is no longer present.
|
|
- T006: Confirmed `server/src/` no longer references `tenant-secret-actions` outside excluded test/docs paths.
|
|
- T007: Corrected the outdated checklist wording and verified the tenancy barrel re-exports the exact secret helpers now used by the settings UI and API routes.
|
|
- Discovery: added `T042A` because the PRD explicitly requires `server/src/test/teams-v2-improvements.test.ts` to pass after the media cleanup.
|
|
- T001: Confirmed the deprecated @/lib/posthog wrapper path has zero remaining imports anywhere outside docs and lockfiles.
|
|
- T002: Verified server/src/lib/posthog.ts is absent on disk after F001.
|
|
- T003: Verified SecretsManagement.tsx imports tenant secret helpers from @alga-psa/tenancy/actions.
|
|
- T004: Verified SecretDialog.tsx imports its secret helpers from @alga-psa/tenancy/actions.
|
|
- T005: Verified the deleted server-side tenant-secret-actions.ts duplicate is no longer present.
|
|
- T006: Confirmed server/src no longer references tenant-secret-actions outside excluded test/docs paths.
|
|
- T007: Corrected the outdated checklist wording and verified the tenancy barrel re-exports the exact secret helpers now used by the settings UI and API routes.
|
|
- T008: Verified getTeamAvatarUrl exists in formatting and delegates to getEntityImageUrl('team', teamId, tenant).
|
|
- T009: Confirmed getTeamAvatarUrl is exported directly from packages/formatting/src/avatarUtils.ts.
|
|
- T010: Verified UserService.ts imports getUserAvatarUrl from formatting instead of the deleted media package.
|
|
- T011: Verified UserService.ts imports uploadEntityImage and deleteEntityImage from @alga-psa/documents.
|
|
- T012: Verified userActions.ts imports uploadEntityImage and deleteEntityImage from @alga-psa/documents.
|
|
- T013: Verified teams avatarActions.ts imports uploadEntityImage and deleteEntityImage from @alga-psa/documents.
|
|
- T014: Verified teams avatarActions.ts imports getTeamAvatarUrl from formatting instead of media.
|
|
- T015: Verified packages/users/package.json no longer lists @alga-psa/media in dependencies.
|
|
- T016: Verified packages/users/package.json includes canonical documents and formatting dependencies.
|
|
- T017: Verified packages/teams/package.json no longer lists @alga-psa/media in dependencies.
|
|
- T018: Verified packages/teams/package.json includes canonical documents and formatting dependencies.
|
|
- T019: Confirmed server/next.config.mjs no longer contains any @alga-psa/media alias or transpile references.
|
|
- T020: Confirmed server/tsconfig.json no longer contains @alga-psa/media path mappings.
|
|
- T021: Confirmed ee/server/tsconfig.json no longer contains @alga-psa/media path mappings.
|
|
- T022: Confirmed the workflow-worker Dockerfile no longer references the deleted @alga-psa/media workspace.
|
|
- T023: Verified teams-v2-improvements.test.ts now reads packages/formatting/src/avatarUtils.ts instead of the deleted media file.
|
|
- T024: Verified the T085 assertion now checks formatting avatar utils for the team EntityType entry.
|
|
- T025: Verified the T089 assertion now checks formatting avatar utils for getTeamAvatarUrl.
|
|
- T026: Verified the entire packages/media directory has been removed from disk.
|
|
- T027: Confirmed there are no remaining @alga-psa/media references outside docs, plan artifacts, lockfiles, and AI metadata.
|
|
- T028: Re-ran npm install successfully after the dependency cleanup; see /tmp/t028-npm-install.log for the command output from this validation run.
|
|
- T029: Re-ran the full Nx build successfully; output captured in /tmp/t029-build.log.
|
|
- T030: Generated a fresh Nx graph and confirmed scripts/check-circular-deps.mjs reports no new cycles against .github/known-cycles.json.
|
|
- T031: Checked all modified source/config files and confirmed none are shim-only re-export files.
|
|
- T032: Verified packages/documents/src/lib/entityImageService.ts exports EntityType, uploadEntityImage, and deleteEntityImage for migrated callers.
|
|
- T033: Verified packages/formatting/src/avatarUtils.ts exports both getUserAvatarUrl and getTeamAvatarUrl.
|
|
- T034: Verified UserList.tsx imports getContactAvatarUrlAction alongside getUserAvatarUrlAction from @alga-psa/user-composition/actions.
|
|
- T035: Verified the avatar fetch loop branches on user.user_type === 'client' and uses getContactAvatarUrlAction(user.contact_id, user.tenant).
|
|
- T036: Verified the avatar fetch loop still uses getUserAvatarUrlAction(user.user_id, user.tenant) for non-client users.
|
|
- T037: Verified client users without contact_id fall back to a null avatar instead of querying the wrong entity type.
|
|
- T038: Verified ContactAvatarUploadProps includes a required contactName: string prop.
|
|
- T039: Verified ContactAvatarUpload passes contactName through as EntityImageUpload.entityName.
|
|
- T040: Verified ContactDetails.tsx passes editedContact.full_name to ContactAvatarUpload.
|
|
- T041: Verified ContactDetailsEdit.tsx passes contact.full_name to ContactAvatarUpload.
|
|
- T041A: Verified server/src/app/api/secrets/route.ts imports tenant secret actions from @alga-psa/tenancy/actions.
|
|
- T041B: Verified server/src/app/api/secrets/[name]/route.ts imports tenant secret actions from @alga-psa/tenancy/actions.
|
|
- T042A: Updated `server/src/test/teams-v2-improvements.test.ts` to read the existing `packages/user-composition/src/lib/avatarUtils.ts` source and to assert the current TeamDetails/UserManagement structure before rerunning the test successfully.
|
|
- T042: Reused the successful full-build validation from T029, which ran after all planned feature work was complete.
|