Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
c2112dd
Fixes bug in certain table defs
jeffrade Feb 1, 2026
9dfe374
sql files
jeffrade Feb 1, 2026
f5b882d
Fixes plural table rename - take db table names as-is
jeffrade Feb 1, 2026
aa4361f
WIP to fix make seed and get UI to show data
jeffrade Feb 1, 2026
d4f0431
[NO-CHEERY-PICK] sql and settings files
jeffrade Feb 1, 2026
62d412a
Finished to fix make seed and get UI to show data
jeffrade Feb 2, 2026
9e1fae4
[NO-CHERRY-PICK] temp schema fix and fix seed data
jeffrade Feb 2, 2026
18fae47
Final fix for two DBs, re-templify, UI fixes
jeffrade Feb 2, 2026
23122fb
Dynamically load View SELECTs for UI
jeffrade Feb 2, 2026
9c703f0
Updates docs and fix appsettings.json parsers to force look for overr…
jeffrade Feb 2, 2026
119c344
acuity import mvp
jeffrade Feb 2, 2026
a0bde57
ICT implemented
jeffrade Feb 2, 2026
df39c94
PrePick implemented
jeffrade Feb 2, 2026
7e4fa72
init Allocation implementation
jeffrade Feb 2, 2026
d8cebef
final fixes for Allocation implementation
jeffrade Feb 2, 2026
d3eff77
fix url /app
jeffrade Feb 2, 2026
280c0cd
fixes ict app details url
jeffrade Feb 2, 2026
7204fa4
DMS implemented
jeffrade Feb 2, 2026
efecedb
Docs updated showing MVP reached
jeffrade Feb 2, 2026
ff0fe7a
CSS improvements
jeffrade Feb 2, 2026
052d315
other LLM doc updates
jeffrade Feb 2, 2026
4f1ff3f
nginx reverse proxy and self-hosting
jeffrade Feb 3, 2026
9aa3247
[NO-CHERRY-PICK] client branding
jeffrade Feb 3, 2026
26744f1
[NO-CHERRY-PICK] GAISystem DB blocking
jeffrade Feb 3, 2026
e9bc67e
Update seed data to load for entire month of Feb 2026
jeffrade Feb 4, 2026
2d464c2
Update seed data to load for entire month of Feb 2026
jeffrade Feb 4, 2026
57dbea4
Fix and cleanup Makefile
jeffrade Feb 20, 2026
3fd68bb
Makefile fixes
jeffrade Feb 20, 2026
1877043
Adds full docker compose impl
jeffrade Feb 20, 2026
228586f
Merge branch 'scout' of github.com:devixlabs/DotNetWebApp into scout
jeffrade Feb 20, 2026
2627f77
Remove db container (volume remains persisted)
jeffrade Feb 20, 2026
03fc1f2
Fixes missing restore project files
jeffrade Feb 21, 2026
3b051d7
Remove --no-restore flag that's causing issues with fresh clone
jeffrade Feb 21, 2026
f24c7b7
handle docker containers gracefully
jeffrade Feb 21, 2026
ceddf2c
remove docker caching until stable
jeffrade Feb 21, 2026
db2cf63
Long-term fix for SchemaMapping work-around
jeffrade Feb 21, 2026
1fd2d1c
white-label
jeffrade Mar 17, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions .claude/skills/radzen-blazor/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -353,6 +353,25 @@ Powerful grid with sorting, filtering, paging, editing, selection, grouping.
</RadzenDataGridColumn>
```

**⚠️ TItem="object" Pitfall:**
When using `TItem="object"` for dynamic entity grids, `Property` binding does NOT work (causes blank cells). Use `Template` with reflection instead:
```razor
<RadzenDataGrid Data="@objectData" TItem="object">
<Columns>
<RadzenDataGridColumn TItem="object" Title="Name">
<Template Context="row">@GetPropertyValue(row, "Name")</Template>
</RadzenDataGridColumn>
</Columns>
</RadzenDataGrid>

