Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
46b7786
Replace legacy Angular UI with root Svelte application
ejsmith Oct 1, 2026
bb1fd25
Preserve whitespace-tolerant OAuth client configuration
ejsmith Oct 1, 2026
dd37e1c
Honor configured API origins and simplify Slack actions
ejsmith Oct 1, 2026
3d03187
Mock public environment in navigation command tests
ejsmith Oct 1, 2026
e840375
Preserve legacy link history and test preview commits
ejsmith Oct 1, 2026
f7bbccd
Allow configured API origins in application CSP
ejsmith Oct 1, 2026
6e8b4cf
Correct the documented Aspire app endpoint
ejsmith Oct 1, 2026
db6d2bc
Align email previews with current stack actions
ejsmith Oct 1, 2026
3c2097e
Isolate synthetic notification timing in browser tests
ejsmith Oct 1, 2026
b585b3f
Remove remaining UI transition controls and update contributor guidance
ejsmith Oct 1, 2026
b5f6c52
Use configured hosts for service recovery and OAuth navigation
ejsmith Oct 1, 2026
b23b8d7
Align development and preview links with the Svelte application
ejsmith Oct 1, 2026
d29a753
Merge main after CI test improvements
ejsmith Oct 1, 2026
6aa4cb6
Isolate navigation cache checks from saved-view broadcasts
ejsmith Oct 1, 2026
f7eba6a
Wait for saved-view navigation before cache checks
ejsmith Oct 1, 2026
fefe0a5
Preserve configured HTTPS enforcement in Svelte
ejsmith Oct 1, 2026
92eda33
Control stack notification timing in browser stress test
ejsmith Oct 1, 2026
7c73f90
Await real refresh responses and isolate telemetry in browser checks
ejsmith Oct 1, 2026
1cbfa2d
Separate the public OAuth API origin from the UI redirect
ejsmith Oct 1, 2026
5b3a0b7
Merge remote-tracking branch 'origin/main' into feature/remove-legacy-ui
ejsmith Oct 2, 2026
14f0a42
Harden frontend startup and preserve legacy navigation
ejsmith Oct 2, 2026
269c5c1
Provide runtime configuration in Intercom component tests
ejsmith Oct 2, 2026
fbaad35
Clean up frontend guidance and move API origin helper
ejsmith Oct 2, 2026
b4860c3
Restore email stack actions with Svelte confirmations
ejsmith Oct 2, 2026
63ffbde
Merge remote-tracking branch 'origin/main' into feature/remove-legacy-ui
ejsmith Oct 3, 2026
9187287
Simplify UI cutover and preserve notification actions
ejsmith Oct 3, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
2 changes: 1 addition & 1 deletion .agents/skills/aspire-diagnostics/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,6 @@ Report the exact action, resource names, trace IDs, repeated-call counts, durati

## Browser and environment boundaries

The AppHost enables `WithBrowserLogs()` for frontend resources. Use its dashboard for browser console/network evidence or screenshots when they explain a UI failure, and correlate browser activity with backend traces where available.
The AppHost enables `WithBrowserLogs()` for the Svelte `App` resource, which serves the application at `/`. Discover that resource's current endpoint. Use its dashboard for browser console/network evidence or screenshots when they explain a UI failure, and correlate browser activity with backend traces where available.

Avoid restarting the whole AppHost as a diagnostic loop. For deployed or external environments, follow the user's explicit scope and the platform's diagnostics; do not assume local Aspire commands or endpoints apply.
8 changes: 4 additions & 4 deletions .agents/skills/dogfood/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,7 @@ name: dogfood
description: >
Systematically dogfood Exceptionless locally. Use when asked to dogfood, QA, exploratory test,
bug hunt, browser-test, or validate frontend/full-stack behavior in this repo. Start from the
AppHost/Aspire local URLs and choose the Svelte or legacy Angular app based on the changed
surface. External Exceptionless URLs require an explicit user-provided URL and confirmation.
AppHost/Aspire local URLs and use the Svelte application. External Exceptionless URLs require an explicit user-provided URL and confirmation.
---

