chore(repo): initialize planarchy workspace
This commit is contained in:
@@ -0,0 +1,39 @@
|
||||
# Documentation Index
|
||||
|
||||
**Date:** 2026-03-12
|
||||
**Purpose:** Single entry point for active Planarchy product and technical documentation.
|
||||
|
||||
## Canonical Documents
|
||||
|
||||
| Topic | File | Use |
|
||||
|---|---|---|
|
||||
| Active roadmap and open gaps | [product-roadmap.md](/home/hartmut/Documents/Copilot/planarchy/docs/product-roadmap.md) | Primary backlog and current delivery order |
|
||||
| Estimating system design | [estimating-extension-design.md](/home/hartmut/Documents/Copilot/planarchy/docs/estimating-extension-design.md) | Workbook analysis, field mapping, and implementation plan |
|
||||
| Dispo import implementation | [dispo-import-implementation.md](/home/hartmut/Documents/Copilot/planarchy/docs/dispo-import-implementation.md) | Clean-slate Dispo v2 import design, mapping rules, staging flow, and commit policy |
|
||||
| Dispo import ticket pack | [dispo-import-implementation-tickets.md](/home/hartmut/Documents/Copilot/planarchy/docs/dispo-import-implementation-tickets.md) | Worker-ready delivery slices, dependencies, and acceptance criteria for the Dispo import |
|
||||
| Demand/assignment cutover guide | [demand-assignment-migration-cutover.md](/home/hartmut/Documents/Copilot/planarchy/docs/demand-assignment-migration-cutover.md) | Go/no-go criteria, staged cutover, and readiness artifact policy |
|
||||
| Strategic architecture direction | [v2-architecture-proposal-2026-03-11.md](/home/hartmut/Documents/Copilot/planarchy/research/v2-architecture-proposal-2026-03-11.md) | Longer-horizon architecture target |
|
||||
| Implementation history | [LEARNINGS.md](/home/hartmut/Documents/Copilot/planarchy/LEARNINGS.md) | Append-only decisions and lessons |
|
||||
| Agent/project guidance | [CLAUDE.md](/home/hartmut/Documents/Copilot/planarchy/CLAUDE.md) | Working conventions and quality gates |
|
||||
|
||||
## Archive Policy
|
||||
|
||||
Older plan and proposal markdown files stay in the repository only as archive notes when:
|
||||
|
||||
- the feature is already implemented enough to leave the active backlog
|
||||
- the content was merged into a canonical document
|
||||
- the file still has historical value, but should not drive current work
|
||||
|
||||
Archive-note files should point back to the relevant canonical document instead of carrying parallel backlog state.
|
||||
|
||||
## Current Archive Notes
|
||||
|
||||
All archived markdown plan and proposal files now live under `docs/old-markdowns/`.
|
||||
|
||||
- [plan.md](/home/hartmut/Documents/Copilot/planarchy/docs/old-markdowns/plan.md)
|
||||
- [PLAN_SKILLMATRIX.md](/home/hartmut/Documents/Copilot/planarchy/docs/old-markdowns/PLAN_SKILLMATRIX.md)
|
||||
- [refactor-sprint-plan.md](/home/hartmut/Documents/Copilot/planarchy/docs/old-markdowns/refactor-sprint-plan.md)
|
||||
- [estimating-field-mapping.md](/home/hartmut/Documents/Copilot/planarchy/docs/old-markdowns/estimating-field-mapping.md)
|
||||
- [cgi-breakdown-implementation-proposal.md](/home/hartmut/Documents/Copilot/planarchy/docs/old-markdowns/cgi-breakdown-implementation-proposal.md)
|
||||
- [architecture-evaluation-2026-03-06.md](/home/hartmut/Documents/Copilot/planarchy/docs/old-markdowns/architecture-evaluation-2026-03-06.md)
|
||||
- [perf-audit-2026-03-09.md](/home/hartmut/Documents/Copilot/planarchy/docs/old-markdowns/perf-audit-2026-03-09.md)
|
||||
@@ -0,0 +1,87 @@
|
||||
# Azure OpenAI / Codex CLI Setup
|
||||
|
||||
This document collects the steps you need when working with the **Codex CLI** and the
|
||||
Azure OpenAI service. The examples assume that you have two deployments available in
|
||||
your Azure OpenAI project:
|
||||
|
||||
* `gpt-5.4`
|
||||
* `gpt-5.4-pro`
|
||||
|
||||
Both of these models are currently active in our environment and can be referenced from
|
||||
the CLI configuration.
|
||||
|
||||
---
|
||||
|
||||
## 1. Prerequisites
|
||||
|
||||
1. **Azure Subscription** – an active subscription with access to the Azure OpenAI
|
||||
resource.
|
||||
2. **Model Deployment** – make sure at least one of the Codex-compatible models has
|
||||
been deployed. In our case the deployments are named `gpt-5.4` and
|
||||
`gpt-5.4-pro`.
|
||||
3. **Endpoint & key** – note down the endpoint URL and the API key from the Azure
|
||||
portal; you will need them for the configuration file.
|
||||
4. **Supported OS** – macOS 12+, Ubuntu 20.04+, or Windows 11 via WSL2.
|
||||
5. **Tools** – Node.js + npm installed on your machine.
|
||||
|
||||
---
|
||||
|
||||
## 2. Install and configure the Codex CLI
|
||||
|
||||
```bash
|
||||
npm install -g @openai/codex
|
||||
```
|
||||
|
||||
Create a configuration folder in your home directory:
|
||||
|
||||
```bash
|
||||
mkdir -p ~/.codex
|
||||
```
|
||||
|
||||
and then create a `config.toml` inside that folder with the following content
|
||||
(replace the placeholders with your actual values):
|
||||
|
||||
```toml
|
||||
# ~/.codex/config.toml
|
||||
|
||||
# default model to use; switch between "gpt-5.4" and "gpt-5.4-pro" as needed
|
||||
model = "gpt-5.4"
|
||||
model_provider = "azure"
|
||||
|
||||
[model_providers.azure]
|
||||
name = "Azure OpenAI"
|
||||
base_url = "https://<your-resource-name>.openai.azure.com/"
|
||||
env_key = "AZURE_OPENAI_API_KEY"
|
||||
```
|
||||
|
||||
The `model` field can be changed at any time to `gpt-5.4-pro` when you want the
|
||||
higher‑tier model; the CLI reads this file on each invocation.
|
||||
|
||||
Finally, export your API key into the environment:
|
||||
|
||||
```bash
|
||||
export AZURE_OPENAI_API_KEY="<your-key-here>"
|
||||
```
|
||||
|
||||
On Windows (PowerShell) use:
|
||||
|
||||
```powershell
|
||||
setx AZURE_OPENAI_API_KEY "<your-key-here>"
|
||||
```
|
||||
|
||||
or set it in the System environment variables via the Control Panel.
|
||||
|
||||
---
|
||||
|
||||
With that in place you can run `codex --help` and start using the CLI against your
|
||||
Azure deployment.
|
||||
|
||||
*Note:* the CLI will automatically pick the model specified in `config.toml`.
|
||||
To switch models you may either edit the file or pass `--model gpt-5.4-pro` on
|
||||
the command line.
|
||||
|
||||
---
|
||||
|
||||
This repository does not actually contain the `.codex` folder – it lives in your
|
||||
home directory – but the sample file above is provided for reference. You can
|
||||
copy it into your own environment when you set up the CLI.
|
||||
@@ -0,0 +1,191 @@
|
||||
# Demand And Assignment Migration Cutover
|
||||
|
||||
**Date:** 2026-03-13
|
||||
**Purpose:** Canonical go/no-go, artifact, and execution guide for the additive `Allocation` to `DemandRequirement` / `Assignment` persistence split.
|
||||
|
||||
## Scope
|
||||
|
||||
This cutover document governs the additive migration from mixed legacy `Allocation` rows to first-class `DemandRequirement` and `Assignment` rows.
|
||||
|
||||
It assumes:
|
||||
|
||||
- legacy compatibility API paths remain available during the migration window
|
||||
- the backfill is additive and idempotent
|
||||
- cleanup of legacy rows happens only after readiness is green and signoff is recorded
|
||||
|
||||
## Canonical Commands
|
||||
|
||||
Use the readiness command as the primary gate:
|
||||
|
||||
```bash
|
||||
pnpm db:readiness:demand-assignment --write-artifacts
|
||||
```
|
||||
|
||||
Supporting commands:
|
||||
|
||||
```bash
|
||||
pnpm --filter @planarchy/db db:audit:demand-assignment --json --fail-on-blockers
|
||||
pnpm --filter @planarchy/db db:backfill:demand-assignment --json --fail-on-blockers
|
||||
pnpm --filter @planarchy/db db:backfill:demand-assignment --apply
|
||||
```
|
||||
|
||||
`pnpm db:readiness:demand-assignment` fails with a non-zero exit code when the workspace is not ready for `--apply`. Use `--allow-blockers` only when collecting review artifacts before remediation.
|
||||
|
||||
Generated artifacts default to `docs/migration-artifacts/demand-assignment/` with deterministic filenames:
|
||||
|
||||
- `workspace-audit.json`
|
||||
- `workspace-dry-run.json`
|
||||
- `workspace-readiness.json`
|
||||
|
||||
Project-scoped runs use `project-<projectId>-*.json`.
|
||||
|
||||
## Go/No-Go Criteria
|
||||
|
||||
`--apply` is allowed only when all of the following are true in the readiness report:
|
||||
|
||||
1. `goNoGo` is `go`
|
||||
2. `audit.pendingDemandBackfills` is `0`
|
||||
3. `audit.pendingAssignmentBackfills` is `0`
|
||||
4. `audit.invalidStaffedAllocationsWithoutResource` is `0`
|
||||
5. `audit.orphanedDemandRequirementsWithLegacyLink` is `0`
|
||||
6. `audit.orphanedAssignmentsWithLegacyLink` is `0`
|
||||
|
||||
Warnings are review items, not automatic blockers. In particular, placeholder rows with a resource and staffed rows with `headcount > 1` must be acknowledged in the cutover review, but they do not by themselves block `--apply`.
|
||||
|
||||
## Required Artifacts And Signoff
|
||||
|
||||
Before the first production `--apply`, attach all of the following to the cutover review:
|
||||
|
||||
1. readiness artifact set from `pnpm db:readiness:demand-assignment --write-artifacts`
|
||||
2. exact command transcript or CI job link for the readiness run
|
||||
3. environment/date stamp for the target database
|
||||
4. operator signoff confirming no blockers remain
|
||||
5. product/engineering signoff approving the migration window
|
||||
|
||||
No production backfill should run from an ad hoc shell session without the saved artifact set.
|
||||
|
||||
## Staged Sequence
|
||||
|
||||
### Stage 0: Compatibility Freeze
|
||||
|
||||
- keep compatibility facades enabled
|
||||
- avoid schema or router changes that introduce new legacy-only write paths
|
||||
- verify the latest application/API tests for demand-assignment compatibility are green
|
||||
|
||||
### Stage 1: Readiness Review
|
||||
|
||||
- run `pnpm db:readiness:demand-assignment --write-artifacts`
|
||||
- review blockers and warnings from the readiness artifact
|
||||
- remediate invalid legacy rows or orphaned legacy links before continuing
|
||||
|
||||
### Stage 2: Dry-Run Signoff
|
||||
|
||||
- rerun readiness until `goNoGo` is `go`
|
||||
- confirm the dry-run artifact shows zero pending creates and zero invalid skips
|
||||
- record operator and product/engineering approval against the saved artifacts
|
||||
|
||||
### Stage 3: Apply Backfill
|
||||
|
||||
- run `pnpm --filter @planarchy/db db:backfill:demand-assignment --apply`
|
||||
- immediately rerun `pnpm db:readiness:demand-assignment --write-artifacts`
|
||||
- require the post-apply readiness report to remain `go`
|
||||
|
||||
### Stage 4: Observe And Stabilize
|
||||
|
||||
- keep legacy facades active during the observation window
|
||||
- monitor create/update/fill flows for stale-link compatibility behavior
|
||||
- treat the remaining raw legacy writes as an explicit allowlist only:
|
||||
- compatibility delete paths that still accept legacy allocation ids
|
||||
- true legacy-id update mirrors that preserve old `allocation.update` behavior
|
||||
- do not remove legacy rows or legacy-compatible reads until the post-apply observation window is complete
|
||||
|
||||
### Stage 5: Legacy Cleanup
|
||||
|
||||
- plan legacy `Allocation` cleanup only after a separate review
|
||||
- retire the Stage 4 allowlist branches individually and verify each removal with focused application/API compatibility tests plus a Docker smoke check
|
||||
- preserve deterministic linkage or archived evidence for any rows cleaned up
|
||||
- keep ambiguity rules below in force during cleanup
|
||||
|
||||
## Ambiguity And Orphan Policy
|
||||
|
||||
The migration is intentionally strict. When data is ambiguous, stop and remediate instead of guessing.
|
||||
|
||||
- If a legacy allocation id resolves to both a demand and an assignment after cleanup, treat it as an error and resolve it manually.
|
||||
- If a `DemandRequirement` or `Assignment` has a `legacyAllocationId` that no longer exists, treat it as an orphan and block cutover until reviewed.
|
||||
- If a staffed legacy allocation has no `resourceId`, do not synthesize an assignment. Fix or retire the row first.
|
||||
- If a placeholder legacy allocation still has a `resourceId`, preserve it as demand metadata only; do not auto-create an assignment from that signal.
|
||||
- If a staffed legacy allocation has `headcount > 1`, preserve one assignment row and treat the headcount discrepancy as a documented warning, not inferred fan-out.
|
||||
|
||||
## Current Readiness Baseline
|
||||
|
||||
The latest workspace readiness run on `2026-03-13T20:10:43.050Z` reported:
|
||||
|
||||
- `132` legacy allocations in scope
|
||||
- `0` pending demand backfills
|
||||
- `0` pending assignment backfills
|
||||
- `0` orphaned demand links
|
||||
- `0` orphaned assignment links
|
||||
- `0` invalid staffed allocations without a resource
|
||||
- dry-run creates: `0` demand, `0` assignment
|
||||
- `goNoGo: "go"`
|
||||
|
||||
The first real `pnpm --filter @planarchy/db db:backfill:demand-assignment --apply --json` was executed on `2026-03-13` and completed as a no-op:
|
||||
|
||||
- `demandCreates: 0`
|
||||
- `assignmentCreates: 0`
|
||||
- `demandSkips: 2`
|
||||
- `assignmentSkips: 130`
|
||||
- `errors: 0`
|
||||
- `warnings: 0`
|
||||
|
||||
Current interpretation: the workspace is already fully backfilled for the additive split, and future cutover work is now primarily about final compatibility-branch retirement and operational signoff rather than data creation.
|
||||
|
||||
## Migration Completion Status (2026-03-14)
|
||||
|
||||
As of `2026-03-14`, the split persistence migration is fully complete through Stage 5:
|
||||
|
||||
- **All reads are split-authoritative.** No runtime code queries `db.allocation.findMany()` or `db.allocation.findUnique()`. `buildSplitAllocationReadModel` works exclusively from `demandRequirements` and `assignments`.
|
||||
- **All writes are split-authoritative.** Create, update, delete, and fill flows route through `DemandRequirement`/`Assignment` paths.
|
||||
- **Legacy `Allocation` table dropped.** The Prisma model and database table have been removed. 132 legacy rows were dropped.
|
||||
- **`legacyAllocationId` columns removed.** Both `DemandRequirement` and `Assignment` no longer carry legacy link columns. All `@unique` constraints and `@@index` entries have been dropped.
|
||||
- **`getAllocationCompatibilityId` removed.** SSE event emissions now use entity IDs directly. The helper function and all ~20 call sites have been replaced with direct `.id` access.
|
||||
- **`getLegacyAllocationLinks` removed.** `findAllocationFacadeEntry` no longer falls back to legacy link resolution. IDs that don't match a current demand/assignment return null.
|
||||
- **`isPlaceholder` is a derived read-model property.** Demand vs. assignment intent is derived from entity type at read-model build time (`DemandRequirement` → `isPlaceholder: true`, `Assignment` → `isPlaceholder: false`). The shared `Allocation` type exposes `isPlaceholder` as a computed property for frontend consumption.
|
||||
- **`fillPlaceholder` API procedure removed.** Open demand fills use `fillOpenDemandByAllocation`. The UI component has been renamed from `FillPlaceholderModal` to `FillOpenDemandModal`.
|
||||
- **`kind: "legacy"` facade resolution removed.** `AllocationFacadeResolution` only has `kind: "demand"` and `kind: "assignment"`.
|
||||
- **All legacy allocation write-back removed.** No code touches the legacy `Allocation` table.
|
||||
- **Migration tooling deleted.** Backfill, audit, readiness scripts, and the role-string migration script have been removed along with their npm script entries.
|
||||
- **Seed data cleaned.** All `allocation.create` and `allocation.deleteMany` calls removed from seed.
|
||||
- **Deleted files (complete list):**
|
||||
- `allocation-compatibility-id.ts` — `getAllocationCompatibilityId` helper
|
||||
- `get-legacy-allocation-links.ts` — legacy link resolution
|
||||
- `legacy-allocation-record-store.ts` — low-level `db.allocation` CRUD wrapper
|
||||
- `ensure-legacy-allocation-split-persistence.ts` — backfill helper
|
||||
- `ensure-demand-requirement-for-legacy-placeholder.ts` — placeholder demand backfill
|
||||
- `has-backing-legacy-allocation.ts`, `delete-allocation-with-compatibility.ts` — dead code
|
||||
- `create-allocation.ts` — legacy allocation creation
|
||||
- `create-legacy-allocation-with-compatibility.ts`, `create-legacy-allocation-compatibility-bundle.ts` — dead compatibility wrappers
|
||||
- `create-demand-requirement-with-compatibility.ts`, `create-assignment-with-compatibility.ts`, `create-demand-and-assignment-with-compatibility.ts` — dead compatibility wrappers
|
||||
- `create-split-records-from-legacy-allocation.ts` — legacy-to-split record factory
|
||||
- `FillPlaceholderModal.tsx` — replaced by `FillOpenDemandModal.tsx`
|
||||
- `legacy-allocation-links.test.ts` — tests for deleted `getLegacyAllocationLinks`
|
||||
- `backfill-demand-assignment.ts`, `audit-demand-assignment-split.ts`, `run-demand-assignment-readiness.ts` — migration tooling
|
||||
- `demand-assignment-readiness.ts`, `demand-assignment-readiness.test.ts` — readiness checks
|
||||
- `demand-assignment-backfill.ts`, `demand-assignment-backfill.test.ts` — backfill logic
|
||||
- `migrate-role-strings.ts` — one-time Phase 5 migration
|
||||
|
||||
### Facade Retirement (Complete)
|
||||
|
||||
The former compatibility facades have been renamed to clean domain names:
|
||||
- `update-allocation-with-compatibility` → `update-allocation-entry`
|
||||
- `delete-allocation-facade-entry` → `delete-allocation-entry`
|
||||
- `fill-open-demand-with-compatibility` → `fill-open-demand`
|
||||
- `load-allocation-facade-entry` → `load-allocation-entry`
|
||||
|
||||
All `AllocationFacade*` type prefixes have been replaced with `AllocationEntry*`. All `compatibilityId` and `source` fields have been removed from booking interfaces. Variable names like `demandRequirementByCompatibilityId` and `existingFacade` have been renamed to `demandRequirementById` and `resolved`. Test descriptions referencing "compatibility" have been updated.
|
||||
|
||||
No legacy *compatibility* naming (e.g. `compatibilityId`, `AllocationFacade*`, `WithCompatibility`, `FillPlaceholder`) remains in the codebase. The `isPlaceholder` property and `"placeholder"` strategy values are intentionally retained as derived read-model contracts — they describe the demand-vs-assignment distinction at the frontend consumption layer, not legacy migration artifacts.
|
||||
|
||||
## Parallel Workstream Note
|
||||
|
||||
As of 2026-03-13, the Dispo v2 chargeability and resource planning stream runs in parallel with this migration. That stream adds new Prisma models (Country, MetroCity, OrgUnit, UtilizationCategory, Client, ManagementLevelGroup, ManagementLevel) and extends the Resource model with new fields. It does not touch Allocation, DemandRequirement, or Assignment models or any compatibility facades. The only serialization point is `schema.prisma` edits — both streams must not edit the schema file concurrently. See `samples/Dispov2/plan-overview.md` and `docs/product-roadmap.md` for the Dispo v2 plans.
|
||||
@@ -0,0 +1,615 @@
|
||||
# Dispo Import Implementation Tickets
|
||||
|
||||
**Date:** 2026-03-14
|
||||
**Purpose:** Worker-ready implementation tickets for the clean-slate Dispo v2 import defined in [dispo-import-implementation.md](/home/hartmut/Documents/Copilot/planarchy/docs/dispo-import-implementation.md).
|
||||
|
||||
## How To Use This Ticket Pack
|
||||
|
||||
- Treat each ticket as a deliverable slice with its own acceptance criteria.
|
||||
- Respect the dependency graph before starting downstream tickets.
|
||||
- Parallel workers should only take tickets from the same phase when their touch points do not overlap heavily.
|
||||
- `[tbd]` project resolution and ambiguous part-time patterns remain review-gated even after implementation.
|
||||
|
||||
## Dependency Summary
|
||||
|
||||
### Phase 0
|
||||
|
||||
- `DISPO-00` must finish first
|
||||
|
||||
### Phase 1
|
||||
|
||||
- `DISPO-10` depends on `DISPO-00`
|
||||
- `DISPO-11` depends on `DISPO-00`
|
||||
- `DISPO-12` depends on `DISPO-00`
|
||||
|
||||
### Phase 2
|
||||
|
||||
- `DISPO-20` depends on `DISPO-10`
|
||||
- `DISPO-21` depends on `DISPO-10`, `DISPO-11`
|
||||
- `DISPO-22` depends on `DISPO-10`, `DISPO-12`
|
||||
|
||||
### Phase 3
|
||||
|
||||
- `DISPO-30` depends on `DISPO-20`, `DISPO-21`, `DISPO-22`
|
||||
- `DISPO-31` depends on `DISPO-20`, `DISPO-21`
|
||||
- `DISPO-32` depends on `DISPO-20`, `DISPO-22`
|
||||
|
||||
### Phase 4
|
||||
|
||||
- `DISPO-40` depends on `DISPO-30`, `DISPO-31`, `DISPO-32`
|
||||
- `DISPO-41` depends on `DISPO-10`, `DISPO-30`, `DISPO-32`
|
||||
- `DISPO-42` depends on `DISPO-40`
|
||||
|
||||
## Parallel Worker Lanes
|
||||
|
||||
Recommended worker split after `DISPO-00`:
|
||||
|
||||
- Worker A: staging schema and import orchestration
|
||||
- Worker B: reset/reseed and reference-data import
|
||||
- Worker C: parser and token normalization
|
||||
- Worker D: resource, role, chapter, and availability normalization
|
||||
- Worker E: commit pipeline, vacations/public holidays, and reconciliation
|
||||
|
||||
## Tickets
|
||||
|
||||
### `DISPO-00` Canonical Decisions Lock
|
||||
|
||||
**Goal**
|
||||
|
||||
Freeze the implementation assumptions so multiple workers do not diverge.
|
||||
|
||||
**Scope**
|
||||
|
||||
- confirm canonical person ID strategy
|
||||
- confirm auth reset scope
|
||||
- confirm `[tbd]` commit policy
|
||||
- confirm default part-time fallback policy
|
||||
- confirm internal project bucket naming
|
||||
|
||||
**Deliverables**
|
||||
|
||||
- decision log appended to [dispo-import-implementation.md](/home/hartmut/Documents/Copilot/planarchy/docs/dispo-import-implementation.md)
|
||||
- explicit list of values to seed for roles and internal project buckets
|
||||
|
||||
**Acceptance Criteria**
|
||||
|
||||
- no remaining ambiguous blocking decisions for schema work
|
||||
- downstream workers can implement without inventing business rules
|
||||
|
||||
**Suggested Owner**
|
||||
|
||||
- architect / lead worker
|
||||
|
||||
**Estimated Effort**
|
||||
|
||||
- 0.5 day
|
||||
|
||||
### `DISPO-10` Staging Schema And Import Batch Model
|
||||
|
||||
**Goal**
|
||||
|
||||
Add durable staging persistence for workbook parsing and review.
|
||||
|
||||
**Scope**
|
||||
|
||||
- add Prisma models for import batches and staged records
|
||||
- add statuses for parsed, unresolved, approved, committed, failed
|
||||
- add source-trace fields
|
||||
- add indexes for batch lookup and unresolved review
|
||||
|
||||
**Deliverables**
|
||||
|
||||
- Prisma schema changes
|
||||
- migration
|
||||
- shared types/schemas for staged entities
|
||||
|
||||
**Acceptance Criteria**
|
||||
|
||||
- an import batch can store staged resources, projects, assignments, vacations, availability rules, and unresolved rows
|
||||
- all staged records keep workbook, sheet, row, and raw payload traceability
|
||||
- migration applies cleanly
|
||||
|
||||
**Dependencies**
|
||||
|
||||
- `DISPO-00`
|
||||
|
||||
**Suggested Owner**
|
||||
|
||||
- Worker A
|
||||
|
||||
**Estimated Effort**
|
||||
|
||||
- 1 day
|
||||
|
||||
### `DISPO-11` Full Reset And Bootstrap Reseed
|
||||
|
||||
**Goal**
|
||||
|
||||
Provide a safe command that wipes the database and recreates the minimum viable platform baseline.
|
||||
|
||||
**Scope**
|
||||
|
||||
- add full reset script/command
|
||||
- back up before destructive reset
|
||||
- recreate admin/bootstrap access
|
||||
- reseed required platform defaults
|
||||
|
||||
**Deliverables**
|
||||
|
||||
- reset command
|
||||
- reseed command or combined bootstrap command
|
||||
- operator documentation
|
||||
|
||||
**Acceptance Criteria**
|
||||
|
||||
- command wipes the intended database scope only
|
||||
- command requires explicit force confirmation
|
||||
- platform remains sign-in capable after reset
|
||||
- rerunning in development is deterministic
|
||||
|
||||
**Dependencies**
|
||||
|
||||
- `DISPO-00`
|
||||
|
||||
**Suggested Owner**
|
||||
|
||||
- Worker B
|
||||
|
||||
**Estimated Effort**
|
||||
|
||||
- 1 day
|
||||
|
||||
### `DISPO-12` Canonical Identity And Role Seed Preparation
|
||||
|
||||
**Goal**
|
||||
|
||||
Prepare the canonical master-data rules required by all downstream importers.
|
||||
|
||||
**Scope**
|
||||
|
||||
- implement single-ID normalization rule for resources
|
||||
- define role seed list
|
||||
- define chapter normalization list
|
||||
- define internal utilization bucket list
|
||||
|
||||
**Deliverables**
|
||||
|
||||
- shared normalization helpers
|
||||
- seed updates for roles and internal categories
|
||||
- test coverage for token-to-role and token-to-chapter mapping
|
||||
|
||||
**Acceptance Criteria**
|
||||
|
||||
- one canonical person identifier is used throughout import logic
|
||||
- role seeds exist for `2D Artist`, `3D Artist`, `Project Manager`, `Art Director`
|
||||
- chapter mapping is deterministic
|
||||
|
||||
**Dependencies**
|
||||
|
||||
- `DISPO-00`
|
||||
|
||||
**Suggested Owner**
|
||||
|
||||
- Worker D
|
||||
|
||||
**Estimated Effort**
|
||||
|
||||
- 0.5 to 1 day
|
||||
|
||||
### `DISPO-20` Reference Data Importer
|
||||
|
||||
**Goal**
|
||||
|
||||
Import and normalize master/reference data from `MandatoryDispoCategories_V3.xlsx`.
|
||||
|
||||
**Scope**
|
||||
|
||||
- countries
|
||||
- metro cities
|
||||
- org units
|
||||
- management level groups and levels
|
||||
- client hierarchy
|
||||
- utilization categories
|
||||
|
||||
**Deliverables**
|
||||
|
||||
- workbook reader/importer
|
||||
- reference-data upsert logic
|
||||
- validation report for unknown values
|
||||
|
||||
**Acceptance Criteria**
|
||||
|
||||
- importer creates the normalized reference graph without duplicate nodes
|
||||
- re-run is idempotent
|
||||
- unknown or unmapped values are surfaced clearly
|
||||
|
||||
**Dependencies**
|
||||
|
||||
- `DISPO-10`
|
||||
|
||||
**Suggested Owner**
|
||||
|
||||
- Worker B
|
||||
|
||||
**Estimated Effort**
|
||||
|
||||
- 1 to 1.5 days
|
||||
|
||||
### `DISPO-21` Resource, Chapter, Role, And Availability Staging
|
||||
|
||||
**Goal**
|
||||
|
||||
Build staged resource records from `ChgFC`, `EID-Attr`, and Dispo row metadata.
|
||||
|
||||
**Scope**
|
||||
|
||||
- canonical resource identity matching
|
||||
- resource master field extraction
|
||||
- chapter mapping
|
||||
- resource role staging
|
||||
- baseline FTE and availability staging
|
||||
|
||||
**Deliverables**
|
||||
|
||||
- resource staging service
|
||||
- chapter/role mapping helper
|
||||
- unresolved resource conflict handling
|
||||
|
||||
**Acceptance Criteria**
|
||||
|
||||
- staged resources deduplicate correctly by canonical ID
|
||||
- resource chapter is derived consistently from agreed token rules
|
||||
- project-capable roles are staged for later assignment commit
|
||||
- unresolved missing person fields are flagged, not silently defaulted
|
||||
|
||||
**Dependencies**
|
||||
|
||||
- `DISPO-10`
|
||||
- `DISPO-11`
|
||||
|
||||
**Suggested Owner**
|
||||
|
||||
- Worker D
|
||||
|
||||
**Estimated Effort**
|
||||
|
||||
- 1.5 days
|
||||
|
||||
### `DISPO-22` Dispo Matrix Parser And Token Normalization
|
||||
|
||||
**Goal**
|
||||
|
||||
Convert `DISPO_2026.xlsx` matrix cells into normalized staging records.
|
||||
|
||||
**Scope**
|
||||
|
||||
- parse day/slot structure
|
||||
- detect project, internal work, absence, holiday, unassigned, weekend, and part-time markers
|
||||
- extract client token, WBS, win probability, role token, ignore suffixes
|
||||
- emit structured staged records
|
||||
|
||||
**Deliverables**
|
||||
|
||||
- parser module
|
||||
- token normalization library
|
||||
- parser tests with representative cell examples
|
||||
|
||||
**Acceptance Criteria**
|
||||
|
||||
- parser handles known token families: `CH`, `MO`, `MD`, `PD`, `AB`, `NA`, `UN`
|
||||
- parser strips `_HB` and `_SB`
|
||||
- parser extracts `[BMW]`, `[11035763]`, `{CH80}`, and role prefixes correctly
|
||||
- unknown token shapes are routed into unresolved staging rows
|
||||
|
||||
**Dependencies**
|
||||
|
||||
- `DISPO-10`
|
||||
- `DISPO-12`
|
||||
|
||||
**Suggested Owner**
|
||||
|
||||
- Worker C
|
||||
|
||||
**Estimated Effort**
|
||||
|
||||
- 1.5 to 2 days
|
||||
|
||||
### `DISPO-30` Staged Project Resolver And Internal Bucket Builder
|
||||
|
||||
**Goal**
|
||||
|
||||
Resolve staged project identities and create normalized internal planning buckets.
|
||||
|
||||
**Scope**
|
||||
|
||||
- create WBS-backed staged projects
|
||||
- link clients to projects
|
||||
- derive project names
|
||||
- stage internal `M&O`, `MD&I`, `PD&R` projects/buckets
|
||||
- keep `[tbd]` rows unresolved
|
||||
|
||||
**Deliverables**
|
||||
|
||||
- project resolver service
|
||||
- internal project/bucket seed or creation logic
|
||||
- unresolved project review list
|
||||
|
||||
**Acceptance Criteria**
|
||||
|
||||
- WBS-backed projects are unique and deterministic
|
||||
- internal work records resolve to canonical internal buckets
|
||||
- `[tbd]` rows do not auto-create final projects
|
||||
|
||||
**Dependencies**
|
||||
|
||||
- `DISPO-20`
|
||||
- `DISPO-21`
|
||||
- `DISPO-22`
|
||||
|
||||
**Suggested Owner**
|
||||
|
||||
- Worker C or E
|
||||
|
||||
**Estimated Effort**
|
||||
|
||||
- 1 day
|
||||
|
||||
### `DISPO-31` Vacation And Public Holiday Import
|
||||
|
||||
**Goal**
|
||||
|
||||
Normalize workbook absences and geography-driven holidays into the vacation planner.
|
||||
|
||||
**Scope**
|
||||
|
||||
- map `AB` rows to vacations
|
||||
- map public holidays to approved `PUBLIC_HOLIDAY` vacations
|
||||
- skip weekends as persisted vacation rows
|
||||
- reconcile workbook holiday markers with generated holidays
|
||||
|
||||
**Deliverables**
|
||||
|
||||
- staged vacation importer
|
||||
- holiday generation/commit integration
|
||||
- tests covering holiday and absence cases
|
||||
|
||||
**Acceptance Criteria**
|
||||
|
||||
- absences appear as vacation rows
|
||||
- public holidays are created through the vacation model
|
||||
- weekends are not persisted as vacations
|
||||
- duplicate holiday rows are prevented
|
||||
|
||||
**Dependencies**
|
||||
|
||||
- `DISPO-20`
|
||||
- `DISPO-21`
|
||||
|
||||
**Suggested Owner**
|
||||
|
||||
- Worker E
|
||||
|
||||
**Estimated Effort**
|
||||
|
||||
- 1 day
|
||||
|
||||
### `DISPO-32` Part-Time Availability Overlay
|
||||
|
||||
**Goal**
|
||||
|
||||
Apply part-time logic to resource availability without creating fake bookings.
|
||||
|
||||
**Scope**
|
||||
|
||||
- parse staged part-time markers
|
||||
- map percentage to available hours
|
||||
- apply weekday reductions where explicit
|
||||
- preserve unresolved patterns for manual review when not explicit
|
||||
|
||||
**Deliverables**
|
||||
|
||||
- availability overlay service
|
||||
- unresolved availability pattern review states
|
||||
- tests for 50%, 75%, 80%, and 100% examples
|
||||
|
||||
**Acceptance Criteria**
|
||||
|
||||
- 50% maps to 4 hours on a standard day
|
||||
- 100% maps to 8 hours on a standard day
|
||||
- explicit non-working weekdays reduce availability to zero on those days
|
||||
- unresolved part-time patterns do not silently invent weekday schedules
|
||||
|
||||
**Dependencies**
|
||||
|
||||
- `DISPO-20`
|
||||
- `DISPO-22`
|
||||
|
||||
**Suggested Owner**
|
||||
|
||||
- Worker D
|
||||
|
||||
**Estimated Effort**
|
||||
|
||||
- 1 day
|
||||
|
||||
### `DISPO-40` Commit Pipeline
|
||||
|
||||
**Goal**
|
||||
|
||||
Commit approved staged data into final Planarchy entities.
|
||||
|
||||
**Scope**
|
||||
|
||||
- create reference entities if missing
|
||||
- create/update resources and resource roles
|
||||
- create projects and internal buckets
|
||||
- create assignments
|
||||
- create vacations
|
||||
- apply availability updates
|
||||
- preserve staging-to-final traceability
|
||||
|
||||
**Deliverables**
|
||||
|
||||
- commit orchestration service
|
||||
- commit transaction boundaries
|
||||
- failure and rollback handling
|
||||
|
||||
**Acceptance Criteria**
|
||||
|
||||
- only approved/resolved staged rows are committed
|
||||
- unassigned rows do not create assignments
|
||||
- unresolved `[tbd]` rows block final project commit
|
||||
- assignment roles are committed separately from resource chapters
|
||||
- commit can be replayed safely for a batch
|
||||
|
||||
**Dependencies**
|
||||
|
||||
- `DISPO-30`
|
||||
- `DISPO-31`
|
||||
- `DISPO-32`
|
||||
|
||||
**Suggested Owner**
|
||||
|
||||
- Worker E
|
||||
|
||||
**Estimated Effort**
|
||||
|
||||
- 1.5 to 2 days
|
||||
|
||||
### `DISPO-41` Review UI Or Operator Workflow For Unresolved Rows
|
||||
|
||||
**Goal**
|
||||
|
||||
Provide a practical path for resolving staged conflicts and `[tbd]` rows.
|
||||
|
||||
**Scope**
|
||||
|
||||
- unresolved staged row listing
|
||||
- filters by type: person, project, part-time pattern, token parse failure
|
||||
- approve/reject/resolve actions
|
||||
- batch review workflow or CLI operator tooling
|
||||
|
||||
**Deliverables**
|
||||
|
||||
- review UI or CLI workflow
|
||||
- action handlers for staged resolution
|
||||
- operator documentation
|
||||
|
||||
**Acceptance Criteria**
|
||||
|
||||
- reviewers can find all unresolved rows by batch
|
||||
- `[tbd]` rows can be explicitly resolved before commit
|
||||
- identity conflicts and part-time ambiguities can be reviewed without DB edits
|
||||
|
||||
**Dependencies**
|
||||
|
||||
- `DISPO-10`
|
||||
- `DISPO-30`
|
||||
- `DISPO-32`
|
||||
|
||||
**Suggested Owner**
|
||||
|
||||
- Worker A or frontend-focused worker
|
||||
|
||||
**Estimated Effort**
|
||||
|
||||
- 1 to 1.5 days
|
||||
|
||||
### `DISPO-42` Reconciliation And Acceptance Report
|
||||
|
||||
**Goal**
|
||||
|
||||
Validate committed data against the chargeability workbook and expected planning totals.
|
||||
|
||||
**Scope**
|
||||
|
||||
- resource count reconciliation
|
||||
- FTE reconciliation
|
||||
- management-group target reconciliation
|
||||
- project/client/WBS consistency checks
|
||||
- public-holiday/vacation visibility checks
|
||||
- free-capacity vs assignment integrity checks
|
||||
|
||||
**Deliverables**
|
||||
|
||||
- reconciliation command/report
|
||||
- machine-readable summary output
|
||||
- human-readable discrepancy report
|
||||
|
||||
**Acceptance Criteria**
|
||||
|
||||
- system can produce a batch-level pass/fail report
|
||||
- discrepancies identify the exact source rows or final entities involved
|
||||
- report is repeatable for reimports
|
||||
|
||||
**Dependencies**
|
||||
|
||||
- `DISPO-40`
|
||||
|
||||
**Suggested Owner**
|
||||
|
||||
- Worker E
|
||||
|
||||
**Estimated Effort**
|
||||
|
||||
- 1 day
|
||||
|
||||
## Suggested Execution Rounds
|
||||
|
||||
### Round 1
|
||||
|
||||
- `DISPO-00`
|
||||
|
||||
### Round 2
|
||||
|
||||
- `DISPO-10`
|
||||
- `DISPO-11`
|
||||
- `DISPO-12`
|
||||
|
||||
### Round 3
|
||||
|
||||
- `DISPO-20`
|
||||
- `DISPO-21`
|
||||
- `DISPO-22`
|
||||
|
||||
### Round 4
|
||||
|
||||
- `DISPO-30`
|
||||
- `DISPO-31`
|
||||
- `DISPO-32`
|
||||
|
||||
### Round 5
|
||||
|
||||
- `DISPO-40`
|
||||
- `DISPO-41`
|
||||
|
||||
### Round 6
|
||||
|
||||
- `DISPO-42`
|
||||
|
||||
## Critical Path
|
||||
|
||||
The likely critical path is:
|
||||
|
||||
1. `DISPO-00`
|
||||
2. `DISPO-10`
|
||||
3. `DISPO-22`
|
||||
4. `DISPO-30`
|
||||
5. `DISPO-40`
|
||||
6. `DISPO-42`
|
||||
|
||||
If speed matters most, staff this path first.
|
||||
|
||||
## Suggested Definition Of Done
|
||||
|
||||
The Dispo import implementation is complete when:
|
||||
|
||||
- the database can be reset and bootstrapped safely
|
||||
- the three source workbooks can be staged deterministically
|
||||
- unresolved rows are surfaced for review
|
||||
- approved staged rows can be committed into normalized planning data
|
||||
- public holidays and absences appear correctly in the vacation planner
|
||||
- part-time availability affects availability instead of creating fake bookings
|
||||
- project bookings carry assignment roles
|
||||
- unassigned time remains free capacity only
|
||||
- reconciliation passes against the source workbooks within agreed tolerance
|
||||
@@ -0,0 +1,636 @@
|
||||
# Dispo Import Implementation
|
||||
|
||||
**Date:** 2026-03-14
|
||||
**Purpose:** Canonical implementation document for replacing the current Planarchy planning dataset with a clean-slate import from the Dispo v2 Excel workbooks.
|
||||
|
||||
## Scope
|
||||
|
||||
This document defines how Planarchy should ingest and normalize the following source workbooks:
|
||||
|
||||
- `/samples/Dispov2/MandatoryDispoCategories_V3.xlsx`
|
||||
- `/samples/Dispov2/DISPO_2026.xlsx`
|
||||
- `/samples/Dispov2/20260309_Bi-Weekly_Chargeability_Reporting_Content_Production_V0.943_4Hartmut.xlsx`
|
||||
- `/samples/Dispov2/MV_DispoRoster.xlsx`
|
||||
- `/samples/Dispov2/Resource Roster_MASTER_FY26_CJ_20251201.xlsx`
|
||||
|
||||
The goal is not a raw workbook archive. The goal is a normalized Planarchy dataset that:
|
||||
|
||||
- wipes existing database data and starts from a clean baseline
|
||||
- imports canonical reference data first
|
||||
- stages operational Dispo data before commit
|
||||
- creates real projects, assignments, vacations, availability rules, and reporting inputs
|
||||
- does not create fake bookings for unassigned time
|
||||
- handles public holidays through the vacation planner
|
||||
|
||||
## Agreed Business Rules
|
||||
|
||||
These rules are fixed unless superseded by a later decision record:
|
||||
|
||||
- There is only one canonical person identifier. `EID` and `Enterprise ID` are the same source identity.
|
||||
- Existing database data should be wiped completely before the new import.
|
||||
- `[BMW]` is the client token.
|
||||
- `[11035763]` is the stable WBS/project key.
|
||||
- `{CH80}` means utilization category `CH` and `winProbability = 80`.
|
||||
- `_HB` and `_SB` suffixes can be ignored.
|
||||
- `TBD` means unassigned time. It must not create a fake project or fake booking.
|
||||
- `[tbd]` means unresolved project identity and should remain staged until resolved.
|
||||
- `2D` and `3D` map to chapter `Digital Content Production`.
|
||||
- `PM` maps to chapter `Project Management`.
|
||||
- `AD` maps to chapter `Art Direction`.
|
||||
- People booked on projects need the corresponding project role assigned on the booking.
|
||||
- Internal work categories should be mapped as normalized internal project/utilization buckets.
|
||||
- Public holidays should be modeled properly in the vacation planner.
|
||||
- Project start and end dates should be inferred from earliest and latest imported assignment dates.
|
||||
- Assignment granularity should normalize 50% to 4 hours and 100% to 8 hours.
|
||||
- Part-time import must reduce weekday availability on the days the person is not available.
|
||||
|
||||
## Source Workbook Roles
|
||||
|
||||
### 1. `MandatoryDispoCategories_V3.xlsx`
|
||||
|
||||
Use as the source of:
|
||||
|
||||
- reference/master-data vocabulary
|
||||
- client and project attribute glossary
|
||||
- calendar and SAH rules
|
||||
- validation guidance for resource attributes
|
||||
|
||||
Do not treat it as the primary source of transactional planning rows.
|
||||
|
||||
### 2. `DISPO_2026.xlsx`
|
||||
|
||||
Use as the primary source of:
|
||||
|
||||
- operational planning matrix
|
||||
- project bookings
|
||||
- internal work bookings
|
||||
- absences
|
||||
- public-holiday source hints
|
||||
- part-time hints
|
||||
- unassigned capacity
|
||||
|
||||
This workbook requires a parser. It is not directly importable as row-based CRUD input.
|
||||
|
||||
### 3. `Bi-Weekly Chargeability Reporting...xlsx`
|
||||
|
||||
Use as the source of:
|
||||
|
||||
- target and forecast reconciliation
|
||||
- resource enrichment when missing elsewhere
|
||||
- aggregate validation after commit
|
||||
|
||||
Do not treat PTD/MTD/YTD outputs as canonical source-of-truth records when Planarchy can derive them from normalized data.
|
||||
|
||||
### 4. `MV_DispoRoster.xlsx`
|
||||
|
||||
Use as the source of:
|
||||
|
||||
- operational resource master rows keyed by `EID`
|
||||
- `SAP_data` enrichment for real display names and email addresses
|
||||
- chapter, department, client-unit, FTE, and activity-window enrichment
|
||||
- pseudo-demand row filtering before any resource commit
|
||||
|
||||
Do not import `Demand_*` rows as real resources.
|
||||
|
||||
## Verified Source Constraint
|
||||
|
||||
The workbook set now includes both a row-based resource master source and a cost-rate source.
|
||||
|
||||
What is actually present:
|
||||
|
||||
- `MandatoryDispoCategories_V3.xlsx` `EID-Attr` is a glossary/reference sheet
|
||||
- `Bi-Weekly Chargeability Reporting...xlsx` provides roster identity, FTE, management group, chapter, metro city, and client unit
|
||||
- `MV_DispoRoster.xlsx` `DispoRoster` provides operational roster rows and `SAP_data` provides real email/display-name coverage for many resources
|
||||
- `Resource Roster_MASTER_FY26_CJ_20251201.xlsx` provides per-person `LCR` / `UCR` rows plus management-level averages for fallback resolution
|
||||
- `DISPO_2026.xlsx` provides transactional planning, vacation, holiday, and part-time signals
|
||||
|
||||
Implementation consequence:
|
||||
|
||||
- staging can be completed from the current workbook set
|
||||
- strict source-data blockers are cleared for the supplied workbook set
|
||||
- resources missing a source email are imported with fallback email `<EID>@accenture.com`
|
||||
- `demand_*` planning identities are ignored during staging and readiness checks
|
||||
- unresolved `[tbd]` project rows still remain staged by design and must not be auto-committed as final projects
|
||||
|
||||
## Current Implementation Status
|
||||
|
||||
Implemented in the application layer:
|
||||
|
||||
- reference workbook parser and stager
|
||||
- chargeability parser and stager
|
||||
- planning parser and stager
|
||||
- project resolution staging
|
||||
- roster parser and stager with `DispoRoster` + `SAP_data` merge logic
|
||||
- cost-rate parser and roster-rate merge logic with exact and management-level fallback resolution
|
||||
- readiness assessment over merged resource sources
|
||||
- batch staging orchestration across all current workbook inputs
|
||||
|
||||
Remaining import blocker for a strict production-grade commit:
|
||||
|
||||
- unresolved `[tbd]` project references that are intentionally kept out of final project commit
|
||||
|
||||
## Target Domain Model
|
||||
|
||||
The import commits into the existing planning model:
|
||||
|
||||
- `Country`
|
||||
- `MetroCity`
|
||||
- `OrgUnit`
|
||||
- `UtilizationCategory`
|
||||
- `Client`
|
||||
- `ManagementLevelGroup`
|
||||
- `ManagementLevel`
|
||||
- `Role`
|
||||
- `Resource`
|
||||
- `ResourceRole`
|
||||
- `Project`
|
||||
- `DemandRequirement`
|
||||
- `Assignment`
|
||||
- `Vacation`
|
||||
- `VacationEntitlement`
|
||||
|
||||
Relevant current schema anchors:
|
||||
|
||||
- [schema.prisma](/home/hartmut/Documents/Copilot/planarchy/packages/db/prisma/schema.prisma#L178)
|
||||
- [schema.prisma](/home/hartmut/Documents/Copilot/planarchy/packages/db/prisma/schema.prisma#L235)
|
||||
- [schema.prisma](/home/hartmut/Documents/Copilot/planarchy/packages/db/prisma/schema.prisma#L334)
|
||||
- [schema.prisma](/home/hartmut/Documents/Copilot/planarchy/packages/db/prisma/schema.prisma#L372)
|
||||
- [schema.prisma](/home/hartmut/Documents/Copilot/planarchy/packages/db/prisma/schema.prisma#L460)
|
||||
- [schema.prisma](/home/hartmut/Documents/Copilot/planarchy/packages/db/prisma/schema.prisma#L754)
|
||||
- [schema.prisma](/home/hartmut/Documents/Copilot/planarchy/packages/db/prisma/schema.prisma#L780)
|
||||
- [schema.prisma](/home/hartmut/Documents/Copilot/planarchy/packages/db/prisma/schema.prisma#L815)
|
||||
|
||||
## Required Implementation Changes
|
||||
|
||||
### 1. Canonical Person Identity
|
||||
|
||||
Planarchy currently stores both `eid` and `enterpriseId` on `Resource`. The import should operate on a single canonical identity.
|
||||
|
||||
Recommendation:
|
||||
|
||||
- choose `enterpriseId` as the canonical external person key
|
||||
- keep `eid` synchronized to the same value during transition, or remove its operational significance in the import path
|
||||
- reject imports that produce conflicting person rows for the same canonical identity
|
||||
|
||||
This avoids duplicate matching logic throughout staging and commit.
|
||||
|
||||
### 2. Staging Layer
|
||||
|
||||
Add dedicated staging tables or equivalent durable import records. The staging layer is required.
|
||||
|
||||
Recommended staging entities:
|
||||
|
||||
- `ImportBatch`
|
||||
- `StagedResource`
|
||||
- `StagedClient`
|
||||
- `StagedProject`
|
||||
- `StagedAssignment`
|
||||
- `StagedVacation`
|
||||
- `StagedAvailabilityRule`
|
||||
- `StagedUnresolvedRecord`
|
||||
|
||||
Each staged record should retain:
|
||||
|
||||
- source workbook name
|
||||
- sheet name
|
||||
- row number
|
||||
- original raw value
|
||||
- normalized parsed fields
|
||||
- parser warnings
|
||||
- resolution status
|
||||
|
||||
The staging layer is the review boundary between workbook parsing and final commit.
|
||||
|
||||
### 3. Clean-Slate Reset
|
||||
|
||||
Before final import, wipe the existing database contents.
|
||||
|
||||
Recommended reset scope:
|
||||
|
||||
- business data
|
||||
- auth/session data
|
||||
- derived snapshots
|
||||
- previous import artifacts
|
||||
|
||||
After reset, reseed immediately:
|
||||
|
||||
- admin user
|
||||
- access roles and permissions required to sign in
|
||||
- essential platform defaults
|
||||
- import reference seed data only when not supplied from the workbooks
|
||||
|
||||
Implementation note:
|
||||
|
||||
- take a full backup before reset
|
||||
- make the reset command idempotent in non-production development environments
|
||||
- require an explicit force flag in scripts
|
||||
|
||||
## Two-Step Import Flow
|
||||
|
||||
### Step A. Stage
|
||||
|
||||
### Goals
|
||||
|
||||
- parse all source files
|
||||
- normalize tokens
|
||||
- build deterministic staging rows
|
||||
- surface conflicts before any planning data is committed
|
||||
|
||||
### Responsibilities
|
||||
|
||||
1. ingest workbook files
|
||||
2. parse reference/master data
|
||||
3. parse planning matrix cells into typed staging records
|
||||
4. detect conflicts and unresolved cases
|
||||
5. generate a review report
|
||||
|
||||
### Stage Output
|
||||
|
||||
- staged resources
|
||||
- staged roles
|
||||
- staged chapters/org mapping
|
||||
- staged clients
|
||||
- staged projects
|
||||
- staged assignments
|
||||
- staged vacations/public holidays
|
||||
- staged part-time availability rules
|
||||
- unresolved `[tbd]` project references
|
||||
- unresolved identity conflicts
|
||||
|
||||
### Step B. Commit
|
||||
|
||||
### Goals
|
||||
|
||||
- write only validated data
|
||||
- preserve traceability to staging
|
||||
- block unresolved project identities
|
||||
|
||||
### Responsibilities
|
||||
|
||||
1. create reference data
|
||||
2. create resources and roles
|
||||
3. create projects and internal buckets
|
||||
4. create assignments
|
||||
5. create vacations/public holidays
|
||||
6. apply availability overrides
|
||||
7. run reconciliation against chargeability workbook aggregates
|
||||
|
||||
### Commit Rules
|
||||
|
||||
- unresolved `[tbd]` project rows must not silently create final projects
|
||||
- unassigned time must not create assignments
|
||||
- weekend markers must not create vacation rows
|
||||
- all project bookings must resolve to a role and utilization category
|
||||
- all resources must resolve to a canonical person ID
|
||||
|
||||
## Field Mapping
|
||||
|
||||
### Reference Data Mapping
|
||||
|
||||
| Source | Field/Token | Target | Notes |
|
||||
| ---------------------------------- | ------------------------ | --------------------------------------------------------------------- | -------------------------------------------- |
|
||||
| `MandatoryDispoCategories_V3.xlsx` | `Country/Territory` | `Country` | source for country master data and SAH rules |
|
||||
| `MandatoryDispoCategories_V3.xlsx` | `Metro City` | `MetroCity` | child of country |
|
||||
| `MandatoryDispoCategories_V3.xlsx` | `Chapter` / org labels | `OrgUnit` and `Resource.chapter` | normalize level mapping during stage |
|
||||
| `MandatoryDispoCategories_V3.xlsx` | `Management Level Group` | `ManagementLevelGroup` | includes target percentage reference |
|
||||
| `MandatoryDispoCategories_V3.xlsx` | `Management Level` | `ManagementLevel` | child of management level group |
|
||||
| `MandatoryDispoCategories_V3.xlsx` | `WBS Master Client` | `Client` parent | master client node |
|
||||
| `MandatoryDispoCategories_V3.xlsx` | `WBS Client Name` | `Client` child | legal/sub-client node |
|
||||
| `MandatoryDispoCategories_V3.xlsx` | SAH rules | `Country.dailyWorkingHours`, schedule logic, holiday generation rules | not all rules map 1:1 yet |
|
||||
|
||||
### Resource Mapping
|
||||
|
||||
| Source | Field | Target | Notes |
|
||||
| ----------------------------------------- | ------------------------- | ----------------------------------------------------- | ------------------------------------------------------ |
|
||||
| `EID-Attr`, `ChgFC`, `Dispo` row metadata | `Enterprise ID` / `EID` | canonical resource key | one identity only |
|
||||
| `ChgFC` | `FTE` | `Resource.fte` | baseline contract capacity |
|
||||
| `ChgFC` | `Management Level Group` | `Resource.managementLevelGroupId` | reference lookup |
|
||||
| `EID-Attr` | `Management Level` | `Resource.managementLevelId` | reference lookup |
|
||||
| `ChgFC` | `Metro City` | `Resource.metroCityId` | resolve via master data |
|
||||
| `EID-Attr` | `Country/Territory` | `Resource.countryId` | resolve via master data |
|
||||
| `ChgFC` | `MV Org Unit 1 / Chapter` | `Resource.chapter` / `Resource.orgUnitId` | normalize by agreed mapping |
|
||||
| `EID-Attr` | `Unit (Client Unit)` | `Resource.clientUnitId` | lookup to client tree if modeled there |
|
||||
| `EID-Attr` | `Ressource Type` | `Resource.resourceType` | enum mapping required |
|
||||
| `EID-Attr` | `LCR` | `Resource.lcrCents` | normalize currency to cents |
|
||||
| `EID-Attr` | `UCR` | `Resource.ucrCents` | normalize currency to cents |
|
||||
| `ChgFC` | `Target (per Level)` | `Resource.chargeabilityTarget` or group target source | use management group target as primary when consistent |
|
||||
|
||||
Rate resolution during staging:
|
||||
|
||||
- `Resource Roster_MASTER_FY26_CJ_20251201.xlsx` is the primary cost-rate source.
|
||||
- Exact `EID`/enterprise matches populate `lcrCents` and `ucrCents` directly.
|
||||
- If a person is missing in the cost workbook, the importer falls back to same-management-level averages from that workbook.
|
||||
- Only resources with neither an exact row nor a usable management-level fallback remain readiness blockers for LCR/UCR.
|
||||
|
||||
### Chapter and Role Mapping
|
||||
|
||||
Resource chapter mapping:
|
||||
|
||||
| Token | Resource chapter |
|
||||
| ----- | ---------------------------- |
|
||||
| `2D` | `Digital Content Production` |
|
||||
| `3D` | `Digital Content Production` |
|
||||
| `PM` | `Project Management` |
|
||||
| `AD` | `Art Direction` |
|
||||
|
||||
Assignment role mapping:
|
||||
|
||||
| Token | Assignment role |
|
||||
| ----- | ----------------- |
|
||||
| `2D` | `2D Artist` |
|
||||
| `3D` | `3D Artist` |
|
||||
| `PM` | `Project Manager` |
|
||||
| `AD` | `Art Director` |
|
||||
|
||||
Implementation guidance:
|
||||
|
||||
- chapter is a resource-organizational dimension
|
||||
- role is an assignment-level delivery dimension
|
||||
- assign both when both are known
|
||||
|
||||
### Project Mapping
|
||||
|
||||
| Source token | Target | Notes |
|
||||
| ------------------------ | -------------------------------------------------------------- | ------------------------------------------ |
|
||||
| `[BMW]` | `Project.clientId` | resolve to client |
|
||||
| `[11035763]` | stable WBS key | recommended source for `Project.shortCode` |
|
||||
| `{CH80}` | `Project.utilizationCategoryId`, `Project.winProbability = 80` | parser splits prefix and numeric suffix |
|
||||
| project text body | `Project.name` | cleaned of helper suffixes |
|
||||
| earliest assignment date | `Project.startDate` | inferred |
|
||||
| latest assignment date | `Project.endDate` | inferred |
|
||||
| `[tbd]` | unresolved staged project | do not auto-commit as final project |
|
||||
|
||||
### Utilization and Planning Token Mapping
|
||||
|
||||
| Token family | Meaning | Commit target |
|
||||
| ------------ | ---------------------------------- | --------------------------------------------------------------------- |
|
||||
| `CH` | chargeable client work | project assignment |
|
||||
| `MO` | management and operations | internal project/bucket assignment |
|
||||
| `MD` | market development / initiative | internal project/bucket assignment |
|
||||
| `PD` | personal development / recruitment | internal project/bucket assignment |
|
||||
| `AB` | absence | vacation row |
|
||||
| `NA` | non-bookable / calendar state | usually availability or derived calendar rule, not project assignment |
|
||||
| `UN` | unassigned | no assignment commit |
|
||||
|
||||
### Assignment Mapping
|
||||
|
||||
Assignments should be written only when a project or internal bucket is resolved.
|
||||
|
||||
| Source | Target | Notes |
|
||||
| --------------------- | --------------------------------------- | --------------------------------------------------------- |
|
||||
| project booking cell | `Assignment` | resource, project, role, start/end, hours/day, percentage |
|
||||
| internal `MO` cell | `Assignment` to internal project/bucket | utilization category `M&O` |
|
||||
| internal `MD` cell | `Assignment` to internal project/bucket | utilization category `MD&I` |
|
||||
| internal `PD` cell | `Assignment` to internal project/bucket | utilization category `PD&R` |
|
||||
| `[_UN] unassign {UN}` | no final assignment | capacity remains free |
|
||||
|
||||
### Vacation and Holiday Mapping
|
||||
|
||||
| Source token | Target | Notes |
|
||||
| ------------------------------- | ------------------------------- | -------------------------------------------------------- |
|
||||
| `[_AB] ... {AB}` | `Vacation` | approved absence row |
|
||||
| `[_NA] Public Holiday ... {NA}` | `Vacation(type=PUBLIC_HOLIDAY)` | preferred source of truth is geography-driven generation |
|
||||
| `[_NA] Weekend {NA}` | no vacation row | derive from calendar |
|
||||
|
||||
Public holiday implementation should integrate with the existing vacation planner and batch holiday support in [vacation.ts](/home/hartmut/Documents/Copilot/planarchy/packages/api/src/router/vacation.ts#L425).
|
||||
|
||||
### Availability and Part-Time Mapping
|
||||
|
||||
Part-time markers must alter resource availability instead of creating fake bookings.
|
||||
|
||||
Rules:
|
||||
|
||||
- `100%` maps to 8 available hours on a standard full working day
|
||||
- `50%` maps to 4 available hours on a standard full working day
|
||||
- part-time markers should reduce weekday availability on non-working or reduced-working days
|
||||
|
||||
Recommended commit target:
|
||||
|
||||
- `Resource.fte` remains the contractual baseline
|
||||
- `Resource.availability` stores actual weekday available hours
|
||||
|
||||
Examples:
|
||||
|
||||
- 75% with one day fully off per week:
|
||||
- availability sets one weekday to `0`
|
||||
- 80% with reduced time across five weekdays:
|
||||
- availability distributes reduced hours across weekdays
|
||||
|
||||
If the workbook does not encode the weekday pattern explicitly:
|
||||
|
||||
- stage the record as `availabilityPattern = unresolved`
|
||||
- commit only the `fte`
|
||||
- require manual review before applying weekday reductions
|
||||
|
||||
## Parser Design
|
||||
|
||||
The `DISPO_2026.xlsx` parser should operate at calendar-slot level and emit normalized staging records.
|
||||
|
||||
### Parser Inputs
|
||||
|
||||
- workbook name
|
||||
- sheet name
|
||||
- row identity
|
||||
- day/column identity
|
||||
- source token text
|
||||
- resource roster metadata from the row
|
||||
|
||||
### Parser Outputs
|
||||
|
||||
- normalized booking type
|
||||
- resource canonical ID
|
||||
- date
|
||||
- slot fraction
|
||||
- hours per day
|
||||
- percentage
|
||||
- client token
|
||||
- WBS
|
||||
- utilization category
|
||||
- win probability
|
||||
- role token
|
||||
- chapter token
|
||||
- ignore flags
|
||||
- unresolved reason when parsing fails
|
||||
|
||||
### Token Normalization Rules
|
||||
|
||||
1. strip ignored suffixes like `_HB`, `_SB`
|
||||
2. extract client from `[CLIENT]`
|
||||
3. extract WBS from `[12345678]` when numeric
|
||||
4. extract unresolved project marker from `[tbd]`
|
||||
5. extract utilization and win probability from `{CH80}`
|
||||
6. extract role prefix from leading `2D`, `3D`, `PM`, `AD`
|
||||
7. classify special bracket tokens `[_AB]`, `[_NA]`, `[_UN]`, `[_MO]`, `[_MD]`, `[_PD]`
|
||||
|
||||
## Internal Project Strategy
|
||||
|
||||
Internal work should not be left as free text.
|
||||
|
||||
Recommendation:
|
||||
|
||||
- seed canonical internal projects or internal planning buckets for:
|
||||
- `M&O`
|
||||
- `MD&I`
|
||||
- `PD&R`
|
||||
- assign them consistent utilization categories
|
||||
- keep source token text in assignment metadata for traceability
|
||||
|
||||
This allows planning, reporting, and chargeability to remain normalized.
|
||||
|
||||
## `[tbd]` Resolution Strategy
|
||||
|
||||
`[tbd]` is not a valid final project identity.
|
||||
|
||||
Recommended behavior:
|
||||
|
||||
- stage as unresolved project demand
|
||||
- do not auto-create final project rows during commit
|
||||
- allow reviewer resolution by:
|
||||
- matching to existing WBS
|
||||
- creating a new real project
|
||||
- converting the row into intentional unassigned capacity
|
||||
- converting the row into a `DemandRequirement` when a role need is known but no confirmed project exists
|
||||
|
||||
This is the only area where a manual review gate is required by default.
|
||||
|
||||
## Public Holiday Strategy
|
||||
|
||||
Public holidays should be driven by geography and stored in the vacation planner.
|
||||
|
||||
Recommended approach:
|
||||
|
||||
1. resolve each resource to country and, where relevant, metro city/federal state
|
||||
2. generate public holidays for the applicable calendar year
|
||||
3. commit them as approved `Vacation(type=PUBLIC_HOLIDAY)` rows
|
||||
4. reconcile workbook holiday markers against generated rows
|
||||
|
||||
Known implementation gap:
|
||||
|
||||
- the chargeability forecast currently passes an empty `publicHolidays` list into SAH calculation in [chargeability-report.ts](/home/hartmut/Documents/Copilot/planarchy/packages/api/src/router/chargeability-report.ts#L167)
|
||||
|
||||
Required follow-up:
|
||||
|
||||
- make forecast logic consume public-holiday vacation rows or geography-derived holiday dates
|
||||
|
||||
## Reconciliation and Acceptance Checks
|
||||
|
||||
After commit, run reconciliation against the chargeability workbook.
|
||||
|
||||
Required checks:
|
||||
|
||||
- resource count matches expected staged resource count
|
||||
- FTE totals by org unit match workbook aggregates within tolerance
|
||||
- chargeability targets by management group match expected values
|
||||
- project/client/WBS relationships are complete for all committed assignments
|
||||
- unassigned capacity is visible only as free capacity, not as fake bookings
|
||||
- vacations and public holidays are visible in the vacation planner
|
||||
- part-time resources show reduced weekday availability where resolved
|
||||
|
||||
## Suggested Implementation Order
|
||||
|
||||
1. add import staging schema and storage
|
||||
2. add full reset + reseed command
|
||||
3. add reference-data importer for `MandatoryDispoCategories_V3.xlsx`
|
||||
4. add canonical resource importer and identity normalization
|
||||
5. add role and chapter normalization
|
||||
6. add `DISPO_2026.xlsx` parser
|
||||
7. add staged project resolver for WBS and `[tbd]`
|
||||
8. add assignment commit flow
|
||||
9. add vacation and public-holiday import flow
|
||||
10. add part-time availability overlay logic
|
||||
11. add reconciliation report against `ChgFC` and aggregate sheets
|
||||
12. add rollback/replay support for repeated dry runs
|
||||
|
||||
## Operator Commands
|
||||
|
||||
For the clean-slate import workflow, use dedicated DB scripts instead of ad-hoc SQL:
|
||||
|
||||
- reset and bootstrap a disposable environment:
|
||||
- `pnpm --filter @planarchy/db db:reset:dispo -- --force`
|
||||
- reset without `pg_dump` backup only in an intentionally disposable environment:
|
||||
- `pnpm --filter @planarchy/db db:reset:dispo -- --force --skip-backup`
|
||||
- seed Dispo v2 reference vocabulary after reset:
|
||||
- `pnpm --filter @planarchy/db db:seed:dispo-v2`
|
||||
|
||||
The reset command:
|
||||
|
||||
- backs up the database with `pg_dump` by default
|
||||
- truncates all public tables except Prisma migration history
|
||||
- recreates a bootstrap admin user and baseline `SystemSettings`
|
||||
- leaves workbook-derived reference and transactional data to the import pipeline
|
||||
|
||||
## Decision Log
|
||||
|
||||
The following decisions are locked for implementation and should be treated as the canonical baseline for all downstream tickets.
|
||||
|
||||
### D1. Canonical Resource Identity
|
||||
|
||||
- `enterpriseId` is the canonical external person key for all staged and committed import logic.
|
||||
- `eid` remains in the schema as a compatibility alias during the transition period.
|
||||
- the importer must mirror the canonical identity into both `enterpriseId` and `eid` on committed `Resource` rows unless a later cleanup ticket removes `eid`
|
||||
- conflicting source rows for the same canonical identity must remain staged and unresolved
|
||||
|
||||
### D2. Reset And Bootstrap Scope
|
||||
|
||||
- the clean-slate reset wipes business data, auth/session data, notifications, audit logs, estimate data, and previous import artifacts
|
||||
- the reset must reseed a bootstrap admin user, baseline platform permissions, and required singleton settings immediately after wipe
|
||||
- imported workbook data is not the source of truth for platform access bootstrapping
|
||||
- reset remains an explicit operator action with backup-first workflow
|
||||
|
||||
### D3. `[tbd]` Commit Policy
|
||||
|
||||
- `[tbd]` rows never auto-create final `Project` rows
|
||||
- `[tbd]` rows remain staged and unresolved by default
|
||||
- a reviewer may explicitly resolve a `[tbd]` row into:
|
||||
- an existing real project
|
||||
- a newly created real project
|
||||
- intentional unassigned capacity
|
||||
- a `DemandRequirement`
|
||||
- automatic commit logic must skip unresolved `[tbd]` rows
|
||||
|
||||
### D4. Default Part-Time Fallback
|
||||
|
||||
- when the workbook encodes an explicit weekday pattern, the importer must commit that exact reduced availability pattern
|
||||
- when only an FTE/percentage is known, the importer should distribute the reduced weekly capacity evenly across Monday to Friday
|
||||
- any such fallback must be marked with a staging warning so operators can refine the weekday pattern later
|
||||
- examples:
|
||||
- `100%` => `8/8/8/8/8`
|
||||
- `50%` => `4/4/4/4/4`
|
||||
- `80%` => `6.4/6.4/6.4/6.4/6.4`
|
||||
|
||||
### D5. Internal Project Buckets
|
||||
|
||||
Seed canonical internal planning projects/buckets as follows:
|
||||
|
||||
| Source token | Project short code | Project name | Utilization category |
|
||||
| ------------ | ------------------ | ---------------------------------- | -------------------- |
|
||||
| `MO` | `INT-MO` | `Management & Operations` | `M&O` |
|
||||
| `MD` | `INT-MD` | `Market Development & Initiatives` | `MD&I` |
|
||||
| `PD` | `INT-PD` | `People Development & Recruitment` | `PD&R` |
|
||||
|
||||
The importer should preserve the original source token in staged and committed metadata for traceability.
|
||||
|
||||
### D6. Seeded Role Vocabulary
|
||||
|
||||
The baseline role seed list required for Dispo import is:
|
||||
|
||||
- `2D Artist`
|
||||
- `3D Artist`
|
||||
- `Project Manager`
|
||||
- `Art Director`
|
||||
|
||||
These roles are assignment-level delivery roles. They do not replace chapter/org ownership on the resource profile.
|
||||
|
||||
## Recommendation
|
||||
|
||||
Proceed with a staged importer and treat this document as the implementation baseline.
|
||||
|
||||
The critical architectural choices are:
|
||||
|
||||
- clean-slate reset
|
||||
- canonical single-ID resource matching
|
||||
- staged parsing before commit
|
||||
- no fake unassigned bookings
|
||||
- explicit assignment roles separate from resource chapters
|
||||
- geography-driven public holidays in the vacation planner
|
||||
- manual resolution gate only for `[tbd]` and unresolved availability patterns
|
||||
@@ -0,0 +1,308 @@
|
||||
# Estimating Extension Design
|
||||
|
||||
**Date:** 2026-03-13
|
||||
**Related workbook:** `samples/CGIBreakdown_Template/Template_CGI-Breakdown+Calc_25Dez_V0.976_251212_beta_LCR-Update.xlsx`
|
||||
**Purpose:** Canonical design, field mapping, and implementation plan for a browser-based estimating system in Planarchy.
|
||||
|
||||
## Executive Summary
|
||||
|
||||
The workbook is not a simple calculator. It is a full estimating and pricing system with:
|
||||
|
||||
- project and commercial assumptions
|
||||
- scope breakdown for shots and assets
|
||||
- roster and rate lookups
|
||||
- phased effort and cost calculations
|
||||
- management summaries
|
||||
- downstream export sheets
|
||||
|
||||
Planarchy can support this, but not by copying Excel cell logic into the browser. The right implementation is a dedicated estimating bounded context with:
|
||||
|
||||
- a wizard for first-pass estimate creation
|
||||
- a workspace for iterative revisions
|
||||
- a typed calculation pipeline
|
||||
- live linkage to Planarchy resources and roles
|
||||
- immutable snapshots for auditability
|
||||
|
||||
## Design Principles
|
||||
|
||||
### 1. Do not emulate Excel
|
||||
|
||||
The workbook contains very large formula surfaces, including roughly 823k formula cells in `CALC_AUX` alone. Rebuilding that as browser spreadsheet emulation would preserve the current maintenance problem instead of solving it.
|
||||
|
||||
The replacement should be:
|
||||
|
||||
- typed
|
||||
- stage-based
|
||||
- versioned
|
||||
- testable
|
||||
- explainable
|
||||
|
||||
### 2. Reuse the current platform where it already fits
|
||||
|
||||
Useful existing Planarchy primitives:
|
||||
|
||||
- `Resource` for roster, rates, skills, availability, and dynamic metadata
|
||||
- `Project` for schedule, budget, and project linkage
|
||||
- `Role` for assignment and capability alignment
|
||||
- blueprint-driven fields for temporary bridge data where first-class models do not yet exist
|
||||
|
||||
### 3. Keep estimating separate from operational staffing
|
||||
|
||||
Estimating answers:
|
||||
|
||||
- what work is assumed
|
||||
- what rates and policies apply
|
||||
- what cost, price, and margin result
|
||||
|
||||
Operational planning answers:
|
||||
|
||||
- who is actually assigned
|
||||
- when capacity is consumed
|
||||
- how delivery is staffed in reality
|
||||
|
||||
`DemandRequirement` and `Assignment` are downstream execution data, not the primary estimating store.
|
||||
|
||||
## Product Shape
|
||||
|
||||
### Estimate Wizard
|
||||
|
||||
The wizard should generate the first complete draft through structured steps:
|
||||
|
||||
1. Opportunity and project shell
|
||||
2. Scope breakdown
|
||||
3. Commercial assumptions
|
||||
4. Staffing strategy
|
||||
5. Rate and resource matching
|
||||
6. Financial review
|
||||
7. Export and approval
|
||||
|
||||
### Estimate Workspace
|
||||
|
||||
After the wizard, the user should move into a workspace with tabs:
|
||||
|
||||
- `Overview`
|
||||
- `Scope Breakdown`
|
||||
- `Assumptions`
|
||||
- `Rates & Resources`
|
||||
- `Staffing / Phasing`
|
||||
- `Financials`
|
||||
- `Exports`
|
||||
- `Version Compare`
|
||||
|
||||
This replaces the giant spreadsheet with a clearer domain-oriented UI.
|
||||
|
||||
## Workbook Domains
|
||||
|
||||
The analyzed workbook combines several distinct domains:
|
||||
|
||||
- input and assumption sheets such as `ProjectInfo`, `Shots&Assets_Breakdown`, `ratesBreakdown`, and `Ressource Roster MASTER`
|
||||
- reference catalogs such as `ExperienceAdjust`, `Packages`, `IT Rate card`, `machine_rates`, `FX`, and `Rates ACN`
|
||||
- derived engine sheets such as `Calculation`, `CALC_AUX`, `4Dispo`, `SAP Phasing`, and `MMP Import`
|
||||
- management and reporting views such as `Overview_*`, `Cockpit`, `Analytics`, and `Per Year`
|
||||
|
||||
That mix is exactly why the app needs separated models for assumptions, scope, demand, rates, snapshots, outputs, and exports.
|
||||
|
||||
## Proposed Domain Model
|
||||
|
||||
### New bounded context: `Estimating`
|
||||
|
||||
| Model | Purpose |
|
||||
|---|---|
|
||||
| `Estimate` | Top-level estimate container tied to a project or opportunity |
|
||||
| `EstimateVersion` | Versioning, options, baselines, approvals, and locked commercial states |
|
||||
| `EstimateAssumption` | Structured commercial, tax, pricing, and scenario inputs |
|
||||
| `ScopeItem` | Scope rows imported or authored from the breakdown sheet |
|
||||
| `ScopeEffortRule` | Rules that turn scope into discipline effort |
|
||||
| `EstimateDemandLine` | Normalized effort lines with phasing and pricing attributes |
|
||||
| `RateCard` | Versioned pricing and cost catalog |
|
||||
| `RateCardLine` | Attribute-based rate resolution entries |
|
||||
| `ResourceCostSnapshot` | Immutable copy of roster/rate facts used by one estimate version |
|
||||
| `EstimateMetric` | Persisted derived totals for fast reads and auditability |
|
||||
| `EstimateExport` | Stored export artifacts and serializer metadata |
|
||||
|
||||
### Reuse strategy
|
||||
|
||||
| Existing model | Reuse level | How it fits |
|
||||
|---|---|---|
|
||||
| `Project` | `Direct` | Parent linkage, timeline context, budget bridge |
|
||||
| `Resource` | `Direct` | Roster, chapter, role, LCR/UCR, skill and availability context |
|
||||
| `Role` | `Direct` | Demand-line role alignment and staffing suggestions |
|
||||
| `DemandRequirement` / `Assignment` | `Downstream` | Planning handoff target after estimate approval |
|
||||
| `dynamicFields` / blueprints | `Bridge only` | Short-term bridge for unmigrated metadata, not core estimate storage |
|
||||
|
||||
## Mapping Strategy
|
||||
|
||||
### Mapping legend
|
||||
|
||||
- `Direct`: already maps to an existing first-class Planarchy field
|
||||
- `Bridge`: can be bridged short-term, but should move to estimating models
|
||||
- `Derived`: calculate it, do not persist it as manual source data
|
||||
- `New Model`: requires estimating schema
|
||||
|
||||
### Project and commercial inputs
|
||||
|
||||
| Workbook field | Current target | Status | Recommended target |
|
||||
|---|---|---|---|
|
||||
| Project Name | `Project.name` | `Direct` | keep on `Project`, mirror into `Estimate.name` |
|
||||
| Opportunity ID | project dynamic field | `Bridge` | `Estimate.opportunityId` |
|
||||
| Timeframe From / To | `Project.startDate` / `Project.endDate` | `Direct` | default estimate context from project |
|
||||
| Currency | project/resource bridge only | `Bridge` | `Estimate.baseCurrency` |
|
||||
| Contract Owner / Business Unit / Service Group | none | `New Model` | `EstimateAssumption.*` |
|
||||
| Pricing Structure | partly `Project.orderType` | `Bridge` | `EstimateAssumption.pricingStructure` |
|
||||
| Revenue Timing / Recognition | none | `New Model` | `EstimateAssumption.*` |
|
||||
| Sales Tax / Billing Arrears / Payment Terms | none | `New Model` | `EstimateAssumption.*` |
|
||||
| Contingency / Capital Charge / Mgmt Fee policies | none | `New Model` | `EstimateAssumption.*` |
|
||||
|
||||
### Scope breakdown inputs
|
||||
|
||||
| Workbook field | Current target | Status | Recommended target |
|
||||
|---|---|---|---|
|
||||
| Row sequence, type, package | none | `New Model` | `ScopeItem.sequenceNo`, `scopeType`, `packageCode` |
|
||||
| Description, scene, page, location | coarse project notes only | `New Model` | `ScopeItem.*` |
|
||||
| Assumptions / comments | none | `New Model` | `ScopeItem.assumptionCategory`, `internalComments` |
|
||||
| Resolution / FPS / aspect / shot length | project dynamic fields only | `Bridge` | `ScopeItem.technicalSpec` JSON |
|
||||
| Frame count / count / unit mode | limited bridge only | `Bridge` | `ScopeItem.frameCount`, `count`, `unitMode` |
|
||||
| Discipline effort columns | none | `New Model` | generated `EstimateDemandLine` rows |
|
||||
| Total costs on the breakdown sheet | none | `Derived` | `EstimateMetric` |
|
||||
|
||||
### Resource, rate, and lookup data
|
||||
|
||||
| Workbook field | Current target | Status | Recommended target |
|
||||
|---|---|---|---|
|
||||
| Roster employee/name | `Resource.displayName` / `eid` | `Bridge` | link to `Resource` plus snapshot source text |
|
||||
| UCR / LCR | `Resource.ucrCents` / `lcrCents` | `Direct` | direct reuse plus snapshot |
|
||||
| FTE | indirect only | `Bridge` | `ResourceCostSnapshot.fte` |
|
||||
| Level / work type / area | dynamic fields only | `Bridge` | normalize later, snapshot now |
|
||||
| Location / country | dynamic bridge only | `Bridge` | snapshot + demand-line attributes |
|
||||
| Rates ACN / rate breakdown / machine / FX | none | `New Model` | `RateCard`, `RateCardLine`, FX/rule tables |
|
||||
| Experience adjustments | none | `New Model` | rate adjustment rules |
|
||||
|
||||
### Calculation, phasing, and exports
|
||||
|
||||
| Workbook field group | Current target | Status | Recommended target |
|
||||
|---|---|---|---|
|
||||
| Calculation line items | none | `New Model` | `EstimateDemandLine` |
|
||||
| Named resource references | `Assignment.resourceId` via planning handoff | `Direct` | linked demand line + resource snapshot |
|
||||
| Dates, hours, bill code, org unit, economic profile | none | `New Model` | `EstimateDemandLine.*` |
|
||||
| Monthly spread | none | `New Model` | `EstimateDemandLine.monthlySpread` |
|
||||
| Weekly phasing (`4Dispo`) | none | `Derived` | generated projection view |
|
||||
| `CALC_AUX` transformed outputs | none | `Derived` | derived from demand lines and snapshots |
|
||||
| `MMP Import` / external export sheets | none | `New Model` | serializer output + `EstimateExport` |
|
||||
| Cockpit / analytics totals | none | `Derived` | persisted `EstimateMetric` rows |
|
||||
|
||||
## Browser Architecture
|
||||
|
||||
### Calculation engine
|
||||
|
||||
Implement a typed calculation pipeline in `packages/engine`:
|
||||
|
||||
1. validate assumptions and scope
|
||||
2. resolve effort rules into demand lines
|
||||
3. resolve roster/rate snapshots
|
||||
4. calculate phased costs, prices, and metrics
|
||||
5. materialize outputs for UI and export
|
||||
|
||||
This should be deterministic and test-first. Manual overrides must be explicit and traceable.
|
||||
|
||||
### Resource-connected behavior
|
||||
|
||||
The browser system can stay dynamic and resource-connected if it uses two data modes at once:
|
||||
|
||||
- live links to `Resource` and `Role` for current matching and suggestion UX
|
||||
- immutable snapshots on `EstimateVersion` for pricing, auditability, and approval history
|
||||
|
||||
That prevents old approved estimates from changing when roster rates or metadata are edited later.
|
||||
|
||||
## Implementation Plan
|
||||
|
||||
### Phase 1. Schema and contracts
|
||||
|
||||
- add `Estimate`, `EstimateVersion`, `EstimateAssumption`, `ScopeItem`, `EstimateDemandLine`, `RateCard`, `RateCardLine`, `ResourceCostSnapshot`, `EstimateMetric`, and `EstimateExport`
|
||||
- define DTOs and use cases in `packages/application`
|
||||
- create engine contracts and test fixtures
|
||||
|
||||
### Phase 2. Wizard and workspace
|
||||
|
||||
- build the estimate wizard
|
||||
- add estimate workspace routes and tabs
|
||||
- support import from workbook-derived source data where useful
|
||||
|
||||
### Phase 3. Calculation and pricing
|
||||
|
||||
- implement rule engine for scope-to-effort conversion
|
||||
- add rate resolution and cost/price calculations
|
||||
- persist metrics and audit trail
|
||||
|
||||
### Phase 4. Resource linkage and planning handoff
|
||||
|
||||
- connect demand lines to resources, roles, and availability
|
||||
- add staffing suggestions from current Planarchy data
|
||||
- support conversion from approved estimate demand into downstream planning entities
|
||||
|
||||
### Phase 5. Exports and approvals
|
||||
|
||||
- generate external export formats
|
||||
- add version compare, lock, approval, and audit views
|
||||
|
||||
## Current Status
|
||||
|
||||
This is no longer design-only.
|
||||
|
||||
Implemented baseline in the current codebase:
|
||||
|
||||
- estimating Prisma schema and enums
|
||||
- shared estimate types and validation schemas
|
||||
- engine-level summary metric helper
|
||||
- application-layer estimate creation and retrieval use-cases
|
||||
- estimate API router registration
|
||||
- estimates list route and first estimate creation wizard
|
||||
- estimate workspace detail route with overview, assumptions, scope, staffing, versions, and exports tabs
|
||||
- working-draft editor for overview, assumptions, scope, and staffing
|
||||
- version submit, approve, and locked revision-cloning actions
|
||||
- export artifact scaffolding with stored serializer metadata records
|
||||
- format-specific export generation with stored payloads for JSON, CSV, XLSX, SAP, and MMP
|
||||
- live resource-linked staffing rows that can sync current Planarchy rates and persist estimate-version snapshots
|
||||
- explicit live-vs-manual rate mode metadata on demand lines, with server-side recalculation before metrics are persisted
|
||||
- read-only and draft workspace visibility for manual overrides versus live resource snapshots
|
||||
- project snapshot persistence on estimate versions
|
||||
- approved-version planning handoff into downstream `DemandRequirement` and `Assignment` records, with estimate lineage metadata
|
||||
- scope import from XLSX in the estimate wizard
|
||||
- financials tab in the estimate workspace with summary cards, cost-to-price bridge, chapter breakdown, and monthly phasing
|
||||
- rate cards with per-client association and client filter in the admin UI
|
||||
|
||||
Still open:
|
||||
|
||||
- estimate templates and cloning for recurring project types
|
||||
- richer version comparison (side-by-side diff of demand lines and metrics)
|
||||
- approval email notifications
|
||||
- scope-to-effort rule engine (currently manual demand lines only)
|
||||
- rate adjustment rules and experience multipliers
|
||||
|
||||
## Planning Handoff Model
|
||||
|
||||
The demand/assignment persistence split is complete. The legacy `Allocation` table has been dropped.
|
||||
|
||||
### Current behavior
|
||||
|
||||
Approved estimate versions hand off like this:
|
||||
|
||||
1. one `DemandRequirement` is created per normalized estimate demand line
|
||||
2. if a linked resource is valid, an `Assignment` is created linked to that demand
|
||||
3. if no valid resource is available, the demand stays open with the suggested resource stored in metadata
|
||||
4. estimate provenance is preserved on both records through `estimateHandoff` metadata
|
||||
|
||||
### Estimate-to-planning mapping
|
||||
|
||||
| Estimate source | DemandRequirement target | Assignment target | Notes |
|
||||
|---|---|---|---|
|
||||
| `Estimate.projectId` + approved version | `projectId` | `projectId` | direct |
|
||||
| `EstimateDemandLine.id` | `metadata.estimateHandoff.estimateDemandLineId` | same | provenance |
|
||||
| `EstimateDemandLine.name` | `role` or demand title | copied display metadata | readable context |
|
||||
| `EstimateDemandLine.roleId` | `roleId` | optional copied roleId | direct when present |
|
||||
| `EstimateDemandLine.resourceId` | `metadata.suggestedResourceId` when open | `resourceId` when assigned | demand vs assignment split eliminates nullable-resource ambiguity |
|
||||
| `EstimateDemandLine.hours` + project window | `hoursPerDay`, `percentage`, `headcount` | `hoursPerDay`, `percentage` | reused derivation logic |
|
||||
| `EstimateDemandLine.fte` | `headcount` | not needed | demand owns quantity |
|
||||
| rate and price totals | metadata snapshot | metadata snapshot | preserve auditability |
|
||||
| staffing attributes / monthly spread | metadata | metadata | direct carry-over |
|
||||
|
||||
The workbook mapping is feasible. The estimating product covers wizard creation, workspace editing, version management, export generation, and planning handoff. Remaining work focuses on templates, richer comparison, and the scope-to-effort rule engine.
|
||||
@@ -0,0 +1,9 @@
|
||||
# Migration Artifacts
|
||||
|
||||
Generated migration review artifacts are written here when a readiness or rehearsal command is run with artifact output enabled.
|
||||
|
||||
Current convention:
|
||||
|
||||
- demand/assignment readiness artifacts: `docs/migration-artifacts/demand-assignment/`
|
||||
|
||||
These files are operational evidence for cutover reviews, not canonical design documentation.
|
||||
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"totalAllocations": 132,
|
||||
"placeholderAllocations": 2,
|
||||
"staffedAllocations": 130,
|
||||
"invalidStaffedAllocationsWithoutResource": 0,
|
||||
"placeholderAllocationsWithResource": 0,
|
||||
"staffedAllocationsWithHeadcountGtOne": 0,
|
||||
"backfilledDemandRequirements": 2,
|
||||
"backfilledAssignments": 130,
|
||||
"pendingDemandBackfills": 0,
|
||||
"pendingAssignmentBackfills": 0,
|
||||
"explicitDemandRequirementsWithoutLegacyLink": 0,
|
||||
"explicitAssignmentsWithoutLegacyLink": 0,
|
||||
"orphanedDemandRequirementsWithLegacyLink": 0,
|
||||
"orphanedAssignmentsWithLegacyLink": 0,
|
||||
"warnings": 0,
|
||||
"errors": 0,
|
||||
"hasBlockingIssues": false
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"scanned": 132,
|
||||
"demandCreates": 0,
|
||||
"assignmentCreates": 0,
|
||||
"demandSkips": 2,
|
||||
"assignmentSkips": 130,
|
||||
"invalidSkips": 0,
|
||||
"warnings": 0,
|
||||
"errors": 0,
|
||||
"hasBlockingIssues": false
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
{
|
||||
"generatedAt": "2026-03-13T20:10:43.050Z",
|
||||
"projectId": null,
|
||||
"goNoGo": "go",
|
||||
"readyForApply": true,
|
||||
"blockers": [],
|
||||
"requiredArtifacts": [
|
||||
"audit.json",
|
||||
"dry-run.json",
|
||||
"readiness.json"
|
||||
],
|
||||
"recommendedNextStep": "Backfill apply may proceed after attaching the saved audit, dry-run, and readiness artifacts to the cutover review.",
|
||||
"audit": {
|
||||
"totalAllocations": 132,
|
||||
"placeholderAllocations": 2,
|
||||
"staffedAllocations": 130,
|
||||
"invalidStaffedAllocationsWithoutResource": 0,
|
||||
"placeholderAllocationsWithResource": 0,
|
||||
"staffedAllocationsWithHeadcountGtOne": 0,
|
||||
"backfilledDemandRequirements": 2,
|
||||
"backfilledAssignments": 130,
|
||||
"pendingDemandBackfills": 0,
|
||||
"pendingAssignmentBackfills": 0,
|
||||
"explicitDemandRequirementsWithoutLegacyLink": 0,
|
||||
"explicitAssignmentsWithoutLegacyLink": 0,
|
||||
"orphanedDemandRequirementsWithLegacyLink": 0,
|
||||
"orphanedAssignmentsWithLegacyLink": 0,
|
||||
"warnings": 0,
|
||||
"errors": 0,
|
||||
"hasBlockingIssues": false
|
||||
},
|
||||
"dryRun": {
|
||||
"scanned": 132,
|
||||
"demandCreates": 0,
|
||||
"assignmentCreates": 0,
|
||||
"demandSkips": 2,
|
||||
"assignmentSkips": 130,
|
||||
"invalidSkips": 0,
|
||||
"warnings": 0,
|
||||
"errors": 0,
|
||||
"hasBlockingIssues": false
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
# Archived Plan Note
|
||||
|
||||
Most of this plan has already been implemented:
|
||||
|
||||
- skill-matrix parsing and upload flows
|
||||
- `isMainSkill` support
|
||||
- resource metadata such as `portfolioUrl`, `aiSummary`, and `skillMatrixUpdatedAt`
|
||||
- admin system settings for AI configuration
|
||||
- AI summary generation and resource detail UI
|
||||
|
||||
Do not use this file as an active backlog. Remaining product work belongs in [docs/product-roadmap.md](/home/hartmut/Documents/Copilot/planarchy/docs/product-roadmap.md), and completed implementation detail is reflected in the codebase and [LEARNINGS.md](/home/hartmut/Documents/Copilot/planarchy/LEARNINGS.md).
|
||||
@@ -0,0 +1,15 @@
|
||||
# Archived Research Note
|
||||
|
||||
This review was a useful snapshot on 2026-03-06, but many of its findings are now resolved or outdated.
|
||||
|
||||
Examples that are no longer current:
|
||||
|
||||
- Argon2 auth mismatch is fixed
|
||||
- notification permissions were tightened
|
||||
- resource detail content exists
|
||||
- timeline virtualization exists
|
||||
- Excel support exists
|
||||
- Redis-backed SSE work has already landed
|
||||
- Playwright E2E coverage is no longer empty
|
||||
|
||||
Use [product-roadmap.md](/home/hartmut/Documents/Copilot/planarchy/docs/product-roadmap.md) for the active backlog and [v2-architecture-proposal-2026-03-11.md](/home/hartmut/Documents/Copilot/planarchy/research/v2-architecture-proposal-2026-03-11.md) for the still-relevant strategic direction.
|
||||
@@ -0,0 +1,3 @@
|
||||
# Archived Proposal Note
|
||||
|
||||
The CGI workbook analysis and implementation proposal were merged into [estimating-extension-design.md](/home/hartmut/Documents/Copilot/planarchy/docs/estimating-extension-design.md) so the estimating work now has one canonical document.
|
||||
@@ -0,0 +1,3 @@
|
||||
# Archived Mapping Note
|
||||
|
||||
The field mapping table was merged into [estimating-extension-design.md](/home/hartmut/Documents/Copilot/planarchy/docs/estimating-extension-design.md) so the estimating design, workbook analysis, and implementation plan live in one canonical file.
|
||||
@@ -0,0 +1,19 @@
|
||||
# Archived Research Note
|
||||
|
||||
This audit contained both fixed defects and still-useful scale warnings.
|
||||
|
||||
Already resolved from this document:
|
||||
|
||||
- dashboard budget aggregation bug
|
||||
- redundant second project-budget lookup
|
||||
- `batchImportSkillMatrices` N+1 pattern
|
||||
- `recomputeValueScores` sequential update pattern
|
||||
- extra user lookup during audit-log creation
|
||||
|
||||
Still conceptually relevant, but no longer the canonical backlog:
|
||||
|
||||
- SQL-first dashboard aggregation improvements
|
||||
- staffing suggestion scalability
|
||||
- index strategy for larger datasets
|
||||
|
||||
Use [product-roadmap.md](/home/hartmut/Documents/Copilot/planarchy/docs/product-roadmap.md) for active prioritization and keep this file only as archive context.
|
||||
@@ -0,0 +1,11 @@
|
||||
# Archived Plan Note
|
||||
|
||||
This file previously held the detailed implementation plan for table sorting, row ordering, and persistent view state.
|
||||
|
||||
That work is now only partially relevant as an archive:
|
||||
|
||||
- shared view-preference groundwork exists
|
||||
- several sorting/view-state pieces were implemented
|
||||
- Blueprints parity still appears open
|
||||
|
||||
The active backlog now lives in [docs/product-roadmap.md](/home/hartmut/Documents/Copilot/planarchy/docs/product-roadmap.md).
|
||||
@@ -0,0 +1,13 @@
|
||||
# Archived Sprint Note
|
||||
|
||||
This sprint plan mixed active refactor work with implementation mechanics that are now stale.
|
||||
|
||||
The still-relevant backlog from this document is tracked centrally in [product-roadmap.md](/home/hartmut/Documents/Copilot/planarchy/docs/product-roadmap.md):
|
||||
|
||||
- widget config typing and layout versioning
|
||||
- registry-driven dashboard rendering
|
||||
- shared dynamic-field validation and filter-building
|
||||
- project/resource validation parity
|
||||
- package-level regression tests
|
||||
|
||||
Treat this file as archived planning context, not the current source of truth.
|
||||
@@ -0,0 +1,447 @@
|
||||
# Product Roadmap And Status
|
||||
|
||||
**Date:** 2026-03-13
|
||||
**Purpose:** Canonical source for active roadmap, open gaps, and document ownership.
|
||||
|
||||
## Canonical Documents
|
||||
|
||||
- Active product and refactor backlog: this file
|
||||
- Estimating system design and workbook mapping: [estimating-extension-design.md](/home/hartmut/Documents/Copilot/planarchy/docs/estimating-extension-design.md)
|
||||
- Dispo clean-slate import design and field mapping: [dispo-import-implementation.md](/home/hartmut/Documents/Copilot/planarchy/docs/dispo-import-implementation.md)
|
||||
- Dispo worker ticket pack and dependency breakdown: [dispo-import-implementation-tickets.md](/home/hartmut/Documents/Copilot/planarchy/docs/dispo-import-implementation-tickets.md)
|
||||
- Demand/assignment migration cutover and readiness policy: [demand-assignment-migration-cutover.md](/home/hartmut/Documents/Copilot/planarchy/docs/demand-assignment-migration-cutover.md)
|
||||
- Strategic longer-horizon architecture direction: [v2-architecture-proposal-2026-03-11.md](/home/hartmut/Documents/Copilot/planarchy/research/v2-architecture-proposal-2026-03-11.md)
|
||||
- Implementation history and decisions: [LEARNINGS.md](/home/hartmut/Documents/Copilot/planarchy/LEARNINGS.md)
|
||||
|
||||
Older plans and reviews were left in place only as archive notes so active guidance is no longer split across stale task lists.
|
||||
|
||||
## Current Baseline
|
||||
|
||||
The following items were proposed in older markdown files and are already implemented enough that they should not stay on the active backlog:
|
||||
|
||||
- Argon2-based user creation and login compatibility
|
||||
- Manager-restricted notification creation
|
||||
- Resource detail surface
|
||||
- Timeline virtualization
|
||||
- Excel import and export support
|
||||
- Skill-matrix import flow, AI summary generation, and related resource metadata
|
||||
- View preference groundwork such as shared column/view preference types and hooks
|
||||
- Shared dynamic-field filter and blueprint-validation parity across project and resource APIs
|
||||
- Blueprints list parity with shared sort, selection, and view-preference behavior
|
||||
- Shared dashboard widget contracts, layout normalization/migration, and registry-driven rendering
|
||||
|
||||
## Active Workstreams
|
||||
|
||||
| Workstream | Status | Why It Is Still Open | Recommended Next Step |
|
||||
|---|---|---|---|
|
||||
| Estimating system | `In progress` | Full CRUD, versioning, export, planning handoff, clone/template, rate cards per client, and richer version comparison (scope item diffs, resource snapshot diffs, chapter subtotals, margin %). Remaining gaps: scope-to-effort rule engine, experience multipliers, weekly phasing, structured commercial terms. | Scope-to-effort rule engine for auto-expanding scope items into demand lines per discipline. |
|
||||
| Demand vs assignment split | `Complete` | Legacy `Allocation` table dropped. `legacyAllocationId` columns removed. Migration tooling deleted. Compatibility facades renamed to clean domain names (`updateAllocationEntry`, `deleteAllocationEntry`, `fillOpenDemand`, `loadAllocationEntry`). `isPlaceholder` is a derived read-model property. No legacy compatibility naming remains. | — |
|
||||
| Widget platform refactor | `Implemented` | Widget config typing, layout normalization, registry-driven rendering, and dashboard query extraction now live behind shared/application contracts instead of ad hoc router logic. | Keep future widgets on the same registry + application-use-case pattern. |
|
||||
| Package-level regression tests | `Expanded` | Shared schema validation (rate-card, allocation, estimate — 32 tests), engine vacation/recurrence (29 tests), staffing capacity-analyzer (12 tests), plus existing application and dashboard tests. | Continue adding API-level integration tests for remaining router procedures. |
|
||||
| Chargeability and resource planning (Dispo v2) | `Complete` | Plans 1-5 (schema, types, SAH engine, 5 API routers, 5 admin UIs, resource/project modal extensions), Phase A (live forecast report), Phase B (target comparison + drill-down grouping), Phase D (Excel/CSV export). Phase C (SAP actuals) removed from scope. | — |
|
||||
|
||||
## Prioritized Backlog
|
||||
|
||||
### 1. Estimating foundation
|
||||
|
||||
Build the estimating bounded context first. It is the largest product gap and the most structurally separate from the existing planning workflow.
|
||||
|
||||
Scope:
|
||||
|
||||
- Prisma models for estimate aggregates
|
||||
- typed calculation engine in `packages/engine`
|
||||
- estimate wizard and estimate workspace UI
|
||||
- rate-card and resource snapshot handling
|
||||
- export serializers
|
||||
|
||||
Current state:
|
||||
|
||||
- completed enough to use as foundation:
|
||||
- estimating Prisma schema
|
||||
- shared estimate types and schemas
|
||||
- engine summary helper
|
||||
- application-layer estimate use-cases
|
||||
- API estimate router registration
|
||||
- estimates list route and first create wizard
|
||||
- completed enough to use as foundation:
|
||||
- estimate workspace detail route with tabbed read surfaces
|
||||
- working-draft editor for overview, assumptions, scope, and staffing
|
||||
- live resource-linked staffing rows with snapshot persistence on save
|
||||
- completed in the current iteration:
|
||||
- server-side demand-line normalization before metrics
|
||||
- persisted live-vs-manual rate override metadata on demand lines
|
||||
- read/write workspace visibility for manual overrides vs live resource snapshots
|
||||
- completed in the current iteration:
|
||||
- approved-version planning handoff into downstream allocations
|
||||
- estimate project snapshot persistence for approval and handoff context
|
||||
- completed in the current iteration:
|
||||
- format-specific export serializers with downloadable stored artifacts and workspace previews
|
||||
- completed in the current iteration:
|
||||
- estimate clone/template feature across all layers (shared schema, application use-case, API router, UI)
|
||||
- rate cards per client with admin management UI
|
||||
- richer version comparison engine: per-item scope diffs with field-level change detection, resource snapshot rate/location diffs, chapter-grouped subtotals sorted by cost impact, margin % delta
|
||||
- version comparison UI: scope item detail table, resource rate diff table, chapter subtotals section, margin summary card
|
||||
|
||||
### 2. Refactor the planning core before v2 migration
|
||||
|
||||
The best low-risk internal work is the refactor slice that reduces duplication without forcing a full relational migration yet.
|
||||
|
||||
Scope:
|
||||
|
||||
- shared dynamic-field validation/filter path
|
||||
- typed widget config and layout migration
|
||||
- package-level regression tests
|
||||
|
||||
### 3. Prepare the demand/assignment model split
|
||||
|
||||
This should follow the refactor slice, not precede it. The current `Allocation` model is workable short-term but is the main domain-model constraint for v2 planning and estimating integration.
|
||||
|
||||
Current incremental slice:
|
||||
|
||||
- completed in the current iteration:
|
||||
- shared `DemandRequirement` and `Assignment` contracts
|
||||
- application adapter that splits mixed allocation rows into explicit read models
|
||||
- additive timeline/allocation API read endpoints and project-context exposure for the new split
|
||||
- migrate primary timeline and allocations UI surfaces onto explicit `demands` / `assignments` read models
|
||||
- add demand-aware allocations page visibility alongside assignment-first tables
|
||||
- completed in the current iteration:
|
||||
- manual create flows now write through `createDemandRequirement` / `createAssignment` instead of the mixed `allocation.create` payload where the UI already has an explicit intent
|
||||
- open-demand fill flows now route through a single compatibility-aware backend command so the UI no longer resolves linked demand records or branches between demand and placeholder fill mutations
|
||||
- completed in the current iteration:
|
||||
- centralize create-side legacy-allocation compatibility wiring in application use-cases so allocation create, explicit demand/assignment create, and timeline quick-assign share the same dual-write path
|
||||
- centralize split-record creation from compatibility allocations behind shared application helpers so demand-only, assignment-only, and estimate-handoff create facades no longer each hand-wire `legacyAllocationId` propagation
|
||||
- centralize the remaining compatibility-create orchestration behind a shared legacy-allocation bundle helper so demand-only, assignment-only, and combined compatibility creates no longer duplicate the "create legacy allocation, then materialize split rows" sequence
|
||||
- completed in the current iteration:
|
||||
- centralize estimate planning-handoff compatibility creation in shared application helpers so resource-backed and fallback-placeholder handoff lines reuse the same demand/assignment dual-write paths as the rest of planning
|
||||
- completed in the current iteration:
|
||||
- migrate the resource-detail surface off legacy mixed allocation reads onto assignment-only read models
|
||||
- completed in the current iteration:
|
||||
- align allocation report/export generation with assignment read-model semantics instead of direct placeholder filtering
|
||||
- completed in the current iteration:
|
||||
- migrate dashboard demand queries onto demand-requirement and assignment semantics, with legacy allocation and `staffingReqs` fallback during the compatibility period
|
||||
- centralize dashboard planning demand loading behind a shared split read-model helper so project demand rollups no longer hand-normalize mixed allocation rows and can derive project metadata from explicit demand/assignment relations during the compatibility window
|
||||
- completed in the current iteration:
|
||||
- migrate resource and dashboard utilization metrics onto assignment-first booking reads with legacy allocation fallback
|
||||
- completed in the current iteration:
|
||||
- migrate staffing suggestion, utilization-analysis, and capacity-window APIs off direct `resource.allocations` reads onto the shared assignment-first booking helper
|
||||
- completed in the current iteration:
|
||||
- migrate project detail compatibility reads and project cost rollups off direct `project.allocations` queries onto split read models and assignment-first booking reads with legacy fallback
|
||||
- completed in the current iteration:
|
||||
- remove unused legacy allocation hydration from `resource.getById` and move timeline budget-status calculations onto assignment-first booking reads with legacy fallback
|
||||
- completed in the current iteration:
|
||||
- keep timeline quick-assign, inline edit, and project-shift mutations in sync with linked demand/assignment rows during the compatibility period, while falling back to legacy allocation sync for intentionally dual-linked estimate handoff rows
|
||||
- completed in the current iteration:
|
||||
- keep legacy allocation delete flows in sync with linked demand/assignment rows and move allocation edit flows onto explicit demand/assignment update commands where linked rows already exist
|
||||
- collapse the main allocation edit modal onto the compatibility update facade so the frontend no longer resolves linked demand or assignment ids before submitting edits
|
||||
- completed in the current iteration:
|
||||
- centralize demand-requirement and assignment update compatibility sync in application use-cases so dedicated API procedures, legacy allocation edit facades, and bulk status updates share the same write path
|
||||
- completed in the current iteration:
|
||||
- centralize legacy-allocation link resolution in shared application code so allocation and timeline compatibility facades use the same exact-one-link vs dual-link decision rule
|
||||
- completed in the current iteration:
|
||||
- centralize compatibility-aware legacy allocation update routing in an application use-case so allocation edit, bulk status, timeline inline edit, and project-shift mutations share the same exact-one-link vs dual-link fallback behavior
|
||||
- completed in the current iteration:
|
||||
- move timeline `getEntriesView` and `getProjectContext` read paths to demand/assignment-first responses, while preserving legacy allocation fallback and compatibility ids for drag/edit flows
|
||||
- completed in the current iteration:
|
||||
- move timeline drag-context cross-project resource bookings onto the shared assignment-first booking helper, and allow that helper to serve unbounded resource-context reads while preserving legacy allocation fallback
|
||||
- completed in the current iteration:
|
||||
- update the project detail page to present explicit assignments and open demands instead of relying on the compatibility `project.allocations` view
|
||||
- completed in the current iteration:
|
||||
- route the legacy `allocation.list` and `timeline.getEntries` facades through the same demand/assignment-first read-model loaders as `listView` and `getEntriesView`, so compatibility endpoints no longer hand-shape raw allocation query results
|
||||
- completed in the current iteration:
|
||||
- centralize project-scoped planning reads behind a shared project/timeline loader so `project.getById`, `timeline.getProjectContext`, and project-shift preparation all build from the same demand/assignment-first source
|
||||
- add focused API regression coverage for the shared project-planning loader, including active-only filtering and explicit-plus-legacy fallback shaping
|
||||
- completed in the current iteration:
|
||||
- move dashboard overview budget utilization onto the shared assignment-first booking helper so linked legacy allocations no longer risk double-counting staffing cost in the top-level summary cards
|
||||
- completed in the current iteration:
|
||||
- route the legacy `allocation.fillPlaceholder` API facade through the same compatibility-aware open-demand fill command as `fillOpenDemandByAllocation`, while preserving the old response contract for callers still on the legacy endpoint
|
||||
- move project-shift resource booking windows onto the shared assignment-first booking helper so shift validation no longer hand-loads mixed allocation and assignment rows for cross-project overlap checks
|
||||
- completed in the current iteration:
|
||||
- rename primary allocation/timeline UX copy from placeholder language to open-demand and assignment language where the explicit demand/assignment flows already exist
|
||||
- completed in the current iteration:
|
||||
- route timeline project-shift preview/apply through a shared demand/assignment-first planning helper, updating explicit demand and assignment rows directly while preserving compatibility fallback for legacy-only rows
|
||||
- move the allocation modal form state to explicit demand-vs-assignment intent semantics while preserving the legacy allocation edit facade during the migration window
|
||||
- completed in the current iteration:
|
||||
- harden legacy allocation update, delete, batch delete, batch status, and timeline inline-edit facades so explicit `DemandRequirement` and `Assignment` ids without a backing legacy allocation row still work through the old endpoints
|
||||
- centralize allocation-facade id resolution in shared application helpers so legacy API surfaces can accept allocation, demand, or assignment ids without duplicating router-side branching
|
||||
- add regression coverage for explicit-id compatibility across application helpers, allocation router facades, and timeline inline editing
|
||||
- completed in the current iteration:
|
||||
- move explicit assignment availability validation onto the shared assignment-booking compatibility loader so conflict checks no longer hand-read mixed legacy allocation rows
|
||||
- add exclusion support for in-flight compatibility ids in shared booking reads, preventing linked legacy rows from being double-counted during assignment creation
|
||||
- completed in the current iteration:
|
||||
- move legacy resource-allocation availability validation onto the shared assignment-booking compatibility loader so old create flows also respect explicit assignment bookings during the migration window
|
||||
- add regression coverage proving legacy non-placeholder allocation creation now blocks against explicit assignment availability conflicts
|
||||
- completed in the current iteration:
|
||||
- move dashboard overview allocation counters off raw legacy `allocation.count()` so explicit demand/assignment rows without a backing legacy allocation still appear in top-level planning totals
|
||||
- keep dashboard budget utilization on assignment-first booking reads while aligning the visible overview counts with the split planning read model
|
||||
- completed in the current iteration:
|
||||
- move project-list and role usage counts onto a shared compatibility-aware planning-entry counter so linked legacy rows are deduplicated against explicit demand/assignment rows in user-facing badges and delete guards
|
||||
- keep existing `_count.allocations` response shapes intact while sourcing those values from the split planning model during the migration window
|
||||
- completed in the current iteration:
|
||||
- move estimate planning-handoff duplicate detection onto a shared compatibility-aware planning-entry counter so explicit demand/assignment-only handoff rows block reruns without hand-rolled legacy allocation bookkeeping
|
||||
- completed in the current iteration:
|
||||
- add an idempotent `packages/db` backfill + dry-run rehearsal utility for migrating legacy allocation rows into additive `DemandRequirement` / `Assignment` records without overwriting already-linked explicit rows
|
||||
- completed in the current iteration:
|
||||
- add a reconciliation audit utility for the demand/assignment persistence split so migration readiness can be measured by pending legacy backfills, explicit non-legacy rows, and legacy-data anomalies before any broader cutover
|
||||
- completed in the current iteration:
|
||||
- allow legacy open-demand fill compatibility commands to accept explicit `DemandRequirement` ids without a backing legacy allocation row
|
||||
- keep the legacy `allocation.fillPlaceholder` facade reload path compatible with split assignment/demand ids by reloading through the shared allocation-facade resolver
|
||||
- completed in the current iteration:
|
||||
- centralize linked demand-fill compatibility behind a shared explicit demand-fill helper so `fillDemandRequirement` and the legacy `fillPlaceholder` facade now reuse the same assignment-first transaction path
|
||||
- keep explicit demand fulfillment working even when a legacy placeholder link is stale or already missing, so additive split records remain operable during migration cleanup
|
||||
- completed in the current iteration:
|
||||
- stop explicit `DemandRequirement` and `Assignment` updates from broadly mirroring back into legacy `Allocation` rows, so split persistence is authoritative by default after backfill completion
|
||||
- keep the remaining legacy mirror writes scoped to true legacy-id compatibility updates, preserving old `allocation.update` behavior without forcing every explicit split edit through the legacy updater
|
||||
- add regression coverage proving live-linked explicit allocation-facade updates stay on explicit split semantics while legacy-only update branches still sync the compatibility row intentionally
|
||||
- completed in the current iteration:
|
||||
- move timeline inline-edit compatibility loading onto the shared allocation-facade resolver so it no longer hand-resolves allocation vs demand vs assignment ids
|
||||
- keep timeline inline cost recalculation resource loading separate from id-resolution logic, reducing another compatibility-only branch in the router
|
||||
- completed in the current iteration:
|
||||
- turn the legacy `allocation.create` facade into an intent-inferred compatibility path so open-demand creation no longer requires `isPlaceholder` when no resource is supplied, while resource-backed creates still route through assignment dual-write behavior
|
||||
- stop the allocation modal edit flow from sending the legacy `isPlaceholder` toggle back to the compatibility update facade, letting persisted demand-vs-assignment identity stay authoritative during the migration window
|
||||
- add router regression coverage for generic create compatibility on both demand and assignment paths so the remaining facade stays stable while newer explicit commands continue to replace it
|
||||
- completed in the current iteration:
|
||||
- centralize the generic allocation-create compatibility contract in shared schemas so omitted `isPlaceholder` now means "infer intent from resource presence" across callers instead of only inside the API router
|
||||
- move the low-level legacy `createAllocation` use-case onto the same inferred-demand rule so direct application callers and compatibility wrappers cannot drift from the router behavior
|
||||
- add application regression coverage proving omitted-flag open-demand creation still writes a placeholder-compatible legacy allocation row
|
||||
- completed in the current iteration:
|
||||
- harden the demand/assignment backfill rehearsal tooling with blocker detection for orphaned explicit legacy links, pending backfills, and invalid staffed legacy rows
|
||||
- add strict `--fail-on-blockers` and machine-readable `--json` modes to the DB backfill/audit scripts so migration rehearsal can gate automation safely
|
||||
- extend DB regression coverage for metadata-preserving backfill planning, staffed `headcount > 1` warnings, and orphaned legacy-link audit states
|
||||
- completed in the current iteration:
|
||||
- make explicit demand and assignment updates tolerate stale `legacyAllocationId` values when the backing `Allocation` row has already been cleaned up, so split-row edits no longer fail during the migration window
|
||||
- centralize backing-legacy-allocation existence checks across update and delete compatibility helpers instead of assuming every split row with a legacy link still has a live legacy record
|
||||
- add regression coverage for stale-link explicit update flows through the allocation compatibility facade
|
||||
- completed in the current iteration:
|
||||
- make shared allocation-facade id resolution fall back from missing legacy `Allocation` rows to split `DemandRequirement` or `Assignment` rows by `legacyAllocationId`, so stale compatibility ids continue to work after legacy-row cleanup
|
||||
- keep that fallback intentionally strict by refusing to guess when both a demand and an assignment still claim the same stale legacy id
|
||||
- add regression coverage for stale legacy-id update and delete flows through both the application compatibility helpers and the allocation router facade
|
||||
- completed in the current iteration:
|
||||
- self-heal missing `DemandRequirement` rows for legacy placeholders before compatibility fills run, so legacy placeholder ids no longer bypass split persistence when backfill has not happened yet
|
||||
- route `fillOpenDemandWithCompatibility` and the `allocation.fillPlaceholder` facade through explicit demand-fill semantics after that self-heal step, deleting the backing legacy placeholder row instead of mutating or cloning staffed legacy allocations
|
||||
- keep the low-level `fillPlaceholder` helper on the shared demand-fill compatibility transaction so allocation-shaped responses still remain available for intentional legacy-placeholder compatibility branches
|
||||
- completed in the current iteration:
|
||||
- add a canonical demand/assignment cutover document with explicit go/no-go criteria, signoff requirements, staged execution, and ambiguity policy
|
||||
- add a single readiness command that combines audit and dry-run signals, writes deterministic review artifacts, and fails fast when cutover blockers remain
|
||||
- add focused DB regression coverage for readiness report generation and deterministic artifact naming
|
||||
- completed in the current iteration:
|
||||
- rerun the demand/assignment readiness gate against the live workspace and confirm a clean `go` baseline with `0` pending demand backfills, `0` pending assignment backfills, and `0` orphaned legacy links
|
||||
- execute the first real `db:backfill:demand-assignment --apply` pass on shared data; it completed as a no-op because all `132` scanned legacy allocations were already represented by additive split rows
|
||||
- refresh the canonical cutover baseline and saved readiness artifacts so follow-up work can focus on compatibility-branch retirement and signoff rather than backlog speculation
|
||||
- completed in the current iteration:
|
||||
- make legacy allocation update compatibility self-heal unbackfilled rows by creating a `DemandRequirement` or `Assignment` on first legacy-only edit instead of leaving the row split-blind indefinitely
|
||||
- keep the old `allocation.update` and batch-status facade behavior intact while ensuring staffed legacy rows still run through assignment availability validation during that backfill-on-update path
|
||||
- add regression coverage for legacy-only placeholder and staffed update flows so split persistence is now exercised even before the bulk backfill runs
|
||||
- completed in the current iteration:
|
||||
- keep explicit `DemandRequirement` and `Assignment` deletes on explicit persistence semantics even when a backing legacy `Allocation` row still exists, instead of routing those deletes through the legacy-removal branch
|
||||
- remove the backing legacy allocation row as a cleanup side effect for those explicit deletes, while leaving surviving split rows addressable through stale compatibility ids during the migration window
|
||||
- add regression coverage for explicit delete paths with live legacy links so demand deletes detach assignments and assignment deletes no longer risk deleting sibling demand records
|
||||
- completed in the current iteration:
|
||||
- make explicit demand-fill flows sever a linked legacy placeholder instead of continuing to mutate or clone legacy `Allocation` rows after the split records already exist
|
||||
- keep legacy-placeholder-id fill compatibility intact, but route direct `DemandRequirement` fills onto assignment-first persistence with legacy cleanup as a side effect
|
||||
- add regression coverage for explicit legacy-linked fill flows through both the application use-cases and the allocation router facade
|
||||
- completed in the current iteration:
|
||||
- centralize compatibility id derivation in a shared helper so allocation read models, booking fallbacks, demand-fill compatibility, dashboard demand loading, and timeline consumers all preserve the same `legacyAllocationId ?? explicitId` rule
|
||||
- centralize stale-legacy fallback partitioning in the shared split-allocation read-model helper so timeline and allocation compatibility reads no longer duplicate the same fallback-legacy branching logic
|
||||
- add regression coverage for booking fallback compatibility ids and shared split-read fallback partitioning, keeping timeline/router cleanup pinned to application-level helpers
|
||||
- completed in the current iteration:
|
||||
- stop the explicit `createDemandRequirement` and `createAssignment` API routes from dual-writing legacy `Allocation` rows by default, so split persistence remains authoritative unless a caller intentionally uses a compatibility facade
|
||||
- move the legacy `allocation.create` facade itself onto split-authoritative demand/assignment creation, preserving intent inference and the allocation-shaped response contract without persisting new legacy `Allocation` rows
|
||||
- emit create/update allocation SSE events through the shared compatibility-id helper for explicit and legacy-linked split rows alike, and add router regression coverage for explicit create behavior without legacy dual writes
|
||||
- completed in the current iteration:
|
||||
- isolate the last legacy-placeholder fill mutation path behind a dedicated application helper so explicit `DemandRequirement` fills no longer carry inline `allocation.create` / `allocation.update` branching
|
||||
- centralize demand-fill progress updates behind a shared application helper so explicit demand fills and the legacy-placeholder branch now decrement or complete demand rows through the same path
|
||||
- remove the extra assignment reload from the single-headcount legacy-placeholder fill branch because the created assignment already carries the correct compatibility linkage and relations
|
||||
- retire the dedicated legacy-placeholder fill mutation branch entirely, so both explicit demand fills and `allocation.fillPlaceholder` now route through the same split-authoritative demand-fill command and legacy placeholder rows are always cleaned up as a side effect instead of being mutated in place
|
||||
- move explicit demand-fill legacy-row cleanup onto the shared delete-side compatibility helper so fill transactions no longer carry their own inline `allocation.delete` branch
|
||||
- isolate the create-side allocation compatibility paths behind dedicated legacy-create helpers so demand, assignment, and estimate-handoff compatibility writes no longer piggyback on the generic low-level create entry point
|
||||
- centralize direct legacy allocation table create/update/delete calls behind a shared record-store helper so compatibility-only write paths now share one low-level mutation surface
|
||||
- centralize direct legacy allocation compatibility reads behind the same shared record-store helper so placeholder self-heal, facade resolution, and legacy reload flows no longer hand-call `db.allocation.findUnique`
|
||||
- centralize true legacy-id mirror payload shaping in shared helpers so intentional `allocation.update` compatibility writes are clearly separated from split-authoritative demand/assignment updates
|
||||
- isolate the compatibility delete-side legacy removal path behind a dedicated helper so the allocation facade no longer carries inline raw `allocation.delete` branching
|
||||
- move delete-side backing-legacy existence tolerance into the shared existence helper so the compatibility delete path no longer carries its own `allocation.findUnique` shape shim
|
||||
- verify the isolated compatibility branches with focused application/API regression coverage and keep the remaining raw legacy allocation access constrained to the shared record-store helper plus the shared backing-existence helper
|
||||
- completed in the current iteration:
|
||||
- expose explicit split-row ids alongside compatibility ids in shared planning read models, with allocation-shaped entries carrying `entityId` and demand/assignment entries carrying the real explicit row id in `sourceAllocationId`
|
||||
- move timeline drag, inline edit, open-demand fill, project-panel edit/delete, allocation modal edit, and single-row allocation delete flows onto those explicit ids while preserving compatibility `id` values for rendering, SSE, and stale-legacy callers
|
||||
- completed in the current iteration:
|
||||
- keep the allocations table selection UX keyed to compatibility-facing display ids while routing batch status and batch delete payloads through explicit split-row ids where available
|
||||
- completed in the current iteration:
|
||||
- retired the true legacy-id delete surface by routing legacy allocation deletes through split-authoritative `deleteAssignment`/`deleteDemandRequirement` paths with lazy backfill via `ensureLegacyAllocationSplitPersistence`
|
||||
- retired the true legacy-id update mirror by routing legacy allocation updates through split-authoritative `updateAssignment`/`updateDemandRequirement` paths with lazy backfill
|
||||
- removed `isPlaceholder` from Prisma schema columns, router inputs, and create facade — demand vs. assignment intent is now derived from `resourceId` presence at read-model build time; the shared `Allocation` type still exposes `isPlaceholder` as a computed property for frontend consumption
|
||||
- removed legacy allocation reads from `loadAllocationReadModel` — now queries only demand/assignment tables, passing `allocations: []`
|
||||
- reversed `findAllocationFacadeEntry` resolution priority to be split-authoritative (demand/assignment first, legacy allocation last resort)
|
||||
- removed the `fillPlaceholder` legacy facade from the allocation router
|
||||
- cleaned up dead legacy compatibility helpers: `updateLegacyAllocationWithCompatibility`, `deleteLegacyAllocationWithCompatibility`, `syncLegacyAllocationUpdate`, `syncLegacyAllocationRemoval`, `toLegacyAllocationUpdateData`, `fillPlaceholder` application use-case, and their tests
|
||||
- moved `deleteBackingLegacyAllocationIfPresent` into the shared `legacy-allocation-record-store` helper
|
||||
- completed in the current iteration:
|
||||
- Stage 5: dropped the legacy `Allocation` table from the Prisma schema (132 rows removed)
|
||||
- removed `legacyAllocationId` columns and indexes from `DemandRequirement` and `Assignment`
|
||||
- deleted `getAllocationCompatibilityId` helper and replaced all ~20 call sites with direct entity `.id` access
|
||||
- deleted `getLegacyAllocationLinks` and removed legacy-link fallback from `findAllocationFacadeEntry`
|
||||
- simplified SSE event emissions to use entity IDs directly
|
||||
- deleted migration tooling: backfill, audit, readiness scripts and their tests
|
||||
- cleaned seed data: removed all `allocation.create` and `allocation.deleteMany` calls
|
||||
- renamed `FillPlaceholderModal` to `FillOpenDemandModal`
|
||||
- deleted `legacy-allocation-links.test.ts` and updated all remaining tests
|
||||
- completed in the current iteration:
|
||||
- retired compatibility facades by renaming to clean domain names: `updateAllocationEntry`, `deleteAllocationEntry`, `fillOpenDemand`, `loadAllocationEntry`
|
||||
- replaced all `AllocationFacade*` type prefixes with `AllocationEntry*`
|
||||
- removed `compatibilityId` and `source` fields from booking interfaces
|
||||
- renamed `demandRequirementByCompatibilityId` → `demandRequirementById`, `existingFacade` → `resolved`
|
||||
- updated test descriptions to remove "compatibility" references
|
||||
- **migration is fully complete — no legacy compatibility naming or debt remains**
|
||||
|
||||
## Delivery Sequence
|
||||
|
||||
1. Completed: shared dynamic-field parity, blueprint validation parity, Blueprints list parity, and typed dashboard layout/widget migration
|
||||
2. Completed: estimate router procedures, estimates list route, and first wizard shell
|
||||
3. Completed: demand/assignment split persistence — all reads and writes are split-authoritative, legacy compatibility branches retired
|
||||
4. Complete: Dispo v2 — all phases delivered (Phase C/SAP actuals removed from scope).
|
||||
5. Next: broader cross-package regression coverage
|
||||
6. Then: broader cross-package regression coverage
|
||||
|
||||
### Dispo v2 Parallel Stream
|
||||
|
||||
Runs independently of the demand/assignment workstream. Source analysis and detailed plans in `samples/Dispov2/plan-*.md`.
|
||||
|
||||
| Plan | Scope | Depends On | Primary Files |
|
||||
|---|---|---|---|
|
||||
| Country/SAH/FTE | Country + MetroCity models, SAH calculator, Spain schedule, FTE scaling | - | `schema.prisma`, `packages/engine/src/sah/`, `packages/shared/src/types/country.ts` |
|
||||
| OrgUnit Hierarchy | 3-level self-ref OrgUnit tree (L5→L6→L7) | - | `schema.prisma`, `packages/api/src/router/org-unit.ts`, `apps/web/src/components/org-units/` |
|
||||
| Utilization Categories | UtilizationCategory model on Projects (Chg, BD, MD&I, M&O, PD&R, Absence) | - | `schema.prisma`, `packages/api/src/router/utilization-category.ts` |
|
||||
| Client/WBS | Self-ref Client tree (Master→Entity), project linking | - | `schema.prisma`, `packages/api/src/router/client.ts`, `apps/web/src/components/clients/` |
|
||||
| Resource Extensions | EID attributes, ManagementLevel, ResourceType, derivation rules | Plans 1-4 | `schema.prisma`, `Resource` model, `ResourceModal.tsx` |
|
||||
| Chargeability Report | Live reporting page, forecast from assignments + SAH, export | All above | `packages/engine/src/chargeability/`, `apps/web/src/app/(app)/reports/` |
|
||||
|
||||
Serialization constraint: all plans add to `schema.prisma` — edits serialized, not parallel.
|
||||
|
||||
## Demand And Assignment Persistence Split
|
||||
|
||||
This is now the highest-value planning-core change. The read side is already separated enough that the next step should be an additive persistence migration instead of more UI churn.
|
||||
|
||||
### Problem (resolved)
|
||||
|
||||
The legacy `Allocation` table mixed two business concepts: demand (`isPlaceholder = true`) and assignment (`isPlaceholder = false`). That overload leaked into creation, fill, estimate handoff, validation, reporting, and planning logic.
|
||||
|
||||
This has been fully resolved: the `Allocation` table has been dropped, and all reads/writes now go through first-class `DemandRequirement` and `Assignment` tables. `isPlaceholder` remains as a derived read-model property for frontend consumption.
|
||||
|
||||
### Target persistence model
|
||||
|
||||
Additive target for the next schema slice:
|
||||
|
||||
| New model | Core fields | Purpose |
|
||||
|---|---|---|
|
||||
| `DemandRequirement` | `id`, `projectId`, `roleId`, `role`, `startDate`, `endDate`, `hoursPerDay`, `percentage`, `headcount`, `status`, `metadata` | first-class planning demand |
|
||||
| `Assignment` | `id`, `projectId`, `resourceId`, `demandRequirementId?`, `startDate`, `endDate`, `hoursPerDay`, `percentage`, `dailyCostCents`, `status`, `metadata` | actual staffing assignment |
|
||||
| `AssignmentRevision` later | `assignmentId`, `changedAt`, `before`, `after`, `reason` | audit-friendly history after the base split lands |
|
||||
|
||||
### Field mapping from current `Allocation`
|
||||
|
||||
| Current `Allocation` field | DemandRequirement target | Assignment target | Notes |
|
||||
|---|---|---|---|
|
||||
| `id` | new id on backfill | new id on backfill | keep old allocation id in compatibility metadata during migration |
|
||||
| `projectId` | `projectId` | `projectId` | direct |
|
||||
| `resourceId` | not stored except optional `suggestedResourceId` metadata | `resourceId` | nullable meaning is removed from the main model |
|
||||
| `startDate` / `endDate` | direct | direct | direct |
|
||||
| `hoursPerDay` | direct | direct | direct |
|
||||
| `percentage` | direct | direct | direct |
|
||||
| `role` / `roleId` | direct | copied from linked demand when useful | preserve text fallback until role normalization is done |
|
||||
| `isPlaceholder` | removed | removed | business state moves to model choice, not a flag |
|
||||
| `headcount` | direct | removed from assignment | one assignment row always means one staffing record |
|
||||
| `dailyCostCents` | derived or zero | direct | demand does not carry execution cost as a required source field |
|
||||
| `status` | direct | direct | keep enum initially for compatibility |
|
||||
| `metadata` | direct | direct | preserve `estimateHandoff`, recurrence, and migration provenance |
|
||||
|
||||
### Delivery phases
|
||||
|
||||
1. Phase A: additive schema
|
||||
Add Prisma models for `DemandRequirement` and `Assignment` without removing `Allocation`. Add nullable `demandRequirementId` on `Assignment` only if the implementation keeps the `Assignment` name; if the table name must stay `allocations` temporarily, keep a compatibility mapping documented in Prisma comments.
|
||||
2. Phase B: dual-write application services
|
||||
Introduce `defineDemand`, `assignResource`, and `fillDemand` use cases in `packages/application`. New estimate handoff should create `DemandRequirement` rows first, then create `Assignment` rows only for lines that have a resolvable resource.
|
||||
3. Phase C: backfill and compatibility reads — **Complete.** Backfill ran as a no-op (all rows already split). Backfill/audit/readiness tooling has been deleted.
|
||||
4. Phase D: command/API cutover — **Complete.** `isPlaceholder` removed from create/update payloads. `fillPlaceholder` replaced by `fillOpenDemandByAllocation`. Compatibility facades renamed to clean domain names.
|
||||
5. Phase E: legacy removal — **Complete.** Legacy `Allocation` table dropped. `legacyAllocationId` columns removed. All compatibility naming retired.
|
||||
|
||||
### Use cases to migrate first
|
||||
|
||||
| Priority | Scope | Why |
|
||||
|---|---|---|
|
||||
| `P0` | estimate planning handoff | this is where planning demand now enters the operational domain |
|
||||
| `P0` | manual demand creation and fill flow | direct replacement for placeholder allocation creation/fill |
|
||||
| `P1` | timeline command paths | move/resize/edit semantics should stop branching on placeholder state |
|
||||
| `P1` | timeline command paths and remaining persistence-facing reads | remove the remaining placeholder-specific assumptions after the dashboard/report cleanup |
|
||||
| `P2` | legacy allocation CRUD compatibility | keep only as a migration facade |
|
||||
|
||||
### Acceptance criteria for the split
|
||||
|
||||
- A demand can exist without inventing a fake allocation row.
|
||||
- Filling one seat of a multi-headcount demand does not mutate assignment semantics.
|
||||
- Approved estimate handoff writes demand first and assignment second.
|
||||
- Timeline and allocations pages render from explicit demand and assignment reads with no `isPlaceholder` branching in UI data loading.
|
||||
- Legacy `allocation.list` can remain temporarily, but new features must not require `isPlaceholder` input.
|
||||
- Migration can be run without losing existing allocation history or estimate handoff metadata.
|
||||
|
||||
### Parallel tickets
|
||||
|
||||
| Ticket | Owner | Scope |
|
||||
|---|---|---|
|
||||
| `DAS-01` | `A1-architect` | finalize Prisma target schema, compatibility period, and cutover rules |
|
||||
| `DAS-02` | `C1-estimate-backend` | switch estimate planning handoff from placeholder allocations to demand-first writes |
|
||||
| `DAS-03` | `C1-estimate-backend` | add demand/assignment application services and additive API procedures |
|
||||
| `DAS-04` | `C2-estimate-frontend` | adapt wizard/workspace follow-up UIs and any demand-fill flows to new commands |
|
||||
| `DAS-05` | `T1-regression` | backfill tests, compatibility tests, and Docker smoke checks |
|
||||
|
||||
### Known residual semantic mismatches
|
||||
|
||||
All previously listed mismatches have been resolved:
|
||||
- The legacy `Allocation` table has been dropped; persistence uses `DemandRequirement` and `Assignment` exclusively.
|
||||
- Compatibility facades have been renamed to clean domain names (`updateAllocationEntry`, `deleteAllocationEntry`, `fillOpenDemand`).
|
||||
- `isPlaceholder` is retained as a derived read-model property (not a stored column) for frontend consumption.
|
||||
|
||||
## Parallel Delivery Plan
|
||||
|
||||
Use a single orchestrator and split roadmap execution into package-owned workstreams. Shared files should be merged only at integration checkpoints.
|
||||
|
||||
| Agent | Scope | Primary Files / Packages | Deliverables | Notes |
|
||||
|---|---|---|---|---|
|
||||
| `A1-architect` | keep roadmap, contracts, and merge boundaries coherent | [docs/product-roadmap.md](/home/hartmut/Documents/Copilot/planarchy/docs/product-roadmap.md), [docs/estimating-extension-design.md](/home/hartmut/Documents/Copilot/planarchy/docs/estimating-extension-design.md), shared contract entry points | acceptance criteria, sequencing, shared-file coordination | should not implement feature code unless integration is blocked |
|
||||
| `C1-estimate-backend` | estimate domain, router, persistence, exports | `packages/api`, `packages/application`, `packages/engine`, `packages/db`, `packages/shared` | workspace read/write procedures, export serializers, version actions, metrics persistence | owns server-side behavior and cross-package type safety |
|
||||
| `C2-estimate-frontend` | estimates pages, wizard follow-up, workspace tabs | `apps/web/src/app/(app)/estimates`, `apps/web/src/components/estimates`, shared UI components | detail workspace, overview/assumptions/scope/rates tabs, iteration UX | should avoid editing backend contracts without handoff |
|
||||
| `T1-regression` | tests and runtime verification | `packages/*/test*`, `apps/web` verification paths, Docker runtime checks | regression tests, package typechecks, app smoke validation | runs after each integration checkpoint |
|
||||
| `R1-reviewer` | final integration and regression review | diff review across touched packages | findings, missing permissions, backward-compatibility risks | review after C1 and C2 merge |
|
||||
|
||||
### Active Parallel Slice
|
||||
|
||||
Current target: execute the demand/assignment persistence split without blocking estimate usage that already works.
|
||||
|
||||
| Ticket | Owner | Depends On | Scope |
|
||||
|---|---|---|---|
|
||||
| `DAS-01` Additive Prisma schema and compatibility rules | `A1-architect` + `C1-estimate-backend` | current read-model split | define `DemandRequirement` / `Assignment` tables, migration comments, and cutover constraints |
|
||||
| `DAS-02` Demand-first planning handoff | `C1-estimate-backend` | `DAS-01` | change approved estimate handoff to create demand first, assignment second |
|
||||
| `DAS-03` Demand/assignment command surface | `C1-estimate-backend` | `DAS-01` | add demand create/fill procedures and compatibility wrappers for legacy allocation flows |
|
||||
| `DAS-04` Frontend follow-up flows | `C2-estimate-frontend` | `DAS-02`, `DAS-03` | completed for the main allocation, timeline, and estimate handoff surfaces; continue only for residual legacy copy |
|
||||
| `DAS-05` Regression and migration net | `T1-regression` | `DAS-01` to `DAS-04` checkpoints | backfill tests, contract tests, Docker smoke validation, and migration rehearsal |
|
||||
|
||||
### Merge Boundaries
|
||||
|
||||
- serialize edits to:
|
||||
- `packages/db/prisma/schema.prisma`
|
||||
- `packages/shared/src/types/allocation.ts`
|
||||
- `packages/shared/src/schemas/allocation.schema.ts`
|
||||
- `packages/api/src/router/index.ts`
|
||||
- `packages/api/src/router/allocation.ts`
|
||||
- `packages/application/src/use-cases/estimate/create-planning-handoff.ts`
|
||||
- allow parallel edits to:
|
||||
- demand/assignment backend packages vs estimate frontend app code
|
||||
- docs vs tests
|
||||
- dashboard/report query cleanup vs estimate workspace UI copy
|
||||
|
||||
## Document Ownership
|
||||
|
||||
| Topic | Canonical File | Notes |
|
||||
|---|---|---|
|
||||
| Active backlog | [product-roadmap.md](/home/hartmut/Documents/Copilot/planarchy/docs/product-roadmap.md) | Update this instead of reopening old plan files. |
|
||||
| Estimating design and field mapping | [estimating-extension-design.md](/home/hartmut/Documents/Copilot/planarchy/docs/estimating-extension-design.md) | Holds workbook analysis, mapping, and implementation plan. |
|
||||
| Strategic architecture direction | [v2-architecture-proposal-2026-03-11.md](/home/hartmut/Documents/Copilot/planarchy/research/v2-architecture-proposal-2026-03-11.md) | Keep as strategy, not sprint backlog. |
|
||||
| Historical decisions | [LEARNINGS.md](/home/hartmut/Documents/Copilot/planarchy/LEARNINGS.md) | Append-only log. |
|
||||
Reference in New Issue
Block a user