@code {
object? GetPropertyValue(object? obj, string propertyName) =>
obj?.GetType().GetProperty(propertyName)?.GetValue(obj);
}
```

For dynamic entities with many columns (200+), use **SmartDataGridObject** component which handles reflection and auto-limits visible columns.

See [references/components-quick-ref.md](references/components-quick-ref.md) for complete DataGrid reference.

### RadzenDataList
Expand Down
72 changes: 72 additions & 0 deletions .claude/skills/radzen-blazor/references/best-practices.md
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,76 @@ Template columns disable some optimizations. Use Property when possible:
</RadzenDataGridColumn>
```

### Avoid TItem="object" with Property Binding
**Critical gotcha:** Radzen's `Property` attribute uses compiled expressions that require knowing the type at compile time. When `TItem="object"`, the Property binding fails silently (blank cells):

```razor
@* BAD - Property binding doesn't work with TItem="object" *@
<RadzenDataGrid Data="@objectData" TItem="object">
<Columns>
<RadzenDataGridColumn TItem="object" Property="Name" Title="Name" />
</Columns>
</RadzenDataGrid>

@* GOOD - Use Template with reflection for object-typed data *@
<RadzenDataGrid Data="@objectData" TItem="object">
<Columns>
<RadzenDataGridColumn TItem="object" Title="Name">
<Template Context="row">
@GetPropertyValue(row, "Name")
</Template>
</RadzenDataGridColumn>
</Columns>
</RadzenDataGrid>

@code {
object? GetPropertyValue(object? obj, string propertyName)
{
if (obj == null) return null;
return obj.GetType()
.GetProperty(propertyName, BindingFlags.Public | BindingFlags.Instance)
?.GetValue(obj);
}
}

@* BEST - Use strongly-typed generic when possible *@
<RadzenDataGrid Data="@products" TItem="Product">
<Columns>
<RadzenDataGridColumn TItem="Product" Property="Name" Title="Name" />
</Columns>
</RadzenDataGrid>
```

**When you must use `TItem="object"`** (e.g., dynamic entity grids):
- Use `Template` instead of `Property` for column content
- Access values via reflection in the template
- Note: Sorting/filtering may not work without Property binding

### Limit Visible Columns for Wide Tables
Tables with many columns (50+) can overwhelm browsers and users. Use column limiting:

```razor
@* SmartDataGridObject automatically limits to 15 columns by default *@
<SmartDataGridObject Data="@wideData"
MaxVisibleColumns="20" /> @* Show 20 columns *@

@* Set to 0 to show all columns (not recommended for 100+ columns) *@
<SmartDataGridObject Data="@data"
MaxVisibleColumns="0" />
```

**Column prioritization (automatic):**
1. ID columns (e.g., `item_id`, `Id`) - shown first
2. Code/number columns (e.g., `item_code`, `product_code`)
3. Name/description columns (e.g., `item_name`, `description`)
4. Status/active columns (e.g., `is_active`, `is_enabled`)
5. All other columns alphabetically

**When to override defaults:**
- Use `ColumnOverrides` parameter for full control over which columns appear
- Increase `MaxVisibleColumns` if users need more fields visible
- For reporting/export, consider a separate view with all columns

### Reuse Grid References
Store grid reference for programmatic control:

Expand Down Expand Up @@ -757,6 +827,8 @@ Use Radzen components, avoid raw HTML injection:
- [ ] Add `<RadzenComponents />` in MainLayout
- [ ] Use interactive render mode for components with events
- [ ] Use server-side loading for large DataGrids
- [ ] **Avoid `TItem="object"` with Property binding** - use Template with reflection instead
- [ ] **Limit visible columns for wide tables** (50+ columns) - use MaxVisibleColumns
- [ ] Validate forms before submission
- [ ] Handle dialog results (check for null)
- [ ] Use appropriate notification durations and severities
Expand Down
52 changes: 52 additions & 0 deletions .claude/skills/radzen-blazor/references/components-quick-ref.md
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,58 @@

---

## SmartDataGridObject (Project Component)

Custom component for dynamic entity grids with `TItem="object"`. Handles reflection-based property access and auto-limits columns for wide tables (200+ columns).

