Merge pull request 'chore: full technical rename planarchy → capakraken' (#18) from chore/rename-capakraken into main

This commit is contained in:
2026-03-27 13:18:56 +01:00
303 changed files with 938 additions and 878 deletions
+1 -1
View File
@@ -436,7 +436,7 @@ The agent operates within the Planarchy monorepo and must adhere to all engineer
- **tRPC:** New routers must be registered in `packages/api/src/router/index.ts` - **tRPC:** New routers must be registered in `packages/api/src/router/index.ts`
- **TypeScript:** `exactOptionalPropertyTypes: true` — use spread pattern, never assign `undefined` - **TypeScript:** `exactOptionalPropertyTypes: true` — use spread pattern, never assign `undefined`
- **No speculative abstractions** — only build what the ticket requires - **No speculative abstractions** — only build what the ticket requires
- **Quality gates:** `pnpm test:unit`, `pnpm --filter @planarchy/web exec tsc --noEmit`, `pnpm lint` - **Quality gates:** `pnpm test:unit`, `pnpm --filter @capakraken/web exec tsc --noEmit`, `pnpm lint`
## Arguments ## Arguments
+5 -5
View File
@@ -7,7 +7,7 @@ Lies `plan.md` und implementiere die Tasks Schritt für Schritt. Führe nach jed
- Monorepo: pnpm workspaces + Turborepo - Monorepo: pnpm workspaces + Turborepo
- Stack: Next.js 15 App Router + tRPC v11 + Prisma + PostgreSQL - Stack: Next.js 15 App Router + tRPC v11 + Prisma + PostgreSQL
- Dev-Server: `pnpm dev` auf Port 3100 - Dev-Server: `pnpm dev` auf Port 3100
- DB: PostgreSQL auf Port 5433 (`postgresql://planarchy:planarchy_dev@localhost:5433/planarchy`) - DB: PostgreSQL auf Port 5433 (`postgresql://planarchy:capakraken_dev@localhost:5433/planarchy`)
## Implementierungs-Reihenfolge (immer einhalten) ## Implementierungs-Reihenfolge (immer einhalten)
1. **Prisma Schema** (`packages/db/prisma/schema.prisma`) → `pnpm db:push` 1. **Prisma Schema** (`packages/db/prisma/schema.prisma`) → `pnpm db:push`
@@ -18,14 +18,14 @@ Lies `plan.md` und implementiere die Tasks Schritt für Schritt. Führe nach jed
## Nach jeder Schema-Änderung (Pflicht!) ## Nach jeder Schema-Änderung (Pflicht!)
```bash ```bash
DATABASE_URL="postgresql://planarchy:planarchy_dev@localhost:5433/planarchy" \ DATABASE_URL="postgresql://planarchy:capakraken_dev@localhost:5433/planarchy" \
pnpm --filter @planarchy/db exec prisma generate pnpm --filter @capakraken/db exec prisma generate
rm -rf apps/web/.next rm -rf apps/web/.next
``` ```
## Quality Gate nach jedem Task ## Quality Gate nach jedem Task
```bash ```bash
pnpm --filter @planarchy/web exec tsc --noEmit 2>&1 | grep -v "BlueprintFieldEditor" pnpm --filter @capakraken/web exec tsc --noEmit 2>&1 | grep -v "BlueprintFieldEditor"
# BlueprintFieldEditor TS2589 ist ein bekannter Pre-existing-Error, kein neuer Fehler # BlueprintFieldEditor TS2589 ist ein bekannter Pre-existing-Error, kein neuer Fehler
``` ```
@@ -47,6 +47,6 @@ refactor: [refactoring-beschreibung]
## Abschluss ## Abschluss
Wenn alle Tasks erledigt: Wenn alle Tasks erledigt:
1. `pnpm test:unit` alle Tests grün? 1. `pnpm test:unit` alle Tests grün?
2. `pnpm --filter @planarchy/web exec tsc --noEmit` sauber? 2. `pnpm --filter @capakraken/web exec tsc --noEmit` sauber?
3. Learning in `LEARNINGS.md` eintragen 3. Learning in `LEARNINGS.md` eintragen
4. `git commit -m "docs: learning erfasst - [kurzbeschreibung]"` 4. `git commit -m "docs: learning erfasst - [kurzbeschreibung]"`
+1 -1
View File
@@ -113,7 +113,7 @@ Erstelle `research/perf-audit-[datum].md`:
2. Lies alle tRPC Router in `packages/api/src/router/` 2. Lies alle tRPC Router in `packages/api/src/router/`
3. Prüfe alle `useQuery`-Aufrufe in `apps/web/src/` auf staleTime und placeholderData 3. Prüfe alle `useQuery`-Aufrufe in `apps/web/src/` auf staleTime und placeholderData
4. Führe PostgreSQL `EXPLAIN ANALYZE` auf die wichtigsten Queries aus 4. Führe PostgreSQL `EXPLAIN ANALYZE` auf die wichtigsten Queries aus
5. Prüfe Bundle-Größen via `pnpm --filter @planarchy/web build` (optional) 5. Prüfe Bundle-Größen via `pnpm --filter @capakraken/web build` (optional)
6. Erstelle priorisierten Befundbericht 6. Erstelle priorisierten Befundbericht
Beginne sofort mit Layer 1 (Datenbank) und arbeite dich durch alle Layer. Beginne sofort mit Layer 1 (Datenbank) und arbeite dich durch alle Layer.
+1 -1
View File
@@ -32,7 +32,7 @@ Analysiere die gegebene Anforderung und erstelle einen konkreten Umsetzungsplan.
### Akzeptanzkriterien ### Akzeptanzkriterien
- [ ] `pnpm test:unit` läuft grün - [ ] `pnpm test:unit` läuft grün
- [ ] `pnpm --filter @planarchy/web exec tsc --noEmit` keine neuen Errors - [ ] `pnpm --filter @capakraken/web exec tsc --noEmit` keine neuen Errors
- [ ] [Feature-spezifische Kriterien] - [ ] [Feature-spezifische Kriterien]
### Risiken & offene Fragen ### Risiken & offene Fragen
+1 -1
View File
@@ -18,7 +18,7 @@ pnpm test:unit
### 2. TypeScript ### 2. TypeScript
```bash ```bash
pnpm --filter @planarchy/web exec tsc --noEmit 2>&1 pnpm --filter @capakraken/web exec tsc --noEmit 2>&1
# Bekannter Pre-existing-Error: BlueprintFieldEditor.tsx TS2589 → ignorieren # Bekannter Pre-existing-Error: BlueprintFieldEditor.tsx TS2589 → ignorieren
# Alle anderen Errors müssen 0 sein # Alle anderen Errors müssen 0 sein
``` ```
+25 -25
View File
@@ -37,7 +37,7 @@ jobs:
run: pnpm install --frozen-lockfile run: pnpm install --frozen-lockfile
- name: Generate Prisma client - name: Generate Prisma client
run: pnpm --filter @planarchy/db exec prisma generate run: pnpm --filter @capakraken/db exec prisma generate
- name: Cache Turborepo - name: Cache Turborepo
uses: actions/cache@v4 uses: actions/cache@v4
@@ -47,7 +47,7 @@ jobs:
restore-keys: turbo-typecheck- restore-keys: turbo-typecheck-
- name: Run typecheck - name: Run typecheck
run: pnpm --filter @planarchy/web exec tsc --noEmit run: pnpm --filter @capakraken/web exec tsc --noEmit
# ────────────────────────────────────────────── # ──────────────────────────────────────────────
# Lint — ~20s, no services needed # Lint — ~20s, no services needed
@@ -71,7 +71,7 @@ jobs:
run: pnpm install --frozen-lockfile run: pnpm install --frozen-lockfile
- name: Generate Prisma client - name: Generate Prisma client
run: pnpm --filter @planarchy/db exec prisma generate run: pnpm --filter @capakraken/db exec prisma generate
- name: Cache Turborepo - name: Cache Turborepo
uses: actions/cache@v4 uses: actions/cache@v4
@@ -93,13 +93,13 @@ jobs:
postgres: postgres:
image: postgres:16 image: postgres:16
env: env:
POSTGRES_DB: planarchy_test POSTGRES_DB: capakraken_test
POSTGRES_USER: planarchy POSTGRES_USER: capakraken
POSTGRES_PASSWORD: planarchy_test POSTGRES_PASSWORD: capakraken_test
ports: ports:
- 5432:5432 - 5432:5432
options: >- options: >-
--health-cmd="pg_isready -U planarchy -d planarchy_test" --health-cmd="pg_isready -U capakraken -d capakraken_test"
--health-interval=10s --health-interval=10s
--health-timeout=5s --health-timeout=5s
--health-retries=5 --health-retries=5
@@ -113,7 +113,7 @@ jobs:
--health-timeout=5s --health-timeout=5s
--health-retries=5 --health-retries=5
env: env:
DATABASE_URL: postgresql://planarchy:planarchy_test@localhost:5432/planarchy_test DATABASE_URL: postgresql://capakraken:capakraken_test@localhost:5432/capakraken_test
REDIS_URL: redis://localhost:6379 REDIS_URL: redis://localhost:6379
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
@@ -131,16 +131,16 @@ jobs:
run: pnpm install --frozen-lockfile run: pnpm install --frozen-lockfile
- name: Generate Prisma client - name: Generate Prisma client
run: pnpm --filter @planarchy/db exec prisma generate run: pnpm --filter @capakraken/db exec prisma generate
- name: Run unit tests with coverage - name: Run unit tests with coverage
run: | run: |
pnpm --filter @planarchy/engine exec vitest run --coverage pnpm --filter @capakraken/engine exec vitest run --coverage
pnpm --filter @planarchy/staffing exec vitest run --coverage pnpm --filter @capakraken/staffing exec vitest run --coverage
pnpm --filter @planarchy/api exec vitest run --coverage pnpm --filter @capakraken/api exec vitest run --coverage
pnpm --filter @planarchy/application exec vitest run --coverage pnpm --filter @capakraken/application exec vitest run --coverage
pnpm --filter @planarchy/shared exec vitest run --coverage pnpm --filter @capakraken/shared exec vitest run --coverage
pnpm --filter @planarchy/db test:unit pnpm --filter @capakraken/db test:unit
# ────────────────────────────────────────────── # ──────────────────────────────────────────────
# Build — depends on typecheck passing # Build — depends on typecheck passing
@@ -167,7 +167,7 @@ jobs:
run: pnpm install --frozen-lockfile run: pnpm install --frozen-lockfile
- name: Generate Prisma client - name: Generate Prisma client
run: pnpm --filter @planarchy/db exec prisma generate run: pnpm --filter @capakraken/db exec prisma generate
- name: Cache Turborepo - name: Cache Turborepo
uses: actions/cache@v4 uses: actions/cache@v4
@@ -184,7 +184,7 @@ jobs:
restore-keys: nextjs-${{ hashFiles('pnpm-lock.yaml') }}- restore-keys: nextjs-${{ hashFiles('pnpm-lock.yaml') }}-
- name: Build - name: Build
run: pnpm --filter @planarchy/web exec next build run: pnpm --filter @capakraken/web exec next build
# ────────────────────────────────────────────── # ──────────────────────────────────────────────
# E2E — depends on build, needs PostgreSQL + Redis # E2E — depends on build, needs PostgreSQL + Redis
@@ -197,13 +197,13 @@ jobs:
postgres: postgres:
image: postgres:16 image: postgres:16
env: env:
POSTGRES_DB: planarchy_test POSTGRES_DB: capakraken_test
POSTGRES_USER: planarchy POSTGRES_USER: capakraken
POSTGRES_PASSWORD: planarchy_test POSTGRES_PASSWORD: capakraken_test
ports: ports:
- 5432:5432 - 5432:5432
options: >- options: >-
--health-cmd="pg_isready -U planarchy -d planarchy_test" --health-cmd="pg_isready -U capakraken -d capakraken_test"
--health-interval=10s --health-interval=10s
--health-timeout=5s --health-timeout=5s
--health-retries=5 --health-retries=5
@@ -217,7 +217,7 @@ jobs:
--health-timeout=5s --health-timeout=5s
--health-retries=5 --health-retries=5
env: env:
DATABASE_URL: postgresql://planarchy:planarchy_test@localhost:5432/planarchy_test DATABASE_URL: postgresql://capakraken:capakraken_test@localhost:5432/capakraken_test
REDIS_URL: redis://localhost:6379 REDIS_URL: redis://localhost:6379
PORT: 3100 PORT: 3100
steps: steps:
@@ -236,7 +236,7 @@ jobs:
run: pnpm install --frozen-lockfile run: pnpm install --frozen-lockfile
- name: Generate Prisma client - name: Generate Prisma client
run: pnpm --filter @planarchy/db exec prisma generate run: pnpm --filter @capakraken/db exec prisma generate
- name: Cache Playwright browsers - name: Cache Playwright browsers
id: playwright-cache id: playwright-cache
@@ -248,11 +248,11 @@ jobs:
- name: Install Playwright browsers - name: Install Playwright browsers
if: steps.playwright-cache.outputs.cache-hit != 'true' if: steps.playwright-cache.outputs.cache-hit != 'true'
run: pnpm --filter @planarchy/web exec playwright install --with-deps chromium run: pnpm --filter @capakraken/web exec playwright install --with-deps chromium
- name: Install Playwright system deps - name: Install Playwright system deps
if: steps.playwright-cache.outputs.cache-hit == 'true' if: steps.playwright-cache.outputs.cache-hit == 'true'
run: pnpm --filter @planarchy/web exec playwright install-deps chromium run: pnpm --filter @capakraken/web exec playwright install-deps chromium
- name: Push DB schema & seed - name: Push DB schema & seed
run: | run: |
+3 -3
View File
@@ -1,8 +1,8 @@
# Planarchy # CapaKraken
## Ziel ## Ziel
Planarchy ist ein Ressourcenplanungs- und Projektbesetzungs-Tool fuer eine 3D-Produktionsumgebung. Der aktuelle Produktkern umfasst Timeline-Planung, Kapazitaets- und Budgetsicht, Rollenmanagement, Blueprint-basierte dynamische Felder, Skill-Matrix-Workflows und einen AI-unterstuetzten Staffing-/Profilbereich. CapaKraken ist ein Ressourcenplanungs- und Projektbesetzungs-Tool fuer eine 3D-Produktionsumgebung. Der aktuelle Produktkern umfasst Timeline-Planung, Kapazitaets- und Budgetsicht, Rollenmanagement, Blueprint-basierte dynamische Felder, Skill-Matrix-Workflows und einen AI-unterstuetzten Staffing-/Profilbereich.
## Tech Stack ## Tech Stack
@@ -41,7 +41,7 @@ planarchy/
## Quality Gates ## Quality Gates
- `pnpm test:unit` - `pnpm test:unit`
- `pnpm --filter @planarchy/web exec tsc --noEmit` - `pnpm --filter @capakraken/web exec tsc --noEmit`
- `pnpm lint` - `pnpm lint`
## Dokumente ## Dokumente
+6 -6
View File
@@ -27,7 +27,7 @@
### 2026-03-11 | Architecture | Phase 1: Application Layer Extraction ### 2026-03-11 | Architecture | Phase 1: Application Layer Extraction
- Created `packages/application` with `createAllocation` and `fillPlaceholder` use-case services - Created `packages/application` with `createAllocation` and `fillPlaceholder` use-case services
- `packages/api` router procedures now delegate to use cases; they only check permissions and emit SSE events - `packages/api` router procedures now delegate to use cases; they only check permissions and emit SSE events
- `packages/application` depends on `@planarchy/db`, `@planarchy/engine`, `@planarchy/shared`; `packages/api` depends on `@planarchy/application` - `packages/application` depends on `@capakraken/db`, `@capakraken/engine`, `@capakraken/shared`; `packages/api` depends on `@capakraken/application`
- Use cases throw `TRPCError` directly (pragmatic — project only uses tRPC transport) - Use cases throw `TRPCError` directly (pragmatic — project only uses tRPC transport)
- `Prisma.AllocationGetPayload<{ include: ... }>` used for precise return type in use cases - `Prisma.AllocationGetPayload<{ include: ... }>` used for precise return type in use cases
- `exactOptionalPropertyTypes` + optional params: caller must use spread `...(val !== undefined ? { key: val } : {})` when passing zod inputs to use cases with `{ key?: T }` interfaces - `exactOptionalPropertyTypes` + optional params: caller must use spread `...(val !== undefined ? { key: val } : {})` when passing zod inputs to use cases with `{ key?: T }` interfaces
@@ -43,7 +43,7 @@
### 2026-03-12 | Architecture | Estimating foundation slice ### 2026-03-12 | Architecture | Estimating foundation slice
- Added first-class Prisma estimating models for `Estimate`, `EstimateVersion`, assumptions, scope items, demand lines, rate cards, resource snapshots, metrics, and exports. - Added first-class Prisma estimating models for `Estimate`, `EstimateVersion`, assumptions, scope items, demand lines, rate cards, resource snapshots, metrics, and exports.
- Keep this slice deliberately narrow: persistence + shared contracts + application/engine boundaries first, before any wizard/workspace UI. That avoids baking spreadsheet-shaped UI assumptions into the domain model. - Keep this slice deliberately narrow: persistence + shared contracts + application/engine boundaries first, before any wizard/workspace UI. That avoids baking spreadsheet-shaped UI assumptions into the domain model.
- Shared estimate enums/types/schemas now live in `@planarchy/shared`, and initial application commands/queries (`createEstimate`, `listEstimates`, `getEstimateById`) live in `@planarchy/application`. - Shared estimate enums/types/schemas now live in `@capakraken/shared`, and initial application commands/queries (`createEstimate`, `listEstimates`, `getEstimateById`) live in `@capakraken/application`.
- Added a small engine contract `summarizeEstimateDemandLines()` for aggregate financial totals so later estimate work can reuse a typed pure-function boundary instead of recomputing ad hoc in routers/components. - Added a small engine contract `summarizeEstimateDemandLines()` for aggregate financial totals so later estimate work can reuse a typed pure-function boundary instead of recomputing ad hoc in routers/components.
### 2026-03-11 | Architecture | Tasks 23-27: Bulk Edit, Validation, Export, Reorder ### 2026-03-11 | Architecture | Tasks 23-27: Bulk Edit, Validation, Export, Reorder
@@ -61,10 +61,10 @@
- `useSearchParams` requires `<Suspense>` wrapping at the page level in Next.js App Router or the page will be statically rendered without search param access. - `useSearchParams` requires `<Suspense>` wrapping at the page level in Next.js App Router or the page will be statically rendered without search param access.
### 2026-03-11 | Security | Phase 0 critical fixes ### 2026-03-11 | Security | Phase 0 critical fixes
- `user.create` was hashing passwords with SHA-256; `auth.ts` verifies with Argon2 → users created via admin couldn't log in. Fix: import `hash` from `@node-rs/argon2` in the router. Must also declare `@node-rs/argon2` in `packages/api/package.json` — being a dep of `@planarchy/db` is not enough for TS resolution. - `user.create` was hashing passwords with SHA-256; `auth.ts` verifies with Argon2 → users created via admin couldn't log in. Fix: import `hash` from `@node-rs/argon2` in the router. Must also declare `@node-rs/argon2` in `packages/api/package.json` — being a dep of `@capakraken/db` is not enough for TS resolution.
- `notification.create` was `protectedProcedure` → any logged-in user could create notifications for arbitrary users. Fix: changed to `managerProcedure`. - `notification.create` was `protectedProcedure` → any logged-in user could create notifications for arbitrary users. Fix: changed to `managerProcedure`.
- `testAiConnection` always built Azure deployment URLs regardless of `aiProvider`. Fix: branch on provider, use `https://api.openai.com/v1/chat/completions` with `Authorization: Bearer` for OpenAI. - `testAiConnection` always built Azure deployment URLs regardless of `aiProvider`. Fix: branch on provider, use `https://api.openai.com/v1/chat/completions` with `Authorization: Bearer` for OpenAI.
- `@planarchy/shared` had `test:unit: vitest run` in package.json but no test files → turbo failed. Fix: remove the script (tests live only in engine/staffing). - `@capakraken/shared` had `test:unit: vitest run` in package.json but no test files → turbo failed. Fix: remove the script (tests live only in engine/staffing).
- `crypto.randomUUID()` in `packages/shared/src/schemas/project.schema.ts` failed typecheck because base tsconfig uses `"lib": ["ES2022"]` without DOM. Fix: add `"lib": ["ES2022", "DOM"]` in the shared package's own tsconfig. - `crypto.randomUUID()` in `packages/shared/src/schemas/project.schema.ts` failed typecheck because base tsconfig uses `"lib": ["ES2022"]` without DOM. Fix: add `"lib": ["ES2022", "DOM"]` in the shared package's own tsconfig.
### 2026-03-09 | Performance | Budget utilization showing 562% due to wrong aggregation ### 2026-03-09 | Performance | Budget utilization showing 562% due to wrong aggregation
@@ -149,7 +149,7 @@ For modal focus trapping: create a `panelRef = useRef<HTMLDivElement>(null)`, ca
--- ---
### 2026-02-xx | Architektur | Prisma-Enum vs. Shared-Enum ### 2026-02-xx | Architektur | Prisma-Enum vs. Shared-Enum
**Problem:** Prisma generiert eigene Enum-Typen, die TypeScript-seitig nicht mit den `@planarchy/shared`-Enums kompatibel sind. **Problem:** Prisma generiert eigene Enum-Typen, die TypeScript-seitig nicht mit den `@capakraken/shared`-Enums kompatibel sind.
**Lösung:** An Client-Grenzen `as unknown as SharedType` casten: **Lösung:** An Client-Grenzen `as unknown as SharedType` casten:
- `project as unknown as Project` - `project as unknown as Project`
- `form.orderType as unknown as OrderType` - `form.orderType as unknown as OrderType`
@@ -181,7 +181,7 @@ For modal focus trapping: create a `panelRef = useRef<HTMLDivElement>(null)`, ca
### 2026-03-06 | Architektur | Redis Pub/Sub für SSE ### 2026-03-06 | Architektur | Redis Pub/Sub für SSE
**Problem:** SSE Event-Bus war ein In-Memory-Singleton, funktioniert nicht bei mehreren Server-Instanzen. **Problem:** SSE Event-Bus war ein In-Memory-Singleton, funktioniert nicht bei mehreren Server-Instanzen.
**Lösung:** `ioredis` in `@planarchy/api` hinzugefügt. Publisher schreibt Events in Redis-Channel `planarchy:sse`, Subscriber auf jeder Instanz empfängt und liefert lokal aus. Graceful Degradation: bei Redis-Ausfall weiterhin lokale Delivery. **Lösung:** `ioredis` in `@capakraken/api` hinzugefügt. Publisher schreibt Events in Redis-Channel `planarchy:sse`, Subscriber auf jeder Instanz empfängt und liefert lokal aus. Graceful Degradation: bei Redis-Ausfall weiterhin lokale Delivery.
**Import-Pattern:** `import { Redis } from "ioredis"` (named export, nicht default) notwendig mit `moduleResolution: NodeNext` + ioredis v5. **Import-Pattern:** `import { Redis } from "ioredis"` (named export, nicht default) notwendig mit `moduleResolution: NodeNext` + ioredis v5.
**Offene Frage:** In Dev-Umgebung reicht lokale Delivery; Redis läuft auf Port 6380 via Docker Compose. **Offene Frage:** In Dev-Umgebung reicht lokale Delivery; Redis läuft auf Port 6380 via Docker Compose.
+2 -2
View File
@@ -3,7 +3,7 @@ import { expect, test } from "@playwright/test";
test.describe("Admin Pages", () => { test.describe("Admin Pages", () => {
test.beforeEach(async ({ page }) => { test.beforeEach(async ({ page }) => {
await page.goto("/auth/signin"); await page.goto("/auth/signin");
await page.fill('input[type="email"]', "admin@planarchy.dev"); await page.fill('input[type="email"]', "admin@capakraken.dev");
await page.fill('input[type="password"]', "admin123"); await page.fill('input[type="password"]', "admin123");
await page.click('button[type="submit"]'); await page.click('button[type="submit"]');
await expect(page).toHaveURL(/\/(dashboard|resources)/); await expect(page).toHaveURL(/\/(dashboard|resources)/);
@@ -21,7 +21,7 @@ test.describe("Admin Pages", () => {
await expect(page.locator("h1", { hasText: /User Management/i })).toBeVisible({ timeout: 10000 }); await expect(page.locator("h1", { hasText: /User Management/i })).toBeVisible({ timeout: 10000 });
// Should show a table with at least the admin user // Should show a table with at least the admin user
await expect(page.locator("table")).toBeVisible({ timeout: 10000 }); await expect(page.locator("table")).toBeVisible({ timeout: 10000 });
await expect(page.locator("text=admin@planarchy.dev")).toBeVisible({ timeout: 10000 }); await expect(page.locator("text=admin@capakraken.dev")).toBeVisible({ timeout: 10000 });
}); });
test("roles page loads", async ({ page }) => { test("roles page loads", async ({ page }) => {
+1 -1
View File
@@ -3,7 +3,7 @@ import { expect, test } from "@playwright/test";
test.describe("Allocations", () => { test.describe("Allocations", () => {
test.beforeEach(async ({ page }) => { test.beforeEach(async ({ page }) => {
await page.goto("/auth/signin"); await page.goto("/auth/signin");
await page.fill('input[type="email"]', "admin@planarchy.dev"); await page.fill('input[type="email"]', "admin@capakraken.dev");
await page.fill('input[type="password"]', "admin123"); await page.fill('input[type="password"]', "admin123");
await page.click('button[type="submit"]'); await page.click('button[type="submit"]');
await expect(page).toHaveURL(/\/(dashboard|resources)/); await expect(page).toHaveURL(/\/(dashboard|resources)/);
+1 -1
View File
@@ -8,7 +8,7 @@ test.describe("Authentication", () => {
test("admin can sign in", async ({ page }) => { test("admin can sign in", async ({ page }) => {
await page.goto("/auth/signin"); await page.goto("/auth/signin");
await page.fill('input[type="email"]', "admin@planarchy.dev"); await page.fill('input[type="email"]', "admin@capakraken.dev");
await page.fill('input[type="password"]', "admin123"); await page.fill('input[type="password"]', "admin123");
await page.click('button[type="submit"]'); await page.click('button[type="submit"]');
await expect(page).toHaveURL(/\/(dashboard|resources)/); await expect(page).toHaveURL(/\/(dashboard|resources)/);
+1 -1
View File
@@ -3,7 +3,7 @@ import { expect, test } from "@playwright/test";
test.describe("Dashboard", () => { test.describe("Dashboard", () => {
test.beforeEach(async ({ page }) => { test.beforeEach(async ({ page }) => {
await page.goto("/auth/signin"); await page.goto("/auth/signin");
await page.fill('input[type="email"]', "admin@planarchy.dev"); await page.fill('input[type="email"]', "admin@capakraken.dev");
await page.fill('input[type="password"]', "admin123"); await page.fill('input[type="password"]', "admin123");
await page.click('button[type="submit"]'); await page.click('button[type="submit"]');
await expect(page).toHaveURL(/\/(dashboard|resources)/); await expect(page).toHaveURL(/\/(dashboard|resources)/);
+1 -1
View File
@@ -3,7 +3,7 @@ import { expect, test } from "@playwright/test";
test.describe("Estimates", () => { test.describe("Estimates", () => {
test.beforeEach(async ({ page }) => { test.beforeEach(async ({ page }) => {
await page.goto("/auth/signin"); await page.goto("/auth/signin");
await page.fill('input[type="email"]', "admin@planarchy.dev"); await page.fill('input[type="email"]', "admin@capakraken.dev");
await page.fill('input[type="password"]', "admin123"); await page.fill('input[type="password"]', "admin123");
await page.click('button[type="submit"]'); await page.click('button[type="submit"]');
await expect(page).toHaveURL(/\/(dashboard|resources)/); await expect(page).toHaveURL(/\/(dashboard|resources)/);
+1 -1
View File
@@ -3,7 +3,7 @@ import { expect, test } from "@playwright/test";
test.describe("Navigation", () => { test.describe("Navigation", () => {
test.beforeEach(async ({ page }) => { test.beforeEach(async ({ page }) => {
await page.goto("/auth/signin"); await page.goto("/auth/signin");
await page.fill('input[type="email"]', "admin@planarchy.dev"); await page.fill('input[type="email"]', "admin@capakraken.dev");
await page.fill('input[type="password"]', "admin123"); await page.fill('input[type="password"]', "admin123");
await page.click('button[type="submit"]'); await page.click('button[type="submit"]');
await expect(page).toHaveURL(/\/(dashboard|resources)/); await expect(page).toHaveURL(/\/(dashboard|resources)/);
+1 -1
View File
@@ -3,7 +3,7 @@ import { expect, test } from "@playwright/test";
test.describe("Projects", () => { test.describe("Projects", () => {
test.beforeEach(async ({ page }) => { test.beforeEach(async ({ page }) => {
await page.goto("/auth/signin"); await page.goto("/auth/signin");
await page.fill('input[type="email"]', "manager@planarchy.dev"); await page.fill('input[type="email"]', "manager@capakraken.dev");
await page.fill('input[type="password"]', "manager123"); await page.fill('input[type="password"]', "manager123");
await page.click('button[type="submit"]'); await page.click('button[type="submit"]');
await expect(page).toHaveURL(/\/resources/); await expect(page).toHaveURL(/\/resources/);
+1 -1
View File
@@ -3,7 +3,7 @@ import { expect, test } from "@playwright/test";
test.describe("Resources", () => { test.describe("Resources", () => {
test.beforeEach(async ({ page }) => { test.beforeEach(async ({ page }) => {
await page.goto("/auth/signin"); await page.goto("/auth/signin");
await page.fill('input[type="email"]', "manager@planarchy.dev"); await page.fill('input[type="email"]', "manager@capakraken.dev");
await page.fill('input[type="password"]', "manager123"); await page.fill('input[type="password"]', "manager123");
await page.click('button[type="submit"]'); await page.click('button[type="submit"]');
await expect(page).toHaveURL(/\/resources/); await expect(page).toHaveURL(/\/resources/);
+1 -1
View File
@@ -3,7 +3,7 @@ import { expect, test } from "@playwright/test";
test.describe("Staffing", () => { test.describe("Staffing", () => {
test.beforeEach(async ({ page }) => { test.beforeEach(async ({ page }) => {
await page.goto("/auth/signin"); await page.goto("/auth/signin");
await page.fill('input[type="email"]', "admin@planarchy.dev"); await page.fill('input[type="email"]', "admin@capakraken.dev");
await page.fill('input[type="password"]', "admin123"); await page.fill('input[type="password"]', "admin123");
await page.click('button[type="submit"]'); await page.click('button[type="submit"]');
await expect(page).toHaveURL(/\/(dashboard|resources)/); await expect(page).toHaveURL(/\/(dashboard|resources)/);
+2 -2
View File
@@ -5,10 +5,10 @@ test.describe("Timeline", () => {
test.beforeEach(async ({ page }) => { test.beforeEach(async ({ page }) => {
await page.addInitScript(() => { await page.addInitScript(() => {
localStorage.setItem("planarchy_theme", JSON.stringify({ mode: "dark" })); localStorage.setItem("capakraken_theme", JSON.stringify({ mode: "dark" }));
}); });
await page.goto("/auth/signin"); await page.goto("/auth/signin");
await page.fill('input[type="email"]', "admin@planarchy.dev"); await page.fill('input[type="email"]', "admin@capakraken.dev");
await page.fill('input[type="password"]', "admin123"); await page.fill('input[type="password"]', "admin123");
await page.click('button[type="submit"]'); await page.click('button[type="submit"]');
await expect(page).toHaveURL(/\/(dashboard|resources)/); await expect(page).toHaveURL(/\/(dashboard|resources)/);
+2 -2
View File
@@ -4,7 +4,7 @@ test.describe("Vacations", () => {
test.describe("My Vacations (self-service)", () => { test.describe("My Vacations (self-service)", () => {
test.beforeEach(async ({ page }) => { test.beforeEach(async ({ page }) => {
await page.goto("/auth/signin"); await page.goto("/auth/signin");
await page.fill('input[type="email"]', "admin@planarchy.dev"); await page.fill('input[type="email"]', "admin@capakraken.dev");
await page.fill('input[type="password"]', "admin123"); await page.fill('input[type="password"]', "admin123");
await page.click('button[type="submit"]'); await page.click('button[type="submit"]');
await expect(page).toHaveURL(/\/(dashboard|resources)/); await expect(page).toHaveURL(/\/(dashboard|resources)/);
@@ -38,7 +38,7 @@ test.describe("Vacations", () => {
test.describe("Vacation Management", () => { test.describe("Vacation Management", () => {
test.beforeEach(async ({ page }) => { test.beforeEach(async ({ page }) => {
await page.goto("/auth/signin"); await page.goto("/auth/signin");
await page.fill('input[type="email"]', "admin@planarchy.dev"); await page.fill('input[type="email"]', "admin@capakraken.dev");
await page.fill('input[type="password"]', "admin123"); await page.fill('input[type="password"]', "admin123");
await page.click('button[type="submit"]'); await page.click('button[type="submit"]');
await expect(page).toHaveURL(/\/(dashboard|resources)/); await expect(page).toHaveURL(/\/(dashboard|resources)/);
+6 -6
View File
@@ -8,12 +8,12 @@ const nextConfig: NextConfig = {
optimizePackageImports: ["recharts", "date-fns"], optimizePackageImports: ["recharts", "date-fns"],
}, },
transpilePackages: [ transpilePackages: [
"@planarchy/api", "@capakraken/api",
"@planarchy/db", "@capakraken/db",
"@planarchy/engine", "@capakraken/engine",
"@planarchy/shared", "@capakraken/shared",
"@planarchy/staffing", "@capakraken/staffing",
"@planarchy/ui", "@capakraken/ui",
], ],
typedRoutes: true, typedRoutes: true,
async headers() { async headers() {
+8 -8
View File
@@ -1,5 +1,5 @@
{ {
"name": "@planarchy/web", "name": "@capakraken/web",
"version": "0.1.0", "version": "0.1.0",
"private": true, "private": true,
"scripts": { "scripts": {
@@ -15,12 +15,12 @@
"@dnd-kit/sortable": "^10.0.0", "@dnd-kit/sortable": "^10.0.0",
"@dnd-kit/utilities": "^3.2.2", "@dnd-kit/utilities": "^3.2.2",
"@node-rs/argon2": "^2.0.2", "@node-rs/argon2": "^2.0.2",
"@planarchy/api": "workspace:*", "@capakraken/api": "workspace:*",
"@planarchy/application": "workspace:*", "@capakraken/application": "workspace:*",
"@planarchy/db": "workspace:*", "@capakraken/db": "workspace:*",
"@planarchy/engine": "workspace:*", "@capakraken/engine": "workspace:*",
"@planarchy/shared": "workspace:*", "@capakraken/shared": "workspace:*",
"@planarchy/ui": "workspace:*", "@capakraken/ui": "workspace:*",
"@react-pdf/renderer": "^4.3.2", "@react-pdf/renderer": "^4.3.2",
"@sentry/nextjs": "^10.45.0", "@sentry/nextjs": "^10.45.0",
"@tanstack/react-query": "^5.62.16", "@tanstack/react-query": "^5.62.16",
@@ -44,7 +44,7 @@
"zod": "^3.23.8" "zod": "^3.23.8"
}, },
"devDependencies": { "devDependencies": {
"@planarchy/tsconfig": "workspace:*", "@capakraken/tsconfig": "workspace:*",
"@playwright/test": "^1.49.1", "@playwright/test": "^1.49.1",
"@types/node": "^22.10.2", "@types/node": "^22.10.2",
"@types/react": "^19.0.6", "@types/react": "^19.0.6",
@@ -2,7 +2,7 @@
import { useMemo, useState } from "react"; import { useMemo, useState } from "react";
import Link from "next/link"; import Link from "next/link";
import { EstimateStatus, type EstimateVersionStatus } from "@planarchy/shared"; import { EstimateStatus, type EstimateVersionStatus } from "@capakraken/shared";
import { clsx } from "clsx"; import { clsx } from "clsx";
import { EstimateWizard } from "~/components/estimates/EstimateWizard.js"; import { EstimateWizard } from "~/components/estimates/EstimateWizard.js";
import { InfoTooltip } from "~/components/ui/InfoTooltip.js"; import { InfoTooltip } from "~/components/ui/InfoTooltip.js";
@@ -3,8 +3,8 @@
import { useState, useEffect, useCallback, useMemo, useRef } from "react"; import { useState, useEffect, useCallback, useMemo, useRef } from "react";
import { createPortal } from "react-dom"; import { createPortal } from "react-dom";
import { formatDate, formatMoney } from "~/lib/format.js"; import { formatDate, formatMoney } from "~/lib/format.js";
import type { Project, ColumnDef } from "@planarchy/shared"; import type { Project, ColumnDef } from "@capakraken/shared";
import { ProjectStatus, PROJECT_COLUMNS, BlueprintTarget } from "@planarchy/shared"; import { ProjectStatus, PROJECT_COLUMNS, BlueprintTarget } from "@capakraken/shared";
import Link from "next/link"; import Link from "next/link";
import Image from "next/image"; import Image from "next/image";
import { clsx } from "clsx"; import { clsx } from "clsx";
@@ -3,9 +3,9 @@
import { createPortal } from "react-dom"; import { createPortal } from "react-dom";
import { useState, useEffect, useCallback, useMemo, useRef, type ReactNode } from "react"; import { useState, useEffect, useCallback, useMemo, useRef, type ReactNode } from "react";
import Link from "next/link"; import Link from "next/link";
import type { Resource, SkillEntry } from "@planarchy/shared"; import type { Resource, SkillEntry } from "@capakraken/shared";
import { RESOURCE_COLUMNS } from "@planarchy/shared"; import { RESOURCE_COLUMNS } from "@capakraken/shared";
import { BlueprintTarget, ResourceType } from "@planarchy/shared"; import { BlueprintTarget, ResourceType } from "@capakraken/shared";
import { trpc } from "~/lib/trpc/client.js"; import { trpc } from "~/lib/trpc/client.js";
import { formatMoney } from "~/lib/format.js"; import { formatMoney } from "~/lib/format.js";
import { generateCsv, downloadCsv } from "~/lib/csv-export.js"; import { generateCsv, downloadCsv } from "~/lib/csv-export.js";
@@ -1,6 +1,6 @@
import { NextResponse } from "next/server"; import { NextResponse } from "next/server";
import { prisma } from "@planarchy/db"; import { prisma } from "@capakraken/db";
import { checkChargeabilityAlerts } from "@planarchy/api"; import { checkChargeabilityAlerts } from "@capakraken/api";
export const dynamic = "force-dynamic"; export const dynamic = "force-dynamic";
export const runtime = "nodejs"; export const runtime = "nodejs";
@@ -1,6 +1,6 @@
import { NextResponse } from "next/server"; import { NextResponse } from "next/server";
import { prisma } from "@planarchy/db"; import { prisma } from "@capakraken/db";
import { checkPendingEstimateReminders } from "@planarchy/api"; import { checkPendingEstimateReminders } from "@capakraken/api";
export const dynamic = "force-dynamic"; export const dynamic = "force-dynamic";
export const runtime = "nodejs"; export const runtime = "nodejs";
@@ -1,6 +1,6 @@
import { NextResponse } from "next/server"; import { NextResponse } from "next/server";
import { prisma } from "@planarchy/db"; import { prisma } from "@capakraken/db";
import { autoImportPublicHolidays } from "@planarchy/api"; import { autoImportPublicHolidays } from "@capakraken/api";
export const dynamic = "force-dynamic"; export const dynamic = "force-dynamic";
export const runtime = "nodejs"; export const runtime = "nodejs";
+1 -1
View File
@@ -1,5 +1,5 @@
import { NextResponse } from "next/server"; import { NextResponse } from "next/server";
import { eventBus } from "@planarchy/api/sse"; import { eventBus } from "@capakraken/api/sse";
export const dynamic = "force-dynamic"; export const dynamic = "force-dynamic";
export const runtime = "nodejs"; export const runtime = "nodejs";
+2 -2
View File
@@ -1,5 +1,5 @@
import { NextResponse } from "next/server"; import { NextResponse } from "next/server";
import { prisma } from "@planarchy/db"; import { prisma } from "@capakraken/db";
import { createConnection } from "net"; import { createConnection } from "net";
export const dynamic = "force-dynamic"; export const dynamic = "force-dynamic";
@@ -18,7 +18,7 @@ async function checkPostgres(): Promise<"ok" | "error"> {
/** /**
* Lightweight Redis PING check using a raw TCP socket. * Lightweight Redis PING check using a raw TCP socket.
* Avoids importing ioredis (which is only a dependency of @planarchy/api). * Avoids importing ioredis (which is only a dependency of @capakraken/api).
*/ */
async function checkRedis(): Promise<"ok" | "error"> { async function checkRedis(): Promise<"ok" | "error"> {
return new Promise((resolve) => { return new Promise((resolve) => {
@@ -2,10 +2,10 @@ import { renderToBuffer } from "@react-pdf/renderer";
import { createElement } from "react"; import { createElement } from "react";
import { NextResponse } from "next/server"; import { NextResponse } from "next/server";
import * as XLSX from "xlsx"; import * as XLSX from "xlsx";
import { buildSplitAllocationReadModel } from "@planarchy/application"; import { buildSplitAllocationReadModel } from "@capakraken/application";
import { anonymizeResource, getAnonymizationDirectory } from "@planarchy/api"; import { anonymizeResource, getAnonymizationDirectory } from "@capakraken/api";
import { prisma } from "@planarchy/db"; import { prisma } from "@capakraken/db";
import type { AllocationLike } from "@planarchy/shared"; import type { AllocationLike } from "@capakraken/shared";
import { auth } from "~/server/auth.js"; import { auth } from "~/server/auth.js";
import { AllocationReport } from "~/components/reports/AllocationReport.js"; import { AllocationReport } from "~/components/reports/AllocationReport.js";
+3 -3
View File
@@ -1,6 +1,6 @@
import { eventBus } from "@planarchy/api/sse"; import { eventBus } from "@capakraken/api/sse";
import { startReminderScheduler } from "@planarchy/api/lib/reminder-scheduler"; import { startReminderScheduler } from "@capakraken/api/lib/reminder-scheduler";
import { SSE_EVENT_TYPES } from "@planarchy/shared"; import { SSE_EVENT_TYPES } from "@capakraken/shared";
import { auth } from "~/server/auth.js"; import { auth } from "~/server/auth.js";
// Start the reminder scheduler (idempotent — only starts once) // Start the reminder scheduler (idempotent — only starts once)
+3 -3
View File
@@ -1,6 +1,6 @@
import { createTRPCContext, loadRoleDefaults } from "@planarchy/api"; import { createTRPCContext, loadRoleDefaults } from "@capakraken/api";
import { appRouter } from "@planarchy/api/router"; import { appRouter } from "@capakraken/api/router";
import { prisma } from "@planarchy/db"; import { prisma } from "@capakraken/db";
import { fetchRequestHandler } from "@trpc/server/adapters/fetch"; import { fetchRequestHandler } from "@trpc/server/adapters/fetch";
import type { NextRequest } from "next/server"; import type { NextRequest } from "next/server";
import { auth } from "~/server/auth.js"; import { auth } from "~/server/auth.js";
+2 -2
View File
@@ -18,7 +18,7 @@ const displayFont = Manrope({
}); });
export const metadata: Metadata = { export const metadata: Metadata = {
metadataBase: new URL("https://planarchy.hartmut-noerenberg.com"), metadataBase: new URL("https://capakraken.hartmut-noerenberg.com"),
title: "CapaKraken — Resource & Capacity Planning", title: "CapaKraken — Resource & Capacity Planning",
description: "Interactive resource planning and project staffing tool", description: "Interactive resource planning and project staffing tool",
manifest: "/manifest.json", manifest: "/manifest.json",
@@ -51,7 +51,7 @@ export default function RootLayout({ children }: { children: React.ReactNode })
<head> <head>
<script dangerouslySetInnerHTML={{__html: ` <script dangerouslySetInnerHTML={{__html: `
try { try {
var p = JSON.parse(localStorage.getItem('planarchy_theme') || '{}'); var p = JSON.parse(localStorage.getItem('capakraken_theme') || '{}');
if (p.mode === 'dark') document.documentElement.classList.add('dark'); if (p.mode === 'dark') document.documentElement.classList.add('dark');
if (p.accent) document.documentElement.setAttribute('data-accent', p.accent); if (p.accent) document.documentElement.setAttribute('data-accent', p.accent);
} catch(e) {} } catch(e) {}
@@ -3,7 +3,7 @@
import { useState, useRef } from "react"; import { useState, useRef } from "react";
import { trpc } from "~/lib/trpc/client.js"; import { trpc } from "~/lib/trpc/client.js";
import { parseSkillMatrixWorkbook, matchRoleName } from "~/lib/skillMatrixParser.js"; import { parseSkillMatrixWorkbook, matchRoleName } from "~/lib/skillMatrixParser.js";
import type { SkillEntry } from "@planarchy/shared"; import type { SkillEntry } from "@capakraken/shared";
interface ParsedEntry { interface ParsedEntry {
fileName: string; fileName: string;
@@ -3,8 +3,8 @@
import { useState } from "react"; import { useState } from "react";
import Link from "next/link"; import Link from "next/link";
import { clsx } from "clsx"; import { clsx } from "clsx";
import { Button } from "@planarchy/ui"; import { Button } from "@capakraken/ui";
import { Badge } from "@planarchy/ui"; import { Badge } from "@capakraken/ui";
import { trpc } from "~/lib/trpc/client.js"; import { trpc } from "~/lib/trpc/client.js";
import { AnimatedModal } from "~/components/ui/AnimatedModal.js"; import { AnimatedModal } from "~/components/ui/AnimatedModal.js";
import { ShimmerSkeleton } from "~/components/ui/ShimmerSkeleton.js"; import { ShimmerSkeleton } from "~/components/ui/ShimmerSkeleton.js";
@@ -3,8 +3,8 @@
import { useState } from "react"; import { useState } from "react";
import Link from "next/link"; import Link from "next/link";
import { clsx } from "clsx"; import { clsx } from "clsx";
import { Button } from "@planarchy/ui"; import { Button } from "@capakraken/ui";
import { Badge } from "@planarchy/ui"; import { Badge } from "@capakraken/ui";
import { trpc } from "~/lib/trpc/client.js"; import { trpc } from "~/lib/trpc/client.js";
import { AnimatedModal } from "~/components/ui/AnimatedModal.js"; import { AnimatedModal } from "~/components/ui/AnimatedModal.js";
import { ConfirmDialog } from "~/components/ui/ConfirmDialog.js"; import { ConfirmDialog } from "~/components/ui/ConfirmDialog.js";
@@ -1,7 +1,7 @@
"use client"; "use client";
import { useState } from "react"; import { useState } from "react";
import { PermissionKey } from "@planarchy/shared"; import { PermissionKey } from "@capakraken/shared";
import { trpc } from "~/lib/trpc/client.js"; import { trpc } from "~/lib/trpc/client.js";
import { InfoTooltip } from "~/components/ui/InfoTooltip.js"; import { InfoTooltip } from "~/components/ui/InfoTooltip.js";
@@ -1294,13 +1294,13 @@ export function SystemSettingsClient() {
/> />
</div> </div>
<div> <div>
<label className={LABEL_CLASS}><span className="flex items-center">From Address <InfoTooltip content="The sender email address shown in notification emails (e.g. noreply@planarchy.app)." /></span></label> <label className={LABEL_CLASS}><span className="flex items-center">From Address <InfoTooltip content="The sender email address shown in notification emails (e.g. noreply@capakraken.app)." /></span></label>
<input <input
type="email" type="email"
className={INPUT_CLASS} className={INPUT_CLASS}
value={smtpFrom} value={smtpFrom}
onChange={(e) => setSmtpFrom(e.target.value)} onChange={(e) => setSmtpFrom(e.target.value)}
placeholder="noreply@planarchy.app" placeholder="noreply@capakraken.app"
/> />
</div> </div>
<div className={`${CHECKBOX_ROW_CLASS} pt-0 md:mt-[1.65rem]`}> <div className={`${CHECKBOX_ROW_CLASS} pt-0 md:mt-[1.65rem]`}>
@@ -1,7 +1,7 @@
"use client"; "use client";
import { useState, useMemo } from "react"; import { useState, useMemo } from "react";
import { SystemRole, PermissionKey, ROLE_DEFAULT_PERMISSIONS, type PermissionOverrides } from "@planarchy/shared"; import { SystemRole, PermissionKey, ROLE_DEFAULT_PERMISSIONS, type PermissionOverrides } from "@capakraken/shared";
import { trpc } from "~/lib/trpc/client.js"; import { trpc } from "~/lib/trpc/client.js";
import { AnimatedModal } from "~/components/ui/AnimatedModal.js"; import { AnimatedModal } from "~/components/ui/AnimatedModal.js";
import { SuccessToast } from "~/components/ui/SuccessToast.js"; import { SuccessToast } from "~/components/ui/SuccessToast.js";
@@ -3,8 +3,8 @@
import { useState, useEffect, useRef, useMemo } from "react"; import { useState, useEffect, useRef, useMemo } from "react";
import { useFocusTrap } from "~/hooks/useFocusTrap.js"; import { useFocusTrap } from "~/hooks/useFocusTrap.js";
import { useInvalidatePlanningViews } from "~/hooks/useInvalidatePlanningViews.js"; import { useInvalidatePlanningViews } from "~/hooks/useInvalidatePlanningViews.js";
import { AllocationStatus } from "@planarchy/shared"; import { AllocationStatus } from "@capakraken/shared";
import type { AllocationWithDetails, RecurrencePattern } from "@planarchy/shared"; import type { AllocationWithDetails, RecurrencePattern } from "@capakraken/shared";
import { trpc } from "~/lib/trpc/client.js"; import { trpc } from "~/lib/trpc/client.js";
import { getPlanningEntryMutationId } from "~/lib/planningEntryIds.js"; import { getPlanningEntryMutationId } from "~/lib/planningEntryIds.js";
import { DateInput } from "~/components/ui/DateInput.js"; import { DateInput } from "~/components/ui/DateInput.js";
@@ -4,8 +4,8 @@ import { useState, useEffect, useMemo, useCallback } from "react";
import { formatDate } from "~/lib/format.js"; import { formatDate } from "~/lib/format.js";
import { trpc } from "~/lib/trpc/client.js"; import { trpc } from "~/lib/trpc/client.js";
import { AllocationModal } from "./AllocationModal.js"; import { AllocationModal } from "./AllocationModal.js";
import type { AllocationLike, AllocationReadModel, AllocationWithDetails, ColumnDef } from "@planarchy/shared"; import type { AllocationLike, AllocationReadModel, AllocationWithDetails, ColumnDef } from "@capakraken/shared";
import { AllocationStatus, ALLOCATION_COLUMNS } from "@planarchy/shared"; import { AllocationStatus, ALLOCATION_COLUMNS } from "@capakraken/shared";
import { useSelection } from "~/hooks/useSelection.js"; import { useSelection } from "~/hooks/useSelection.js";
import { BatchActionBar } from "~/components/ui/BatchActionBar.js"; import { BatchActionBar } from "~/components/ui/BatchActionBar.js";
import { ConfirmDialog } from "~/components/ui/ConfirmDialog.js"; import { ConfirmDialog } from "~/components/ui/ConfirmDialog.js";
@@ -188,7 +188,7 @@ export function AllocationsClient() {
// ─── View mode: grouped (default) vs flat ────────────────────────────────── // ─── View mode: grouped (default) vs flat ──────────────────────────────────
const [viewMode, setViewMode] = useState<"grouped" | "flat">(() => { const [viewMode, setViewMode] = useState<"grouped" | "flat">(() => {
if (typeof window === "undefined") return "grouped"; if (typeof window === "undefined") return "grouped";
return (localStorage.getItem("planarchy:allocations:viewMode") as "grouped" | "flat") ?? "grouped"; return (localStorage.getItem("capakraken:allocations:viewMode") as "grouped" | "flat") ?? "grouped";
}); });
const [collapsedGroups, setCollapsedGroups] = useState<Set<string> | "all">("all"); const [collapsedGroups, setCollapsedGroups] = useState<Set<string> | "all">("all");
// Track expanded project sub-groups: key = "resourceId::projectId" // Track expanded project sub-groups: key = "resourceId::projectId"
@@ -197,7 +197,7 @@ export function AllocationsClient() {
const toggleViewMode = useCallback(() => { const toggleViewMode = useCallback(() => {
setViewMode((prev) => { setViewMode((prev) => {
const next = prev === "grouped" ? "flat" : "grouped"; const next = prev === "grouped" ? "flat" : "grouped";
localStorage.setItem("planarchy:allocations:viewMode", next); localStorage.setItem("capakraken:allocations:viewMode", next);
return next; return next;
}); });
}, []); }, []);
@@ -1,7 +1,7 @@
"use client"; "use client";
import { useRef, useState, useMemo } from "react"; import { useRef, useState, useMemo } from "react";
import { AllocationStatus } from "@planarchy/shared"; import { AllocationStatus } from "@capakraken/shared";
import { useFocusTrap } from "~/hooks/useFocusTrap.js"; import { useFocusTrap } from "~/hooks/useFocusTrap.js";
import { formatCents, formatDateMedium } from "~/lib/format.js"; import { formatCents, formatDateMedium } from "~/lib/format.js";
import { getPlanningEntryMutationId } from "~/lib/planningEntryIds.js"; import { getPlanningEntryMutationId } from "~/lib/planningEntryIds.js";
@@ -1,7 +1,7 @@
"use client"; "use client";
import { RecurrenceFrequency } from "@planarchy/shared"; import { RecurrenceFrequency } from "@capakraken/shared";
import type { RecurrencePattern } from "@planarchy/shared"; import type { RecurrencePattern } from "@capakraken/shared";
import { InfoTooltip } from "~/components/ui/InfoTooltip.js"; import { InfoTooltip } from "~/components/ui/InfoTooltip.js";
const WEEKDAY_LABELS = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"]; const WEEKDAY_LABELS = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
@@ -40,7 +40,7 @@ interface Message {
content: string; content: string;
} }
const STORAGE_KEY = "planarchy-chat-messages"; const STORAGE_KEY = "capakraken-chat-messages";
/** Load messages from sessionStorage (survives page reloads, clears on tab close). */ /** Load messages from sessionStorage (survives page reloads, clears on tab close). */
function loadPersistedMessages(): Message[] { function loadPersistedMessages(): Message[] {
@@ -1,8 +1,8 @@
"use client"; "use client";
import { useState, useMemo, useCallback } from "react"; import { useState, useMemo, useCallback } from "react";
import { FieldType } from "@planarchy/shared"; import { FieldType } from "@capakraken/shared";
import type { BlueprintFieldDefinition, FieldOption, StaffingRequirement } from "@planarchy/shared"; import type { BlueprintFieldDefinition, FieldOption, StaffingRequirement } from "@capakraken/shared";
import { trpc } from "~/lib/trpc/client.js"; import { trpc } from "~/lib/trpc/client.js";
import { RolePresetsEditor } from "./RolePresetsEditor.js"; import { RolePresetsEditor } from "./RolePresetsEditor.js";
import { FieldCard } from "./FieldCard.js"; import { FieldCard } from "./FieldCard.js";
@@ -1,8 +1,8 @@
"use client"; "use client";
import { useState } from "react"; import { useState } from "react";
import { FieldType } from "@planarchy/shared"; import { FieldType } from "@capakraken/shared";
import type { BlueprintFieldDefinition, FieldOption, StaffingRequirement } from "@planarchy/shared"; import type { BlueprintFieldDefinition, FieldOption, StaffingRequirement } from "@capakraken/shared";
import { trpc } from "~/lib/trpc/client.js"; import { trpc } from "~/lib/trpc/client.js";
import { RolePresetsEditor } from "./RolePresetsEditor.js"; import { RolePresetsEditor } from "./RolePresetsEditor.js";
@@ -2,8 +2,8 @@
import { useState, useEffect } from "react"; import { useState, useEffect } from "react";
import type { FormEvent, MouseEvent } from "react"; import type { FormEvent, MouseEvent } from "react";
import { BlueprintTarget } from "@planarchy/shared"; import { BlueprintTarget } from "@capakraken/shared";
import type { BlueprintFieldDefinition } from "@planarchy/shared"; import type { BlueprintFieldDefinition } from "@capakraken/shared";
import { trpc } from "~/lib/trpc/client.js"; import { trpc } from "~/lib/trpc/client.js";
import { BlueprintFieldCatalog } from "./BlueprintFieldCatalog.js"; import { BlueprintFieldCatalog } from "./BlueprintFieldCatalog.js";
import { useSelection } from "~/hooks/useSelection.js"; import { useSelection } from "~/hooks/useSelection.js";
@@ -501,7 +501,7 @@ export function BlueprintsClient() {
blueprintName={editingBlueprint.name} blueprintName={editingBlueprint.name}
blueprintTarget={editingBlueprint.target} blueprintTarget={editingBlueprint.target}
initialFieldDefs={Array.isArray(editingBlueprint.fieldDefs) ? (editingBlueprint.fieldDefs as BlueprintFieldDefinition[]) : []} initialFieldDefs={Array.isArray(editingBlueprint.fieldDefs) ? (editingBlueprint.fieldDefs as BlueprintFieldDefinition[]) : []}
initialRolePresets={Array.isArray(editingBlueprint.rolePresets) ? (editingBlueprint.rolePresets as import("@planarchy/shared").StaffingRequirement[]) : []} initialRolePresets={Array.isArray(editingBlueprint.rolePresets) ? (editingBlueprint.rolePresets as import("@capakraken/shared").StaffingRequirement[]) : []}
initialTab={editingTab} initialTab={editingTab}
onClose={() => setEditingBlueprint(null)} onClose={() => setEditingBlueprint(null)}
/> />
@@ -1,8 +1,8 @@
"use client"; "use client";
import { useState } from "react"; import { useState } from "react";
import { FieldType } from "@planarchy/shared"; import { FieldType } from "@capakraken/shared";
import type { FieldOption } from "@planarchy/shared"; import type { FieldOption } from "@capakraken/shared";
import type { CatalogField } from "~/lib/blueprint-field-catalog.js"; import type { CatalogField } from "~/lib/blueprint-field-catalog.js";
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
@@ -1,7 +1,7 @@
"use client"; "use client";
import { useState } from "react"; import { useState } from "react";
import type { StaffingRequirement } from "@planarchy/shared"; import type { StaffingRequirement } from "@capakraken/shared";
import { uuid } from "~/lib/uuid.js"; import { uuid } from "~/lib/uuid.js";
const INPUT_CLS = const INPUT_CLS =
@@ -1,6 +1,6 @@
"use client"; "use client";
import type { DashboardWidgetType } from "@planarchy/shared/types"; import type { DashboardWidgetType } from "@capakraken/shared/types";
import { WIDGET_CATALOG } from "./widget-registry.js"; import { WIDGET_CATALOG } from "./widget-registry.js";
interface AddWidgetModalProps { interface AddWidgetModalProps {
@@ -1,6 +1,6 @@
"use client"; "use client";
import type { DashboardWidgetConfig, DashboardWidgetType } from "@planarchy/shared/types"; import type { DashboardWidgetConfig, DashboardWidgetType } from "@capakraken/shared/types";
import dynamic from "next/dynamic"; import dynamic from "next/dynamic";
import { Suspense, useState, useRef, useEffect } from "react"; import { Suspense, useState, useRef, useEffect } from "react";
import { useDashboardLayout } from "~/hooks/useDashboardLayout.js"; import { useDashboardLayout } from "~/hooks/useDashboardLayout.js";
@@ -2,7 +2,7 @@ import {
DASHBOARD_WIDGET_CATALOG, DASHBOARD_WIDGET_CATALOG,
type DashboardWidgetCatalogEntry, type DashboardWidgetCatalogEntry,
type DashboardWidgetType, type DashboardWidgetType,
} from "@planarchy/shared/types"; } from "@capakraken/shared/types";
import { lazy, type ComponentType, type LazyExoticComponent } from "react"; import { lazy, type ComponentType, type LazyExoticComponent } from "react";
type WidgetUpdate = Record<string, unknown>; type WidgetUpdate = Record<string, unknown>;
@@ -5,7 +5,7 @@ import Link from "next/link";
import { trpc } from "~/lib/trpc/client.js"; import { trpc } from "~/lib/trpc/client.js";
import type { WidgetProps } from "~/components/dashboard/widget-registry.js"; import type { WidgetProps } from "~/components/dashboard/widget-registry.js";
import { formatCents, formatMoney } from "~/lib/format.js"; import { formatCents, formatMoney } from "~/lib/format.js";
import { ProjectStatus } from "@planarchy/shared/types"; import { ProjectStatus } from "@capakraken/shared/types";
import { InfoTooltip } from "~/components/ui/InfoTooltip.js"; import { InfoTooltip } from "~/components/ui/InfoTooltip.js";
import { PROJECT_STATUS_BADGE as STATUS_COLORS } from "~/lib/status-styles.js"; import { PROJECT_STATUS_BADGE as STATUS_COLORS } from "~/lib/status-styles.js";
import { AnimatedNumber } from "~/components/ui/AnimatedNumber.js"; import { AnimatedNumber } from "~/components/ui/AnimatedNumber.js";
@@ -2,8 +2,8 @@
import { clsx } from "clsx"; import { clsx } from "clsx";
import { DateInput } from "~/components/ui/DateInput.js"; import { DateInput } from "~/components/ui/DateInput.js";
import { FieldType } from "@planarchy/shared"; import { FieldType } from "@capakraken/shared";
import type { BlueprintFieldDefinition } from "@planarchy/shared"; import type { BlueprintFieldDefinition } from "@capakraken/shared";
interface Props { interface Props {
fieldDefs: BlueprintFieldDefinition[]; fieldDefs: BlueprintFieldDefinition[];
@@ -2,8 +2,8 @@
import { clsx } from "clsx"; import { clsx } from "clsx";
import { formatDateLong } from "~/lib/format.js"; import { formatDateLong } from "~/lib/format.js";
import { FieldType } from "@planarchy/shared"; import { FieldType } from "@capakraken/shared";
import type { BlueprintFieldDefinition } from "@planarchy/shared"; import type { BlueprintFieldDefinition } from "@capakraken/shared";
interface Props { interface Props {
fieldDefs: BlueprintFieldDefinition[]; fieldDefs: BlueprintFieldDefinition[];
@@ -1,12 +1,12 @@
"use client"; "use client";
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import type { CommercialTerms, PaymentMilestone, PricingModel } from "@planarchy/shared"; import type { CommercialTerms, PaymentMilestone, PricingModel } from "@capakraken/shared";
import { import {
computeCommercialTermsSummary, computeCommercialTermsSummary,
computeMilestoneAmounts, computeMilestoneAmounts,
validatePaymentMilestones, validatePaymentMilestones,
} from "@planarchy/engine"; } from "@capakraken/engine";
import { clsx } from "clsx"; import { clsx } from "clsx";
import { InfoTooltip } from "~/components/ui/InfoTooltip.js"; import { InfoTooltip } from "~/components/ui/InfoTooltip.js";
import { formatMoney } from "~/lib/format.js"; import { formatMoney } from "~/lib/format.js";
@@ -1,8 +1,8 @@
"use client"; "use client";
import { useEffect, useMemo, useRef, useState } from "react"; import { useEffect, useMemo, useRef, useState } from "react";
import { EstimateStatus } from "@planarchy/shared"; import { EstimateStatus } from "@capakraken/shared";
import { computeEvenSpread } from "@planarchy/engine"; import { computeEvenSpread } from "@capakraken/engine";
import { isSpreadsheetFile } from "~/lib/excel.js"; import { isSpreadsheetFile } from "~/lib/excel.js";
import { parseScopeImport } from "~/lib/scopeImportParser.js"; import { parseScopeImport } from "~/lib/scopeImportParser.js";
import { clsx } from "clsx"; import { clsx } from "clsx";
@@ -2,7 +2,7 @@ import type {
EstimateDemandLineCalculationMetadata, EstimateDemandLineCalculationMetadata,
EstimateDemandLineMetadata, EstimateDemandLineMetadata,
EstimateDemandLineRateMode, EstimateDemandLineRateMode,
} from "@planarchy/shared"; } from "@capakraken/shared";
interface ResourceRateSnapshotLike { interface ResourceRateSnapshotLike {
lcrCents: number; lcrCents: number;
@@ -7,7 +7,7 @@ import type {
EstimateExportFormat, EstimateExportFormat,
EstimateStatus, EstimateStatus,
EstimateVersionStatus, EstimateVersionStatus,
} from "@planarchy/shared"; } from "@capakraken/shared";
export interface EstimateMetricView { export interface EstimateMetricView {
id: string; id: string;
@@ -3,7 +3,7 @@
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import Link from "next/link"; import Link from "next/link";
import dynamic from "next/dynamic"; import dynamic from "next/dynamic";
import { EstimateExportFormat } from "@planarchy/shared"; import { EstimateExportFormat } from "@capakraken/shared";
import { clsx } from "clsx"; import { clsx } from "clsx";
import type { import type {
EstimateWorkspaceView, EstimateWorkspaceView,
@@ -1,13 +1,13 @@
"use client"; "use client";
import { useEffect, useMemo, useState } from "react"; import { useEffect, useMemo, useState } from "react";
import type { EstimateDemandLineRateMode } from "@planarchy/shared"; import type { EstimateDemandLineRateMode } from "@capakraken/shared";
import { import {
computeEvenSpread, computeEvenSpread,
getEstimateMonthRange, getEstimateMonthRange,
rebalanceSpread, rebalanceSpread,
summarizeMonthlySpread, summarizeMonthlySpread,
} from "@planarchy/engine"; } from "@capakraken/engine";
import { import {
buildDemandLineMetadata, buildDemandLineMetadata,
getEffectiveDemandLineValues, getEffectiveDemandLineValues,
@@ -8,7 +8,7 @@ import {
type ChapterSubtotal, type ChapterSubtotal,
type ResourceSnapshotDiff, type ResourceSnapshotDiff,
type ScopeItemDiff, type ScopeItemDiff,
} from "@planarchy/engine"; } from "@capakraken/engine";
import type { EstimateVersionView } from "~/components/estimates/EstimateWorkspace.types.js"; import type { EstimateVersionView } from "~/components/estimates/EstimateWorkspace.types.js";
import { InfoTooltip } from "~/components/ui/InfoTooltip.js"; import { InfoTooltip } from "~/components/ui/InfoTooltip.js";
import { formatMoney } from "~/lib/format.js"; import { formatMoney } from "~/lib/format.js";
@@ -1,11 +1,11 @@
"use client"; "use client";
import { useMemo } from "react"; import { useMemo } from "react";
import type { EstimateDemandLineRateMode } from "@planarchy/shared"; import type { EstimateDemandLineRateMode } from "@capakraken/shared";
import { import {
computeEvenSpread, computeEvenSpread,
rebalanceSpread, rebalanceSpread,
} from "@planarchy/engine"; } from "@capakraken/engine";
import { import {
getEffectiveDemandLineValues, getEffectiveDemandLineValues,
} from "~/components/estimates/EstimateWorkspace.calculations.js"; } from "~/components/estimates/EstimateWorkspace.calculations.js";
@@ -3,7 +3,7 @@
import { import {
type EstimateExportArtifactPayload, type EstimateExportArtifactPayload,
EstimateExportFormat, EstimateExportFormat,
} from "@planarchy/shared"; } from "@capakraken/shared";
import type { import type {
EstimateExportView, EstimateExportView,
EstimateVersionView, EstimateVersionView,
@@ -1,7 +1,7 @@
"use client"; "use client";
import { clsx } from "clsx"; import { clsx } from "clsx";
import { EstimateStatus, EstimateVersionStatus } from "@planarchy/shared"; import { EstimateStatus, EstimateVersionStatus } from "@capakraken/shared";
import type { import type {
EstimateMetricView, EstimateMetricView,
EstimateVersionView, EstimateVersionView,
@@ -1,7 +1,7 @@
"use client"; "use client";
import { EstimateVersionStatus } from "@planarchy/shared"; import { EstimateVersionStatus } from "@capakraken/shared";
import { summarizeMonthlySpread } from "@planarchy/engine"; import { summarizeMonthlySpread } from "@capakraken/engine";
import { clsx } from "clsx"; import { clsx } from "clsx";
import { import {
getEffectiveDemandLineValues, getEffectiveDemandLineValues,
@@ -1,6 +1,6 @@
"use client"; "use client";
import { EstimateVersionStatus } from "@planarchy/shared"; import { EstimateVersionStatus } from "@capakraken/shared";
import { clsx } from "clsx"; import { clsx } from "clsx";
import { VersionCompare } from "~/components/estimates/VersionCompare.js"; import { VersionCompare } from "~/components/estimates/VersionCompare.js";
import type { import type {
+1 -1
View File
@@ -15,7 +15,7 @@ import { NotificationBell } from "../notifications/NotificationBell.js";
import { ChatPanel } from "../assistant/ChatPanel.js"; import { ChatPanel } from "../assistant/ChatPanel.js";
import { NavProgressBar } from "~/components/ui/NavProgressBar.js"; import { NavProgressBar } from "~/components/ui/NavProgressBar.js";
const SIDEBAR_COLLAPSED_KEY = "planarchy_sidebar_collapsed"; const SIDEBAR_COLLAPSED_KEY = "capakraken_sidebar_collapsed";
function IconFrame({ children }: { children: ReactNode }) { function IconFrame({ children }: { children: ReactNode }) {
return ( return (
@@ -2,7 +2,7 @@
import { useCallback, useEffect, useRef, useState } from "react"; import { useCallback, useEffect, useRef, useState } from "react";
const DISMISS_KEY = "planarchy_pwa_dismiss"; const DISMISS_KEY = "capakraken_pwa_dismiss";
const DISMISS_DURATION_MS = 30 * 24 * 60 * 60 * 1000; // 30 days const DISMISS_DURATION_MS = 30 * 24 * 60 * 60 * 1000; // 30 days
interface BeforeInstallPromptEvent extends Event { interface BeforeInstallPromptEvent extends Event {
@@ -9,7 +9,7 @@ import { useEffect } from "react";
export function ThemeProvider({ children }: { children: React.ReactNode }) { export function ThemeProvider({ children }: { children: React.ReactNode }) {
useEffect(() => { useEffect(() => {
try { try {
const raw = localStorage.getItem("planarchy_theme"); const raw = localStorage.getItem("capakraken_theme");
if (!raw) return; if (!raw) return;
const prefs = JSON.parse(raw) as { mode?: string; accent?: string }; const prefs = JSON.parse(raw) as { mode?: string; accent?: string };
const html = document.documentElement; const html = document.documentElement;
@@ -6,7 +6,7 @@ import { formatCents, formatDate } from "~/lib/format.js";
import { InfoTooltip } from "~/components/ui/InfoTooltip.js"; import { InfoTooltip } from "~/components/ui/InfoTooltip.js";
import { FillOpenDemandModal } from "~/components/allocations/FillOpenDemandModal.js"; import { FillOpenDemandModal } from "~/components/allocations/FillOpenDemandModal.js";
import { AllocationModal } from "~/components/allocations/AllocationModal.js"; import { AllocationModal } from "~/components/allocations/AllocationModal.js";
import type { AllocationWithDetails } from "@planarchy/shared"; import type { AllocationWithDetails } from "@capakraken/shared";
import type { OpenDemandAssignment } from "~/components/timeline/TimelineProjectPanel.js"; import type { OpenDemandAssignment } from "~/components/timeline/TimelineProjectPanel.js";
import { usePermissions } from "~/hooks/usePermissions.js"; import { usePermissions } from "~/hooks/usePermissions.js";
import { trpc } from "~/lib/trpc/client.js"; import { trpc } from "~/lib/trpc/client.js";
@@ -2,7 +2,7 @@
import { useMemo, useState } from "react"; import { useMemo, useState } from "react";
import { useRouter } from "next/navigation"; import { useRouter } from "next/navigation";
import type { Project } from "@planarchy/shared"; import type { Project } from "@capakraken/shared";
import { ProjectModal } from "./ProjectModal.js"; import { ProjectModal } from "./ProjectModal.js";
import { ConfirmDialog } from "~/components/ui/ConfirmDialog.js"; import { ConfirmDialog } from "~/components/ui/ConfirmDialog.js";
import { usePermissions } from "~/hooks/usePermissions.js"; import { usePermissions } from "~/hooks/usePermissions.js";
@@ -2,8 +2,8 @@
import { useState, useEffect, useRef } from "react"; import { useState, useEffect, useRef } from "react";
import { useFocusTrap } from "~/hooks/useFocusTrap.js"; import { useFocusTrap } from "~/hooks/useFocusTrap.js";
import { OrderType, AllocationType, ProjectStatus } from "@planarchy/shared"; import { OrderType, AllocationType, ProjectStatus } from "@capakraken/shared";
import type { Project } from "@planarchy/shared"; import type { Project } from "@capakraken/shared";
import { trpc } from "~/lib/trpc/client.js"; import { trpc } from "~/lib/trpc/client.js";
import { DateInput } from "~/components/ui/DateInput.js"; import { DateInput } from "~/components/ui/DateInput.js";
import { InfoTooltip } from "~/components/ui/InfoTooltip.js"; import { InfoTooltip } from "~/components/ui/InfoTooltip.js";
@@ -2,8 +2,8 @@
import { useState, useCallback, useEffect, useMemo, useRef } from "react"; import { useState, useCallback, useEffect, useMemo, useRef } from "react";
import { clsx } from "clsx"; import { clsx } from "clsx";
import type { StaffingRequirement } from "@planarchy/shared"; import type { StaffingRequirement } from "@capakraken/shared";
import { BlueprintTarget, OrderType, AllocationType, ProjectStatus, AllocationStatus } from "@planarchy/shared"; import { BlueprintTarget, OrderType, AllocationType, ProjectStatus, AllocationStatus } from "@capakraken/shared";
import { trpc } from "~/lib/trpc/client.js"; import { trpc } from "~/lib/trpc/client.js";
import { uuid } from "~/lib/uuid.js"; import { uuid } from "~/lib/uuid.js";
import { DateInput } from "~/components/ui/DateInput.js"; import { DateInput } from "~/components/ui/DateInput.js";
@@ -656,7 +656,7 @@ function Step3({ state, onChange }: Step3Props) {
// ─── Step 4: Suggestions ───────────────────────────────────────────────────── // ─── Step 4: Suggestions ─────────────────────────────────────────────────────
// Matches StaffingSuggestion from @planarchy/shared (returned by staffing.getSuggestions) // Matches StaffingSuggestion from @capakraken/shared (returned by staffing.getSuggestions)
type SuggestionItem = { type SuggestionItem = {
resourceId: string; resourceId: string;
resourceName: string; resourceName: string;
@@ -1,8 +1,8 @@
"use client"; "use client";
import { useState } from "react"; import { useState } from "react";
import { FieldType } from "@planarchy/shared"; import { FieldType } from "@capakraken/shared";
import type { BlueprintFieldDefinition } from "@planarchy/shared"; import type { BlueprintFieldDefinition } from "@capakraken/shared";
import { trpc } from "~/lib/trpc/client.js"; import { trpc } from "~/lib/trpc/client.js";
const INPUT_CLS = const INPUT_CLS =
@@ -3,7 +3,7 @@
import { useState } from "react"; import { useState } from "react";
import Link from "next/link"; import Link from "next/link";
import dynamic from "next/dynamic"; import dynamic from "next/dynamic";
import type { AllocationLike, AllocationReadModel, AllocationWithDetails, Resource, SkillEntry } from "@planarchy/shared"; import type { AllocationLike, AllocationReadModel, AllocationWithDetails, Resource, SkillEntry } from "@capakraken/shared";
import { trpc } from "~/lib/trpc/client.js"; import { trpc } from "~/lib/trpc/client.js";
import { formatDate, formatMoney } from "~/lib/format.js"; import { formatDate, formatMoney } from "~/lib/format.js";
import { ResourceModal } from "./ResourceModal.js"; import { ResourceModal } from "./ResourceModal.js";
@@ -2,8 +2,8 @@
import { useRef, useState } from "react"; import { useRef, useState } from "react";
import { useFocusTrap } from "~/hooks/useFocusTrap.js"; import { useFocusTrap } from "~/hooks/useFocusTrap.js";
import type { Resource, SkillEntry } from "@planarchy/shared"; import type { Resource, SkillEntry } from "@capakraken/shared";
import { GERMAN_FEDERAL_STATES, inferStateFromPostalCode, ResourceType } from "@planarchy/shared"; import { GERMAN_FEDERAL_STATES, inferStateFromPostalCode, ResourceType } from "@capakraken/shared";
import { trpc } from "~/lib/trpc/client.js"; import { trpc } from "~/lib/trpc/client.js";
import { InfoTooltip } from "~/components/ui/InfoTooltip.js"; import { InfoTooltip } from "~/components/ui/InfoTooltip.js";
@@ -3,7 +3,7 @@
import { useState, useRef } from "react"; import { useState, useRef } from "react";
import { trpc } from "~/lib/trpc/client.js"; import { trpc } from "~/lib/trpc/client.js";
import { parseSkillMatrixWorkbook, matchRoleName } from "~/lib/skillMatrixParser.js"; import { parseSkillMatrixWorkbook, matchRoleName } from "~/lib/skillMatrixParser.js";
import type { SkillEntry } from "@planarchy/shared"; import type { SkillEntry } from "@capakraken/shared";
interface Props { interface Props {
resourceId: string; resourceId: string;
@@ -8,7 +8,7 @@ import {
Radar, Radar,
Tooltip, Tooltip,
} from "recharts"; } from "recharts";
import type { SkillEntry } from "@planarchy/shared"; import type { SkillEntry } from "@capakraken/shared";
interface Props { interface Props {
skills: SkillEntry[]; skills: SkillEntry[];
+1 -1
View File
@@ -1,7 +1,7 @@
"use client"; "use client";
import { useState } from "react"; import { useState } from "react";
import type { RoleWithResourceCount } from "@planarchy/shared"; import type { RoleWithResourceCount } from "@capakraken/shared";
import { trpc } from "~/lib/trpc/client.js"; import { trpc } from "~/lib/trpc/client.js";
import { AnimatedModal } from "~/components/ui/AnimatedModal.js"; import { AnimatedModal } from "~/components/ui/AnimatedModal.js";
import { InfoTooltip } from "~/components/ui/InfoTooltip.js"; import { InfoTooltip } from "~/components/ui/InfoTooltip.js";
@@ -1,7 +1,7 @@
"use client"; "use client";
import { useState } from "react"; import { useState } from "react";
import type { RoleWithResourceCount } from "@planarchy/shared"; import type { RoleWithResourceCount } from "@capakraken/shared";
import { trpc } from "~/lib/trpc/client.js"; import { trpc } from "~/lib/trpc/client.js";
import { RoleModal } from "./RoleModal.js"; import { RoleModal } from "./RoleModal.js";
import { FilterChips } from "~/components/ui/FilterChips.js"; import { FilterChips } from "~/components/ui/FilterChips.js";
@@ -3,12 +3,12 @@
import { useState, useCallback } from "react"; import { useState, useCallback } from "react";
import { trpc } from "~/lib/trpc/client.js"; import { trpc } from "~/lib/trpc/client.js";
import { useInvalidatePlanningViews } from "~/hooks/useInvalidatePlanningViews.js"; import { useInvalidatePlanningViews } from "~/hooks/useInvalidatePlanningViews.js";
import { AllocationStatus } from "@planarchy/shared"; import { AllocationStatus } from "@capakraken/shared";
import { DateInput } from "~/components/ui/DateInput.js"; import { DateInput } from "~/components/ui/DateInput.js";
import { SkillTagInput } from "~/components/ui/SkillTagInput.js"; import { SkillTagInput } from "~/components/ui/SkillTagInput.js";
import { InfoTooltip } from "~/components/ui/InfoTooltip.js"; import { InfoTooltip } from "~/components/ui/InfoTooltip.js";
import { SuccessToast } from "~/components/ui/SuccessToast.js"; import { SuccessToast } from "~/components/ui/SuccessToast.js";
import { Button } from "@planarchy/ui"; import { Button } from "@capakraken/ui";
interface SearchCriteria { interface SearchCriteria {
startDate: string; startDate: string;
@@ -2,7 +2,7 @@
import { clsx } from "clsx"; import { clsx } from "clsx";
import { useEffect, useRef, useState } from "react"; import { useEffect, useRef, useState } from "react";
import type { AllocationLike, AllocationReadModel, Assignment } from "@planarchy/shared"; import type { AllocationLike, AllocationReadModel, Assignment } from "@capakraken/shared";
import { trpc } from "~/lib/trpc/client.js"; import { trpc } from "~/lib/trpc/client.js";
import { useInvalidateTimeline } from "~/hooks/useInvalidatePlanningViews.js"; import { useInvalidateTimeline } from "~/hooks/useInvalidatePlanningViews.js";
import { getPlanningEntryMutationId } from "~/lib/planningEntryIds.js"; import { getPlanningEntryMutationId } from "~/lib/planningEntryIds.js";
@@ -2,7 +2,7 @@
import { clsx } from "clsx"; import { clsx } from "clsx";
import { useEffect, useRef, useState } from "react"; import { useEffect, useRef, useState } from "react";
import { AllocationStatus } from "@planarchy/shared"; import { AllocationStatus } from "@capakraken/shared";
import { trpc } from "~/lib/trpc/client.js"; import { trpc } from "~/lib/trpc/client.js";
import { useInvalidateTimeline } from "~/hooks/useInvalidatePlanningViews.js"; import { useInvalidateTimeline } from "~/hooks/useInvalidatePlanningViews.js";
@@ -2,7 +2,7 @@
import { clsx } from "clsx"; import { clsx } from "clsx";
import { useEffect, useRef, useState } from "react"; import { useEffect, useRef, useState } from "react";
import { AllocationStatus } from "@planarchy/shared"; import { AllocationStatus } from "@capakraken/shared";
import { trpc } from "~/lib/trpc/client.js"; import { trpc } from "~/lib/trpc/client.js";
import { useInvalidateTimeline } from "~/hooks/useInvalidatePlanningViews.js"; import { useInvalidateTimeline } from "~/hooks/useInvalidatePlanningViews.js";
import { DateInput } from "~/components/ui/DateInput.js"; import { DateInput } from "~/components/ui/DateInput.js";
@@ -2,7 +2,7 @@
import { clsx } from "clsx"; import { clsx } from "clsx";
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import { AllocationStatus, type StaffingRequirement } from "@planarchy/shared"; import { AllocationStatus, type StaffingRequirement } from "@capakraken/shared";
import { trpc } from "~/lib/trpc/client.js"; import { trpc } from "~/lib/trpc/client.js";
import { useInvalidateTimeline } from "~/hooks/useInvalidatePlanningViews.js"; import { useInvalidateTimeline } from "~/hooks/useInvalidatePlanningViews.js";
import { getPlanningEntryMutationId } from "~/lib/planningEntryIds.js"; import { getPlanningEntryMutationId } from "~/lib/planningEntryIds.js";
@@ -3,7 +3,7 @@
import { useEffect, useRef, useState } from "react"; import { useEffect, useRef, useState } from "react";
import { trpc } from "~/lib/trpc/client.js"; import { trpc } from "~/lib/trpc/client.js";
import { formatCents } from "~/lib/format.js"; import { formatCents } from "~/lib/format.js";
import type { SkillEntry } from "@planarchy/shared"; import type { SkillEntry } from "@capakraken/shared";
interface ResourceHoverCardProps { interface ResourceHoverCardProps {
resourceId: string; resourceId: string;
@@ -6,7 +6,7 @@ import {
type AllocationReadModel, type AllocationReadModel,
type Assignment, type Assignment,
type DemandRequirement, type DemandRequirement,
} from "@planarchy/shared"; } from "@capakraken/shared";
import { createContext, useContext, useEffect, useMemo, useRef, useState, type ReactNode } from "react"; import { createContext, useContext, useEffect, useMemo, useRef, useState, type ReactNode } from "react";
import { useSearchParams } from "next/navigation"; import { useSearchParams } from "next/navigation";
import { useTimelineSSE } from "~/hooks/useTimelineSSE.js"; import { useTimelineSSE } from "~/hooks/useTimelineSSE.js";
@@ -1,7 +1,7 @@
"use client"; "use client";
import { useState, useRef, useEffect, useCallback } from "react"; import { useState, useRef, useEffect, useCallback } from "react";
import type { ColumnDef } from "@planarchy/shared"; import type { ColumnDef } from "@capakraken/shared";
interface ColumnTogglePanelProps { interface ColumnTogglePanelProps {
allColumns: ColumnDef[]; allColumns: ColumnDef[];
@@ -1,7 +1,7 @@
"use client"; "use client";
import { FieldType } from "@planarchy/shared"; import { FieldType } from "@capakraken/shared";
import type { BlueprintFieldDefinition } from "@planarchy/shared"; import type { BlueprintFieldDefinition } from "@capakraken/shared";
import type { CustomFieldFilter } from "~/hooks/useFilters.js"; import type { CustomFieldFilter } from "~/hooks/useFilters.js";
interface Props { interface Props {
@@ -2,7 +2,7 @@
import { useCallback } from "react"; import { useCallback } from "react";
import { trpc } from "~/lib/trpc/client.js"; import { trpc } from "~/lib/trpc/client.js";
import type { ProjectStatus } from "@planarchy/shared"; import type { ProjectStatus } from "@capakraken/shared";
import { EntityCombobox } from "./EntityCombobox.js"; import { EntityCombobox } from "./EntityCombobox.js";
type ProjectItem = { id: string; shortCode: string; name: string }; type ProjectItem = { id: string; shortCode: string; name: string };
@@ -1,7 +1,7 @@
"use client"; "use client";
import { useState } from "react"; import { useState } from "react";
import { VacationStatus, VacationType } from "@planarchy/shared"; import { VacationStatus, VacationType } from "@capakraken/shared";
import { trpc } from "~/lib/trpc/client.js"; import { trpc } from "~/lib/trpc/client.js";
import { VacationModal } from "./VacationModal.js"; import { VacationModal } from "./VacationModal.js";
import { InfoTooltip } from "~/components/ui/InfoTooltip.js"; import { InfoTooltip } from "~/components/ui/InfoTooltip.js";
@@ -1,7 +1,7 @@
"use client"; "use client";
import { useState } from "react"; import { useState } from "react";
import { GERMAN_FEDERAL_STATES } from "@planarchy/shared"; import { GERMAN_FEDERAL_STATES } from "@capakraken/shared";
import { trpc } from "~/lib/trpc/client.js"; import { trpc } from "~/lib/trpc/client.js";
export function PublicHolidayBatch() { export function PublicHolidayBatch() {
@@ -1,7 +1,7 @@
"use client"; "use client";
import { useState } from "react"; import { useState } from "react";
import { VacationStatus } from "@planarchy/shared"; import { VacationStatus } from "@capakraken/shared";
import { trpc } from "~/lib/trpc/client.js"; import { trpc } from "~/lib/trpc/client.js";
import { InfoTooltip } from "~/components/ui/InfoTooltip.js"; import { InfoTooltip } from "~/components/ui/InfoTooltip.js";
import { VACATION_CALENDAR_COLORS } from "~/lib/status-styles.js"; import { VACATION_CALENDAR_COLORS } from "~/lib/status-styles.js";
@@ -1,7 +1,7 @@
"use client"; "use client";
import { useState } from "react"; import { useState } from "react";
import { VacationStatus, VacationType } from "@planarchy/shared"; import { VacationStatus, VacationType } from "@capakraken/shared";
import { VACATION_CALENDAR_COLORS } from "~/lib/status-styles.js"; import { VACATION_CALENDAR_COLORS } from "~/lib/status-styles.js";
interface VacationEntry { interface VacationEntry {
@@ -1,7 +1,7 @@
"use client"; "use client";
import { useState, useCallback } from "react"; import { useState, useCallback } from "react";
import { VacationStatus, VacationType } from "@planarchy/shared"; import { VacationStatus, VacationType } from "@capakraken/shared";
import { trpc } from "~/lib/trpc/client.js"; import { trpc } from "~/lib/trpc/client.js";
import { VacationModal } from "./VacationModal.js"; import { VacationModal } from "./VacationModal.js";
import { TeamCalendar } from "./TeamCalendar.js"; import { TeamCalendar } from "./TeamCalendar.js";
@@ -2,7 +2,7 @@
import { useRef, useState } from "react"; import { useRef, useState } from "react";
import { useFocusTrap } from "~/hooks/useFocusTrap.js"; import { useFocusTrap } from "~/hooks/useFocusTrap.js";
import { VacationType } from "@planarchy/shared"; import { VacationType } from "@capakraken/shared";
import { trpc } from "~/lib/trpc/client.js"; import { trpc } from "~/lib/trpc/client.js";
import { DateInput } from "~/components/ui/DateInput.js"; import { DateInput } from "~/components/ui/DateInput.js";
import { useDebounce } from "~/hooks/useDebounce.js"; import { useDebounce } from "~/hooks/useDebounce.js";
+2 -2
View File
@@ -22,8 +22,8 @@ export interface AppPreferences {
blinkOverbookedDays: boolean; blinkOverbookedDays: boolean;
} }
const STORAGE_KEY = "planarchy_prefs"; const STORAGE_KEY = "capakraken_prefs";
const CHANGE_EVENT = "planarchy-prefs-changed"; const CHANGE_EVENT = "capakraken-prefs-changed";
const DEFAULT: AppPreferences = { const DEFAULT: AppPreferences = {
hideCompletedProjects: true, hideCompletedProjects: true,
+1 -1
View File
@@ -1,7 +1,7 @@
"use client"; "use client";
import { useMemo, useCallback, useState } from "react"; import { useMemo, useCallback, useState } from "react";
import type { ColumnDef, ColumnPreferences, ViewKey } from "@planarchy/shared"; import type { ColumnDef, ColumnPreferences, ViewKey } from "@capakraken/shared";
import { trpc } from "~/lib/trpc/client.js"; import { trpc } from "~/lib/trpc/client.js";
// Simple localStorage helper (no external lib needed) // Simple localStorage helper (no external lib needed)
+3 -3
View File
@@ -4,16 +4,16 @@ import { useState, useCallback, useEffect, useRef } from "react";
import { import {
type DashboardLayoutConfig, type DashboardLayoutConfig,
type DashboardWidgetType, type DashboardWidgetType,
} from "@planarchy/shared/types"; } from "@capakraken/shared/types";
import { import {
createDashboardWidget, createDashboardWidget,
createDefaultDashboardLayout, createDefaultDashboardLayout,
getNextDashboardWidgetY, getNextDashboardWidgetY,
normalizeDashboardLayout, normalizeDashboardLayout,
} from "@planarchy/shared/schemas"; } from "@capakraken/shared/schemas";
import { trpc } from "~/lib/trpc/client.js"; import { trpc } from "~/lib/trpc/client.js";
const STORAGE_KEY = "planarchy_dashboard_v1"; const STORAGE_KEY = "capakraken_dashboard_v1";
function generateWidgetId() { function generateWidgetId() {
return `widget-${Date.now()}-${Math.random().toString(36).slice(2, 7)}`; return `widget-${Date.now()}-${Math.random().toString(36).slice(2, 7)}`;

Some files were not shown because too many files have changed in this diff Show More