# Dogfood
Expand All @@ -15,9 +14,10 @@ Systematically explore Exceptionless as a local user, find issues, and produce a

Local targets:

The Svelte app at `/` is the only application UI. Exercise primary hash URLs when testing incoming-link compatibility, then verify they resolve to the root routes without losing the session.

- Aspire dashboard: `https://ex.dev.localhost:7101`
- Svelte app: `https://web-ex.dev.localhost:7131/next/`
- Legacy Angular app: `https://angular-ex.dev.localhost:7121`
- Svelte app: `https://web-ex.dev.localhost:7131/`
- API health check: `https://api-ex.dev.localhost:7111/api/v2/about`
- API health fallback for command-line tools with local TLS issues: `http://api-ex.dev.localhost:7110/api/v2/about`

Expand Down
2 changes: 1 addition & 1 deletion .agents/skills/frontend-architecture/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ description: Apply Exceptionless Svelte conventions when adding or restructuring

# Frontend Architecture

Work in `src/Exceptionless.Web/ClientApp` and follow its `AGENTS.md`.
Work in `src/Exceptionless.Web/ClientApp`, the sole application frontend at `/`, and follow its `AGENTS.md`. Generate root routes with `$app/paths`; preserve primary historical hash links through the incoming-link compatibility layer.

## Feature structure

Expand Down
2 changes: 2 additions & 0 deletions .claude/agents/engineer.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ description: Implement scoped Exceptionless changes and verify the requested beh

Follow `AGENTS.md` and the relevant local skill. Establish the requested result and affected compatibility boundaries, then implement the smallest complete change using current repository patterns.

Frontend work targets the Svelte application in `src/Exceptionless.Web/ClientApp` at `/`. Preserve incoming-link and session compatibility.

Work through dependencies in order. Verify the changed behavior, fix regressions caused by the work, and retry when the result identifies a useful correction. Report persistent blockers with evidence instead of repeating the same attempt.

Complete delivery within the user's authorization. Summarize changes, verification, and remaining gaps. Do not require a separate reviewer or QA agent for every edit.
Expand Down
2 changes: 2 additions & 0 deletions .claude/agents/qa.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ maxTurns: 40

Follow `AGENTS.md` and [dogfood](../../.agents/skills/dogfood/SKILL.md) for local runtime setup and evidence. Do not fix application code; use synthetic fixtures and preserve unrelated data.

Test the Svelte `App` at `/`, including incoming-link compatibility and session continuity.

Test the affected success and failure paths, plus relevant loading, empty, keyboard, and accessibility states. For API checks, verify the expected status and response shape; a generic 4xx does not establish correct authorization.

Report PASS, FAIL, or BLOCKED per behavior, with reproduction steps, expected/actual results, and evidence. Distinguish API health from a verified user flow. `SILENT_MODE` returns the report to the parent.
Expand Down
2 changes: 0 additions & 2 deletions .codex/environments/environment.toml
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,6 @@ dotnet restore Exceptionless.slnx
echo "Installing Svelte frontend dependencies..."
npm ci --prefix src/Exceptionless.Web/ClientApp --prefer-offline --no-audit

echo "Installing legacy Angular frontend dependencies..."
npm ci --prefix src/Exceptionless.Web/ClientApp.angular --prefer-offline --no-audit