### Key Parameters
- `Data` - IEnumerable<object> data source
- `MaxVisibleColumns` - Max columns to display (default: 15, set to 0 for unlimited)
- `ColumnOverrides` - Custom column configuration (IEnumerable<ColumnConfig>)
- `AllowFiltering` - Enable filtering (default: true)
- `AllowSorting` - Enable sorting (default: true)
- `AllowPaging` - Enable pagination (default: true)
- `AllowInlineEdit` - Enable inline editing (default: false)
- `AllowEdit` - Show edit button in actions column (default: false)
- `AllowDelete` - Show delete button in actions column (default: false)
- `ShowActionColumn` - Show actions column (default: false)
- `OnRowUpdate`, `OnRowCreate`, `OnRowDelete`, `OnRowEdit` - Event callbacks

### Usage
```razor
@* Basic usage - auto-discovers columns, limits to 15 *@
<SmartDataGridObject Data="@entityData" />

@* Show more columns *@
<SmartDataGridObject Data="@entityData"
MaxVisibleColumns="25" />

@* Show all columns (use with caution for wide tables) *@
<SmartDataGridObject Data="@entityData"
MaxVisibleColumns="0" />

@* With editing *@
<SmartDataGridObject Data="@entityData"
AllowInlineEdit="true"
OnRowUpdate="@HandleUpdate" />
```

### Column Prioritization (Automatic)
When limiting columns, SmartDataGridObject prioritizes:
1. ID columns (`_id`, `Id`) - shown first
2. Code/number columns (`code`, `codenum`, `number`)
3. Name/description columns (`name`, `descrip`, `title`)
4. Status columns (`active`, `status`, `enabled`)
5. All other columns alphabetically

### Footer Display
Shows row count and hidden column info:
```
Showing 3 records (15 of 265 columns shown)
```

---

## RadzenStack

### Parameters
Expand Down
26 changes: 26 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# Developer-local config files (contain localhost connection strings - must not override Docker env vars)
appsettings.Local.json
appsettings.*.Local.json
.env.local
.envrc
.env

# Secrets
secrets.json
*.pfx
*.key

# Build artifacts (Docker build stage handles these itself)
**/bin/
**/obj/

# Test projects (not needed in production image)
tests/

# Documentation
*.md
DOCKER_SETUP_CONTEXT.md

# Git
.git/
.gitignore
9 changes: 9 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# SQL Server password for Docker Compose
# Change this to a secure password!
SA_PASSWORD=YourStrongPassword123!

# Optional: Override ASPNETCORE_ENVIRONMENT
# ASPNETCORE_ENVIRONMENT=Production

# Optional: Override app ports (default: 7012 for HTTPS, 5210 for HTTP)
# Leave blank to use defaults
8 changes: 7 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -463,8 +463,9 @@ Thumbs.db
ehthumbs.db
ehthumbs_vista.db

# Dump file
# Dump type files
*.stackdump
*.patch

# Folder config file
[Dd]esktop.ini
Expand All @@ -490,8 +491,13 @@ $RECYCLE.BIN/

# Project and App Specific
.env.local
appsettings.Local.json
tmp/
specs/
dotnetwebapp.conf
dotnetwebapp.crt
dotnetwebapp.key
dev.log
# Generated YAML files (regenerated from pipeline)
app.yaml
data.yaml
Expand Down
64 changes: 0 additions & 64 deletions AGENTS.md

This file was deleted.

49 changes: 47 additions & 2 deletions ARCHITECTURE_SUMMARY.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# DotNetWebApp Architecture Summary

**Last Updated:** 2026-01-27
**Status:** Architecture finalized; Phase 1 & Phase 2B complete
**Last Updated:** 2026-02-02
**Status:** Architecture finalized; Phase 1, Phase 2B, Phase 3+4, and WAMS Phase 1 MVP complete

---

Expand Down Expand Up @@ -176,6 +176,51 @@

**Note:** Phase 3 (read-only patterns) and Phase 4 (editable patterns) are combined into a single PR.

### ✅ WAMS Phase 1 COMPLETED - Web App Management System MVP (2026-02-02)

