Hermes 284313f908
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
Initial import of AlgaPSA codebase from PSA server
Excluded: .git, node_modules, secrets/, compose.env, assemblyscript tgz

Source: /opt/alga-psa on psa.joliet.tech
2026-06-22 16:12:17 -05:00

126 lines
7.2 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Scratchpad — Hudu Phase 2 (Assets & Documents)
## Decisions
- 2026-06-11 — Scope settled with Natallia via three options questions:
assets = **import + pull sync** (not mapping-only, not one-time import);
articles = **link-only** section in client Documents tab; global view =
**Documents page "Hudu" tab** (not global-search-only).
- Sync is **manual-only** this phase (button per client); scheduled refresh
stays a future enhancement (was already a Phase 1 non-goal).
- Sync conflict policy: **Hudu wins on synced fields only** (`name`,
`serial_number`); everything else in Alga untouched; `asset_type` never
retro-changed after import/mapping.
- Hudu disappearance → mapping metadata `stale: true` + badge. Never delete.
- Layout→type map lives in `hudu_integrations.settings.asset_layout_type_map`
(no new table); UI block inside HuduIntegrationSettings.
- Asset mapping UI reuses the **staged Save/Discard confirmation pattern**
built for company mappings on 2026-06-11 (picker stages; Save commits;
dismissible suggestions; row revert/unmap actions).
## Discoveries (verified in code)
- `tenant_external_entity_mappings` unique indexes
(`server/migrations/20250502173321_…`) are scoped by
`(tenant…, integration_type, alga_entity_type, …)` → asset mappings
(`alga_entity_type='asset'`) coexist with Phase 1 client mappings. The
original migration named the column `tenant_id` but Phase 1's
companyMapping.ts queries `tenant` and its real-DB tests pass — a later
rename superseded it. **Mirror companyMapping.ts, not the old migration.**
- `CreateAssetRequest` (`packages/types/src/interfaces/asset.interfaces.ts:378`):
fixed enum `asset_type: 'workstation'|'network_device'|'server'|
'mobile_device'|'printer'|'unknown'`; **required** `asset_tag`, `name`,
`status`, `client_id`; optional `serial_number`; per-type extension blobs.
- `createAsset` = `packages/assets/src/actions/assetActions.ts:755`
(withAuth wrapper → asset RBAC).
- Client Documents tab: `packages/clients/src/components/clients/
ClientDetails.tsx` tab id `documents` (~line 1715). Phase 1 EE-injection
precedent: `useHuduClientTab(client.client_id)` at line 283 + spread tabs
at ~1844.
- Main documents page: `server/src/app/msp/documents/page.tsx` →
`packages/documents/src/components/DocumentsPage.tsx`.
- Hudu API (plan dir `hudu-api-reference.md`): assets by company
`GET /api/v1/assets?company_id=&page=&archived=false`; articles
`GET /api/v1/articles?company_id=&page=`; global articles = omit
company_id. Asset layouts: `GET /api/v1/asset_layouts` (verify response
shape on local instance). 25/page, 300 req/min.
- Hudu asset payload carries `primary_serial`, `asset_layout_id`, `fields[]`
(layout custom fields), `archived`.
## Environment / testing
- Local Hudu: `http://hudu.localtest.me` (stack in `~/hudu2`), API key
unscoped, password access on. Companies: ExampleCo (1), Emerald City Ltd
(2). Alga dev: bigmac worktree, `localhost:3001`, tenant
`c7c99e9f-19dd-46b0-80be-0a2a59f5ab7a` (has `enterprise` add-on row).
Flags forced via `server/.env.local` (`NEXT_PUBLIC_FORCE_FEATURE_FLAGS`
+ `DISABLE_FEATURE_FLAGS=true`).
- Unit tests: `cd ee/server && npx vitest run src/__tests__/unit/hudu` —
273 passing pre-Phase-2 (incl. staged-save mapping manager rewrite).
## Implementation findings
- **FR1 correction**: `idx_unique_external_mapping` is `(tenant,
integration_type, external_entity_id, COALESCE(external_realm_id,''))` —
NOT scoped by alga_entity_type (only the alga-direction index is). Hudu
company and asset ids overlap numerically → asset mapping rows carry
`external_realm_id = String(hudu company id)` (client rows use null).
T215 proves coexistence with identical external ids.
- `getHuduAssetMappings` reuses the Phase 1 `getHuduCompanyAssets` action
for fetch+cache → effectively requires system_settings read in addition
to asset read (technicians already have it for the client tab). Acceptable.
- regression-phase2 DONE (2026-06-11): huduPermissions.test.ts now enumerates
all 8 action modules (Phase 1 three + layoutMap/assetMapping/assetImport/
assetSync/globalDocs) — 97 tests. Layout-map actions joined the
system_settings manage/view lists; the Technician flows got a
resource+permission matrix (asset read/update/create, client read) plus an
unauthenticated sweep over every entry (withAuth mock now drops the session
user). T093 exhaustiveness still fails on any future unlisted export.
T250 = information_schema column-list check in
hudu-regression.integration.test.ts (real-DB harness): exactly the 12
Phase 1 columns, no pull-only additions (NFR4). T110 expected-file list
extended with the 5 new action modules.
- Found while running tsc for regression-phase2: 6 hudu type errors from
earlier groups, all fixed — HuduAssetMappingManager.tsx relied on
`!result.success` narrowing, which the non-strict EE tsconfig doesn't do
(added isImportFailure/isBulkImportFailure guards, the file's existing
isMappingFailure idiom); two TS2347s (type args on untyped vi helpers) in
huduSettingsPageCategory.test.tsx / huduDocumentsTabGate.test.tsx became
post-call casts. Remaining tsc errors are the known pre-existing chat
registry / mcp agent-tooling / msp-composition ones (14).
- `HuduAsset` in contracts.ts lacks `asset_layout_id` (runtime has it);
typed locally in actions as HuduAssetListItem — consider lifting to
contracts in a later group.
## OQ resolutions (2026-06-11, verified on local instance)
- **OQ1 RESOLVED**: `GET /api/v1/articles?search=` does case-insensitive
partial matching ("vpn" → "VPN Setup Guide"); `?name=` is exact-only.
Use `?search=`. Global list = omit `company_id`; response carries
`company_id` per article.
- **OQ2 RESOLVED**: `assets.asset_tag` is notNullable but has NO unique
constraint (migration `20241112031330_create_asset_management_tables.cjs`).
`primary_serial` as tag is safe; `hudu-<id>` fallback only for missing
serials. NOTE: assets table column is `company_id` (legacy name for
client) + `type_id` uuid — the `asset_type` enum in CreateAssetRequest is
the action-level API; verify createAsset's mapping when implementing.
- Hudu asset payload verified: `{id, name, company_id, asset_layout_id,
primary_serial, archived, fields[]}`. Default layouts on fresh instance
incl. "Computer Assets" (7), "Databases" (9), "Applications" (3).
- Seeded local data: articles (2× ExampleCo + 3 pre-existing, 1× Emerald),
assets EC-WS-001 (SN-EC-1001), EC-SRV-01 (SN-EC-2001) in Computer Assets.
- Git: commits require Natallia's explicit request (auto-mode enforces) —
implement all groups, flip flags, let her commit per group at the end.
## Gotchas
- `asset_tag` uniqueness semantics unverified (R2) — check before using
`primary_serial` as tag; fallback `hudu-<id>`.
- Hudu article search param name unverified (OQ1): try `?search=`, fall back
to `?name=`.
- i18n: every new string needs en + de/es/fr/it/nl/pl/pt keys, and the
Phase 1 static i18n test (`huduI18n.test.ts`) must be extended to scan the
new components (it whitelists scanned sources explicitly).
- DocumentsPage is a CE package — EE tab must inject via gate hook, never a
hard import of EE components (R4).