echo "Setup complete. Use Run Aspire to start the app, Run Storybook for component work, or Run Lume Docs to test the static site."
'''
Expand Down
6 changes: 1 addition & 5 deletions .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
]
}
},
"forwardPorts": [5601, 7101, 7111, 7121, 7131, 8026],
"forwardPorts": [5601, 7101, 7111, 7131, 8026],
"otherPortsAttributes": {
"onAutoForward": "ignore"
},
Expand All @@ -45,10 +45,6 @@
"label": "API",
"protocol": "https"
},
"7121": {
"label": "OldApp",
"protocol": "https"
},
"7131": {
"label": "App",
"protocol": "https"
Expand Down
1 change: 0 additions & 1 deletion .devcontainer/postCreateCommand.sh
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,3 @@ mkdir -p "$HOME/.aspnet/https" "$HOME/.aspnet/dev-certs/trust"

dotnet restore Exceptionless.slnx
npm ci --prefix src/Exceptionless.Web/ClientApp
npm ci --prefix src/Exceptionless.Web/ClientApp.angular
9 changes: 8 additions & 1 deletion .dockerignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,11 @@ LICENSE.txt
**/bin/
**/obj/
**/TestResult/
**/out/
**/out/
**/node_modules/
**/.svelte-kit/
src/Exceptionless.Web/ClientApp/build/
src/Exceptionless.Web/ClientApp/test-results/
src/Exceptionless.Web/ClientApp/playwright-report/
src/Exceptionless.Web/ClientApp/blob-report/
dogfood-output/
17 changes: 7 additions & 10 deletions .github/workflows/build.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,9 @@ jobs:
- name: Lint Client
run: npm run lint

- name: Verify runtime configuration and entrypoints
run: node --test ../../../build/update-config.test.mjs

- name: Check
run: npm run check

Expand Down Expand Up @@ -343,9 +346,7 @@ jobs:
with:
node-version: 24
cache: npm
cache-dependency-path: |
src/Exceptionless.Web/ClientApp/package-lock.json
src/Exceptionless.Web/ClientApp.angular/package-lock.json
cache-dependency-path: src/Exceptionless.Web/ClientApp/package-lock.json

- uses: actions/cache@v6
with:
Expand All @@ -358,10 +359,6 @@ jobs:
working-directory: src/Exceptionless.Web/ClientApp
run: npm ci

- name: Install Legacy Client Npm Packages
working-directory: src/Exceptionless.Web/ClientApp.angular
run: npm ci

- name: Install Playwright Chromium
working-directory: src/Exceptionless.Web/ClientApp
# The hosted Ubuntu image includes Chromium's system libraries. Avoid apt
Expand All @@ -386,7 +383,7 @@ jobs:
run: |
for attempt in {1..60}; do
if curl --connect-timeout 5 --max-time 20 -fksS https://web-ex.dev.localhost:7131/api/v2/about > /dev/null &&
curl --connect-timeout 5 --max-time 20 -fksS https://web-ex.dev.localhost:7131/next/login > /dev/null; then
curl --connect-timeout 5 --max-time 20 -fksS https://web-ex.dev.localhost:7131/login > /dev/null; then
break
fi

Expand All @@ -406,7 +403,7 @@ jobs:
- name: Verify E2E Endpoints
run: |
curl --connect-timeout 5 --max-time 30 -fksS https://web-ex.dev.localhost:7131/api/v2/about > /dev/null
curl --connect-timeout 5 --max-time 30 -fksS https://web-ex.dev.localhost:7131/next/login > /dev/null
curl --connect-timeout 5 --max-time 30 -fksS https://web-ex.dev.localhost:7131/login > /dev/null

- name: Run Playwright E2E Tests
working-directory: src/Exceptionless.Web/ClientApp
Expand All @@ -420,7 +417,7 @@ jobs:
if: ${{ failure() }}
run: |
mkdir -p aspire-logs
for resource in Api App OldApp; do
for resource in Api App; do
timeout 30s aspire logs "$resource" --apphost src/Exceptionless.AppHost --tail 200 --timestamps --non-interactive > "aspire-logs/$resource.log" 2>&1 || true
done
free -m > aspire-logs/memory.log
Expand Down
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,6 @@ App_Data
src/Exceptionless.Web/storage/
src/Exceptionless.Web/ClientApp/build/
src/Exceptionless.Web/appsettings.Local.yml
src/Exceptionless.Web/ClientApp.angular/dist/
src/Exceptionless.Web/wwwroot/
node_modules

Expand Down
8 changes: 4 additions & 4 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -61,15 +61,15 @@
"type": "msedge",
"request": "launch",
"name": "frontend: Web (Edge)",
"url": "https://web-ex.dev.localhost:7131/next",
"url": "https://web-ex.dev.localhost:7131/",
"webRoot": "${workspaceFolder}/src/Exceptionless.Web/ClientApp",
"preLaunchTask": "npm run dev"
},
{
"type": "msedge",
"request": "launch",
"name": "frontend: Web Dev Api (Edge)",
"url": "https://web-ex.dev.localhost:7131/next",
"url": "https://web-ex.dev.localhost:7131/",
"webRoot": "${workspaceFolder}/src/Exceptionless.Web/ClientApp",
"preLaunchTask": "npm run dev:api"
},
Expand All @@ -85,15 +85,15 @@
"type": "chrome",
"request": "launch",
"name": "frontend: Web (Chrome)",
"url": "https://web-ex.dev.localhost:7131/next",
"url": "https://web-ex.dev.localhost:7131/",
"webRoot": "${workspaceFolder}/src/Exceptionless.Web/ClientApp",
"preLaunchTask": "npm run dev"
},
{
"type": "chrome",
"request": "launch",
"name": "frontend: Web Dev Api (Chrome)",
"url": "https://web-ex.dev.localhost:7131/next",
"url": "https://web-ex.dev.localhost:7131/",
"webRoot": "${workspaceFolder}/src/Exceptionless.Web/ClientApp",
"preLaunchTask": "npm run dev:api"
},
Expand Down
12 changes: 5 additions & 7 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,17 +35,16 @@ src/
├── Exceptionless.Core # Domain logic
├── Exceptionless.Insulation # Elasticsearch, Redis, Azure infrastructure
├── Exceptionless.Web # API host
│ ├── ClientApp.angular/ # Legacy Angular UI
│ └── ClientApp/ # Svelte 5 UI
│ └── ClientApp/ # Svelte 5 UI at /
└── Exceptionless.Job # Background workers
tests/ # C# tests and HTTP samples
```

## Frontend Direction

- `src/Exceptionless.Web/ClientApp` is the default target for all new frontend UI work.
- `src/Exceptionless.Web/ClientApp.angular` is legacy. Touch it only when the user explicitly asks for Angular/legacy UI work or the bug exists only there.
- Do not copy Angular patterns into Svelte. Use the frontend skills for Svelte architecture, TanStack Query/Form, and shadcn-svelte details.
- `src/Exceptionless.Web/ClientApp` is the only application frontend and serves Svelte at `/`.
- Use root routes for navigation, documentation, and ordinary test fixtures. Keep hash-route examples in incoming-link compatibility tests only; preserve the existing session storage key and public contracts.
- Use the frontend skills for Svelte architecture, TanStack Query/Form, and shadcn-svelte details.

## Testing and Safety

Expand All @@ -57,8 +56,7 @@ tests/ # C# tests and HTTP samples
- Treat flaky tests as failures to investigate and fix. Retries are for diagnostics, not acceptance; preserve CI's flaky-test gate. Reproduce timing failures with retries disabled and repeat affected scenarios after fixing the cause. Synchronize on observable state and isolate unrelated background activity instead of widening assertions or adding arbitrary sleeps.
- Local app URLs:
- Aspire dashboard: `https://ex.dev.localhost:7101`
- Svelte app: `https://web-ex.dev.localhost:7131/next/`
- Legacy Angular app: `https://angular-ex.dev.localhost:7121`
- Svelte app: `https://web-ex.dev.localhost:7131/`
- API health: `https://api-ex.dev.localhost:7111/api/v2/about`
- API health fallback for command-line tools with local TLS issues: `http://api-ex.dev.localhost:7110/api/v2/about`
- Aspire may assign dynamic local ports; when it does, use the endpoints emitted by the AppHost rather than assuming the fixed URLs above.
Expand Down
2 changes: 2 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ Anyone wishing to contribute to the **[Exceptionless/Exceptionless](https://gith

## Contributing (Step-by-step)

See the [README](README.md#contributing) for Aspire setup. The only application frontend is Svelte in `src/Exceptionless.Web/ClientApp`, served at `/`. Follow its [frontend guide](src/Exceptionless.Web/ClientApp/README.md) and the applicable `AGENTS.md` instructions.

1. Refer to the GitHub documentation on how to fork the repository:

https://help.github.com/articles/fork-a-repo
Expand Down
10 changes: 2 additions & 8 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -83,16 +83,13 @@ WORKDIR /app
COPY --from=app-publish /app/src/Exceptionless.Web/out ./
COPY ./build/app-docker-entrypoint.sh ./
COPY ./build/update-config.sh /usr/local/bin/update-config
COPY ./build/update-config-next.sh /usr/local/bin/update-config-next

ENV EX_ConnectionStrings__Storage=provider=folder;path=/app/storage \
EX_RunJobsInProcess=true \
ASPNETCORE_URLS=http://+:8080 \
EX_Html5Mode=true
ASPNETCORE_URLS=http://+:8080

RUN chmod +x /app/app-docker-entrypoint.sh
RUN chmod +x /usr/local/bin/update-config
RUN chmod +x /usr/local/bin/update-config-next

EXPOSE 8080

Expand All @@ -107,7 +104,6 @@ COPY --from=job-publish /app/src/Exceptionless.Job/out ./
COPY --from=app-publish /app/src/Exceptionless.Web/out ./
COPY ./build/docker-entrypoint.sh ./
COPY ./build/update-config.sh /usr/local/bin/update-config
COPY ./build/update-config-next.sh /usr/local/bin/update-config-next
COPY ./build/supervisord.conf /etc/

USER root
Expand Down Expand Up @@ -137,12 +133,10 @@ ENV discovery.type=single-node \
DOTNET_RUNNING_IN_CONTAINER=true \
EX_ConnectionStrings__Storage=provider=folder;path=/app/storage \
EX_ConnectionStrings__Elasticsearch=server=http://localhost:9200 \
EX_RunJobsInProcess=true \
EX_Html5Mode=true
EX_RunJobsInProcess=true

RUN chmod +x /app/docker-entrypoint.sh && \
chmod +x /usr/local/bin/update-config && \
chmod +x /usr/local/bin/update-config-next && \
chown -R elasticsearch:elasticsearch /app && \
mkdir -p /var/log/supervisor >/dev/null 2>&1 && \
chown -R elasticsearch:elasticsearch /var/log/supervisor
Expand Down
9 changes: 3 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ Start here:

After startup:

1. Open `https://localhost:7121/` if a browser does not open automatically.
1. Open `https://web-ex.dev.localhost:7131/` if a browser does not open automatically. If Aspire assigns a dynamic port, use the App endpoint shown in its dashboard.
2. In `Development` mode, a global administrator user `admin@exceptionless.test` with password `tester` is created automatically.

Notes:
Expand All @@ -48,14 +48,11 @@ Notes:
2. Backend tests bootstrap required infrastructure automatically.
3. Use Aspire CLI 13.6.0 or newer (`aspire update --self` to update). The AppHost uses the CLI bundle for the dashboard and resource orchestrator; when no CLI is installed, the SDK downloads the matching version through DNX.

![image](https://user-images.githubusercontent.com/282584/223168564-6518d509-d292-4078-a61f-ab493d2bb812.png)

## UI Development

Frontend work currently spans two apps:
The Svelte 5 UI in `src/Exceptionless.Web/ClientApp` is the only application frontend and serves at `/`. Aspire starts Svelte together with the API. Primary hash-route bookmarks resolve to the current pages, and existing signed-in sessions are retained.

1. The legacy Angular UI in `src/Exceptionless.Web/ClientApp.angular` is still the main site UI. Most of that app lives in `app/`, `components/`, `less/`, `img/`, `lang/`, and `grunt/`.
2. The Svelte 5 UI in `src/Exceptionless.Web/ClientApp` is still under development.
See the [frontend README](src/Exceptionless.Web/ClientApp/README.md) for development, build, and test commands. Published app images contain the Svelte build at the web root; API-only images retain their API landing page.

For a quick API walkthrough, start with [exceptionless.http](exceptionless.http). The [tests/http](tests/http) folder contains additional examples for manual use, such as querying events, uploading source maps, and obtaining OAuth tokens. These are curated examples, not an automated test suite or an exhaustive endpoint catalog. Set the local API URL and sample variables, then run the requests you need. In Visual Studio Code, use the [REST Client](https://marketplace.visualstudio.com/items?itemName=humao.rest-client) extension.

Expand Down
Loading
Loading