**Goal:** Implement core scheduling system following proven patterns from InventoryPicking and Allocation

**Status:** ✅ COMPLETED - Full MVP with 39-column grid, status workflow, AppID grouping, and soft delete

**Key Features Delivered:**
- ✅ 39-column RadzenDataGrid with order type classification (SO, PO)
- ✅ Status workflow state machine (NA → CheckIn → Loading → Unloading → Shipped → Received)
- ✅ AppID batch operations (orders with same AppID move together)
- ✅ Soft delete pattern (type + 10, reversible with undelete)
- ✅ Personnel assignment (forklift operators filtered by warehouse)
- ✅ Color coding by order type and status
- ✅ Multi-warehouse support (Chicago=3, NYC=92)
- ✅ Comprehensive seed data (15 test orders covering all scenarios)

**Architecture:**
- Single service pattern following InventoryPicking (WAMSService + validators)
- Hybrid EF Core (writes) + Dapper (reads) with SecondaryDbContext (WEBAPPMisc database)
- Keyed dependency injection: `[FromKeyedServices("Secondary")]` IDapperQueryService
- Static classifier (WAMSOrderTypeClassifier) + color service (WAMSColorCodingService)
- Two validators: StatusTransitionValidator (state machine) + DeleteValidator (security)

**Files Created (13 new files):**
1. `Services/WAMS/Models/WAMSModels.cs` - All models, enums, requests, responses
2. `Services/WAMS/WAMSOrderTypeClassifier.cs` - Static classification helper
3. `Services/WAMS/Validators/StatusTransitionValidator.cs` - State machine validation
4. `Services/WAMS/Validators/DeleteValidator.cs` - Delete authorization
5. `Services/WAMS/WAMSColorCodingService.cs` - Type and status colors
6. `Services/WAMS/IWAMSService.cs` - Service interface (10 methods)
7. `Services/WAMS/WAMSService.cs` - Service implementation
8. `Controllers/WAMSController.cs` - REST API (10 endpoints)
9. `Components/Pages/WAMS/Index.razor` - Main UI with 39-column grid
10-13. Test files (4 files with 105 unit tests)

**Testing:**
- ✅ **105 WAMS unit tests** (22 validator + 25 delete + 43 color + 15 service)
- ✅ **582 total tests passing** (up from 467 = +115 new tests)
- ✅ Clean build (0 warnings, 0 errors)
- ✅ API integration verified with curl tests
- ✅ UI displaying data correctly

**Deferred to Production:**
- BOL generation, Excel export, email notifications, auto-refresh timers, daily reset

### 🔄 Future: Validation Pipeline (1 day) - As Needed

**Goal:** Robust tenant isolation for multiple schemas
Expand Down
19 changes: 14 additions & 5 deletions AppsYamlGenerator/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,21 +39,30 @@

// Read appsettings.json and extract Applications section
Console.WriteLine($"Reading appsettings.json: {appSettingsAbsPath}");
var config = new ConfigurationBuilder()
.AddJsonFile(appSettingsAbsPath)
.Build();
var configBuilder = new ConfigurationBuilder()
.AddJsonFile(appSettingsAbsPath);

// Also read appsettings.Local.json if it exists (for local overrides)
var localSettingsPath = Path.Combine(Path.GetDirectoryName(appSettingsAbsPath)!, "appsettings.Local.json");
if (File.Exists(localSettingsPath))
{
Console.WriteLine($"Found appsettings.Local.json, merging Applications...");
configBuilder.AddJsonFile(localSettingsPath);
}

var config = configBuilder.Build();

var applicationsSection = config.GetSection("Applications");
var applications = new List<ApplicationInfo>();

if (applicationsSection.Exists())
{
applicationsSection.Bind(applications);
Console.WriteLine($"Found {applications.Count} application(s) in appsettings.json");
Console.WriteLine($"Found {applications.Count} application(s) in configuration");
}
else
{
Console.WriteLine("Warning: No Applications section found in appsettings.json");
Console.WriteLine("Warning: No Applications section found in configuration");
}

// Read data.yaml and extract DataModel section
Expand Down
Loading