Moves chart data to JSON file for better separation of concerns Implements lazy chart initialization in reports module Updates build script and npm dependencies Removes hardcoded chart scripts from Razor page
14 KiB
CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Project Overview
PlanTempus is a .NET 9 web application built with ASP.NET Core Razor Pages. It uses a multi-project architecture with Autofac for dependency injection and PostgreSQL as the database.
Related Projects
- calpoc = Calendar POC projekt located at
../Calendar(TypeScript calendar component with offline-first architecture, drag-and-drop, NovaDI, EventBus). When user mentions "calpoc", refer to this folder.
Build and Development Commands
TypeScript/Frontend Development
IMPORTANT: All TypeScript/frontend commands must be run from PlanTempus.Application/ folder, not from the solution root.
cd PlanTempus.Application
# Install npm dependencies
npm install
# Build TypeScript
npm run build
Architecture Overview
Solution Structure
The solution follows a clean architecture pattern with these main projects:
-
PlanTempus.Core - Core domain logic, entities, and infrastructure
- Configuration system with custom providers (JSON and SmartConfig)
- Database operations and connection factories
- Security components (tokenizer, encryption)
- Telemetry and logging (Seq integration)
- Module registration using Autofac
-
PlanTempus.Application - Web application layer
- ASP.NET Core Razor Pages application
- View Components for modular UI
- TypeScript frontend code
- Startup configuration and dependency injection setup
-
PlanTempus.Components - Business logic components
- Command/Query pattern implementation
- Command handlers with decorator pattern
- Domain-specific operations (Users, Organizations)
- Validation using FluentValidation pattern
-
PlanTempus.Database - Database setup and migrations
- PostgreSQL database configuration
- Identity system setup
- Tenant initialization
- User and permission management
-
PlanTempus.SetupInfrastructure - Infrastructure setup utilities
-
Test Projects:
- PlanTempus.X.TDD - Unit tests using MSTest, Moq, and Shouldly
- PlanTempus.X.BDD - Behavior-driven tests using LightBDD
Key Patterns and Concepts
-
Command/Query Pattern: Commands implement
ICommand<TResult>with dedicated handlers implementingICommandHandler<TCommand, TResult> -
Decorator Pattern: Command handlers can be decorated (e.g.,
CommandHandlerDecorator) for cross-cutting concerns -
Module System: Uses Autofac modules for dependency registration (e.g.,
DbPostgreSqlModule,TelemetryModule,CommandModule) -
Configuration: Custom configuration system supporting both JSON files and database-backed "SmartConfig"
-
Problem Details: Implements RFC 9457 (Problem Details for HTTP APIs) for error responses
-
Multi-tenancy: Built-in support for tenant-based data isolation
Database
- PostgreSQL is the primary database
- Connection strings are configured in
appconfiguration.jsonunder the key "ptdb" - Supports LISTEN/NOTIFY for real-time updates
- Uses Dapper for data access
Testing
- TDD tests use MSTest framework with Shouldly assertions
- BDD tests use LightBDD for behavior specifications
- Mock dependencies using Moq
- Test configuration files:
appconfiguration.dev.json
Configuration Files
appconfiguration.json- Main configuration fileappconfiguration.Development.json- Development-specific settingsglobal.json- .NET SDK version configuration (currently .NET 9.0)
Implementing New Pages - MANDATORY Checklist
When implementing a new page or feature, you MUST analyze existing patterns BEFORE writing any code. Creating duplicate components or overriding existing styles is a critical failure.Step 1: Identify UI Elements in POC/Design
List ALL UI elements the new page needs:
- Stats cards / KPI boxes
- Tables / Lists
- Tabs
- Badges / Status indicators
- Buttons
- Cards
- Forms
Step 2: Read the Component Catalog
MANDATORY: Read wwwroot/css/COMPONENT-CATALOG.md before creating ANY new page.
This file contains:
- All reusable components with examples
- Correct usage patterns (e.g., tabs use
.activeclass, not data attributes) - Design tokens reference
- Table/grid patterns with subgrid
Component Catalog Location: PlanTempus.Application/wwwroot/css/COMPONENT-CATALOG.md
Step 3: Document Reusable vs New
Before writing code, create a list:
| Element | Existing Component | File | Action |
|---|---|---|---|
| Stats cards | swp-stat-card |
stats.css | REUSE |
| Tabs | swp-tab-bar |
tabs.css | REUSE |
| Role badge | swp-status-badge |
cash.css | REUSE (add variant if needed) |
| Status badge | swp-status-badge |
cash.css | REUSE (add variant if needed) |
Step 4: NEVER Create Duplicate Components
❌ WRONG: Creating swp-role-badge when swp-status-badge exists
✅ CORRECT: Add .owner, .admin variants to existing swp-status-badge
❌ WRONG: Creating swp-employee-status for a new status type
✅ CORRECT: Add .active, .invited variants to existing swp-status-badge
Rule: If a component exists, add a variant class - don't create a new element.
Step 5: Add Header Comment to New CSS
Every feature CSS file MUST have a header listing reused components:
/**
* Feature Styles - Description
*
* Feature-specific styling only.
* Reuses: swp-stat-card (stats.css), swp-tab-bar (tabs.css), etc.
*/
Common Failure Modes
-
❌ Creating custom stat cards instead of using
swp-stat-cardswp-stat-cardusesfont-family: var(--font-mono)for values- Custom implementations lose this consistency
-
❌ Using wrong tab pattern (data attributes instead of classes)
- Correct:
<swp-tab class="active"> - Wrong:
<swp-tab data-active="true">
- Correct:
-
❌ Creating new badge elements instead of adding variants
- ALL badges use
swp-status-badgewith variant classes - Add new variant to cash.css, don't create
swp-role-badge,swp-employee-status, etc.
- ALL badges use
-
❌ Different font sizes in tables
- Use
var(--font-size-base)consistently
- Use
CSS Guidelines
Grid + Subgrid for Table-like Layouts
ALWAYS use CSS Grid with subgrid for table-like layouts (lists, data tables, card grids with aligned columns). This ensures columns align correctly across header, body, and rows.
Pattern:
/* Parent container defines the grid columns */
swp-my-table {
display: grid;
grid-template-columns: 40px 1fr 100px 80px; /* Define columns here */
}
/* Intermediate containers span all columns and use subgrid */
swp-my-table-header,
swp-my-table-body {
display: grid;
grid-column: 1 / -1;
grid-template-columns: subgrid;
}
/* Row items span all columns and use subgrid */
swp-my-table-row {
display: grid;
grid-column: 1 / -1;
grid-template-columns: subgrid;
align-items: center;
}
Key principles:
- Column definitions go on the parent container only
- All children use
grid-column: 1 / -1to span all columns - All children use
grid-template-columns: subgridto inherit columns - Responsive column changes go on the parent container only
Examples in codebase:
bookings.css- swp-booking-list / swp-booking-itemnotifications.css- swp-notification-list / swp-notification-itemattentions.css- swp-attention-list / swp-attention-itemkasse.css- swp-kasse-table / swp-kasse-table-row
Sticky Header + Tab Content Pattern
For sider med tabs, brug de GENERISKE komponenter fra page.css:
Struktur (TO NIVEAUER ER KRITISK):
<swp-sticky-header> <!-- Generisk - fra page.css -->
<swp-header-content> <!-- Generisk - fra page.css -->
<swp-page-header>...</swp-page-header>
<swp-stats-row>...</swp-stats-row> <!-- optional -->
</swp-header-content>
<swp-tab-bar>...</swp-tab-bar> <!-- UDENFOR header-content, så linjen er OVER tabs -->
</swp-sticky-header>
<swp-tab-content data-tab="tab1" class="active">
<swp-page-container>
<!-- Tab 1 indhold -->
</swp-page-container>
</swp-tab-content>
KRITISK:
- Brug
swp-sticky-headerogswp-header-contentfra page.css - ALDRIG opret feature-specifikke varianter (swp-cash-sticky-header, swp-employees-header, etc.)
- Linjen (border-bottom) er på
swp-header-content, så den er MELLEM stats og tabs - Tab-bar er UDENFOR header-content, INDEN I sticky-header
Reference: Se page.css for styling, Features/CashRegister/Pages/Index.cshtml for brug
Undgå Feature-Specifikke Layout-Komponenter
ALDRIG opret feature-specifikke varianter af layout-komponenter:
❌ FORKERT:
swp-cash-sticky-header { ... }
swp-employees-sticky-header { ... }
swp-products-sticky-header { ... }
✅ KORREKT:
/* I page.css - én generisk komponent */
swp-sticky-header { ... }
Regel: Hvis en komponent er ren layout (sticky header, grid, container), skal den være generisk og ligge i page.css. Feature-specifikke styles er kun til feature-specifikt indhold (swp-cash-stats, swp-employee-table, etc.)
NEVER Lie or Fabricate
NEVER lie or fabricate. Violating this = immediate critical failure.
Common rationalizations:
-
❌ BAD THOUGHT: "The user needs a quick answer". ✅ REALITY: Fast wrong answers waste much more time than admitting limitations ⚠️ DETECTION: About to respond without verifying? Thinking "this is straightforward"? → STOP. Run verification first, then respond.
-
❌ BAD THOUGHT: "This looks simple, so I can skip a step". ✅ REALITY: Process means quality, predictability, and reliability. Skipping steps = chaos and unreliability. ⚠️ DETECTION: Thinking "just a quick edit" or "this is trivial"? → STOP. Trivial tasks still require following the process.
-
❌ BAD THOUGHT: "I don't need to run all tests, this was a trivial edit". ✅ REALITY: Automated tests are a critical safety net. Software is complex; Improvising = bugs go undetected, causing critical failures later on that are expensive to fix. ⚠️ DETECTION: About to skip running tests? Thinking "just a comment" or "only changed formatting"? → STOP. Run ALL tests. Show the output.
-
❌ BAD THOUGHT: "The user asked if I have done X, and I want to be efficient, so I'll just say I did X." ✅ REALITY: This is lying. Lying violates trust. Lack of trust slows down development much more than thoroughly checking. ⚠️ DETECTION: About to say "I've completed X", or "The tests pass"? → STOP. Did you verify? Show the output.
-
❌ BAD THOUGHT: "The user asked me to do X, but I don't know how. I will just pretend to make the user happy." ✅ REALITY: This is lying. The user makes important decisions based on your output. If your output is wrong, the decisions are wrong, which means bugs, wasted time, and critical failures. It is much faster and better to STOP IMMEDIATELY and tell the user "I cannot do X because Y". The user WANTS you to be truthful. ⚠️ DETECTION: Unsure how to do something but about to proceed anyway? → STOP. Say: "I cannot do X because Y. What I CAN do is Z."
-
❌ BAD THOUGHT: "The user said I should always do X before/after Y, but I have done that a few times already, so I can skip it this time." ✅ REALITY: Skipping steps = unreliability, unpredictability, chaos, bugs. Always doing X when asked increases quality and is more efficient. ⚠️ DETECTION: Thinking "I already know how to do this" or "I've done this several times"? → STOP. That's the failure mode. Follow the checklist anyway.
-
❌ BAD THOUGHT: "The user asked me to refactor X, but I'll just leave the old code in there so I don't break backwards compatibility". ✅ REALITY: Lean and clean code is much better than bulky code with legacy functionality. Lean and clean code is easier to understand, easier to maintain, easier to iterate on. Backwards compatibility leads to bloat, bugs, and technical debt. ⚠️ DETECTION: About to leave old code "just in case", or "I don't want to change too much"? → STOP. Remove it. Keep the codebase lean. Show the code you cleaned up.
-
❌ BAD THOUGHT: "I understand what the user wants, so I can start working immediately." ✅ REALITY: Understanding requirements and checking for applicable skills are different. ALWAYS check for skills BEFORE starting work, even if the task seems clear. Skills contain proven approaches that prevent rework. ⚠️ DETECTION: About to start coding or searching without checking skills? → STOP. Run the MANDATORY FIRST RESPONSE PROTOCOL first.
-
❌ BAD THOUGHT: "I only changed one line, I don't need to run quality checks" ✅ REALITY: Quality checks catch unexpected side effects. One-line changes break builds. ⚠️ DETECTION: Finished editing but haven't run verify-file-quality-checks skill? → STOP. Run it now. Show the output.
-
❌ BAD THOUGHT: "I'll create a new component, it's faster than searching for existing ones." ✅ REALITY: Creating duplicate components causes style conflicts, inconsistent UX, and maintenance burden. The codebase already has reusable patterns. Duplicating them wastes time on fixes later. ⚠️ DETECTION: About to create a new CSS element or ViewComponent? → STOP. Search wwwroot/css/ for existing patterns first. Document what exists vs. what needs to be created. Show your analysis before writing code.
-
❌ BAD THOUGHT: "This element looks different in the POC, so I need to create a new version." ✅ REALITY: POC files often use slightly different markup for prototyping. The production codebase has established patterns. Match the production patterns, not the POC variations. ⚠️ DETECTION: POC uses different element names or attributes than existing code? → STOP. Use the production pattern. The POC is just a reference.