+ Co-creation spaces for your tenant.
+ Content will live as markdown in Forgejo-backed repositories.
+
+
+ {% if spaces %}
+
+ {% for space in spaces %}
+
+ {{ space.title }}
+ · {{ space.slug }}
+
+ {% endfor %}
+
+ {% else %}
+
+
No spaces yet
+
+ Spaces and Forgejo-backed content land in the next steps
+ (CSOC-WP-0004-T02+). Use the profile menu for session diagnostics.
+
+
+ {% endif %}
{% endblock %}
diff --git a/tests/test_shell.py b/tests/test_shell.py
index 6dd05d0..e268817 100644
--- a/tests/test_shell.py
+++ b/tests/test_shell.py
@@ -38,7 +38,7 @@ def test_app_home_requires_login(client):
@pytest.mark.django_db
-def test_dev_login_establishes_member_and_shell(client, settings):
+def test_dev_login_lands_on_app_home_not_principal_dump(client, settings):
settings.DEBUG = True
settings.OIDC_ENABLED = False
@@ -63,8 +63,45 @@ def test_dev_login_establishes_member_and_shell(client, settings):
home = client.get(reverse("core:app_home"))
assert home.status_code == 200
+ assert b"Spaces" in home.content
+ assert b"No spaces yet" in home.content
+ # Principal dump moved off the home body
+ assert b"user-engine id" not in home.content
+ assert b"sub-abc" not in home.content
+ # Profile chrome shows display name
assert b"Ada Lovelace" in home.content
- assert b"sub-abc" in home.content
+ assert b"Session details" in home.content
+
+
+@pytest.mark.django_db
+def test_account_session_shows_principal_diagnostics(client, settings):
+ settings.DEBUG = True
+ settings.OIDC_ENABLED = False
+ client.post(
+ reverse("identity:dev_login"),
+ {
+ "subject": "sub-diag",
+ "issuer": "https://local.dev/issuer",
+ "name": "Diag User",
+ "email": "diag@example.com",
+ },
+ )
+ r = client.get(reverse("core:account_session"))
+ assert r.status_code == 200
+ assert b"Session details" in r.content
+ assert b"sub-diag" in r.content
+ assert b"Diag User" in r.content
+ assert b"user-engine id" in r.content
+ assert b"Tenant" in r.content
+ assert b"Roles" in r.content
+ assert b"Groups" in r.content
+
+
+@pytest.mark.django_db
+def test_account_session_requires_login(client):
+ r = client.get(reverse("core:account_session"))
+ assert r.status_code == 302
+ assert reverse("identity:login") in r["Location"]
@pytest.mark.django_db
@@ -75,7 +112,6 @@ def test_establish_session_idempotent(client, settings):
email="x@example.com",
name="Once",
)
- # Use request factory via client session by posting twice
settings.DEBUG = True
settings.OIDC_ENABLED = False
client.post(
diff --git a/workplans/CSOC-WP-0004-app-shell-and-space-content.md b/workplans/CSOC-WP-0004-app-shell-and-space-content.md
index 393329d..02cf671 100644
--- a/workplans/CSOC-WP-0004-app-shell-and-space-content.md
+++ b/workplans/CSOC-WP-0004-app-shell-and-space-content.md
@@ -9,6 +9,7 @@ owner: bernd
topic_slug: coulomb-social
created: "2026-08-10"
updated: "2026-08-10"
+# note: T07 added same day — principal diagnostics via profile menu
depends_on:
- CSOC-WP-0002
related:
@@ -16,6 +17,7 @@ related:
- CSOC-WP-0003
origin: operator
origin_ref: session-2026-08-10-parallel-host-product-path
+state_hub_workstream_id: "d10427aa-02d9-4ec9-a466-d7cdb1a9167e"
---
# CSOC-WP-0004 — App shell entry and Forgejo-backed space content
@@ -49,27 +51,33 @@ Migration of all Bubble spaces is **explicitly later** (`CSOC-WP-0001`).
```task
id: CSOC-WP-0004-T01
-status: todo
+status: done
priority: high
+state_hub_task_id: "7cce67c0-6234-4ef4-ad67-de952f5f4519"
```
Replace the dead-end “Signed in / Principal” page as the primary post-login
destination with an **app home** that a member can use:
- Clear primary navigation: Spaces (and placeholders for later surfaces).
-- Principal summary available but secondary (account menu or `/account/`).
+- Compact account control (display name / avatar) opening a **profile menu**
+ (full principal diagnostics live under **T07**, not on the home body).
- Empty state when the member has no spaces yet (“Create space” or “No spaces”).
- `LOGIN_REDIRECT_URL` and templates updated; design-extract tokens only as needed.
**Done when:** after OIDC login on app.coulomb.social, tegwick lands on app home
(not a debug-only principal card) and can navigate without guessing URLs.
+2026-08-11: App home is Spaces empty state; header nav + profile menu; principal
+dump removed from home body. Deploy with next image for app.coulomb.social.
+
## T02 — Space domain model (metadata, tenant-keyed)
```task
id: CSOC-WP-0004-T02
status: todo
priority: high
+state_hub_task_id: "5fd91718-151d-4216-acf2-2104a45cddf9"
```
Introduce `Space` (name pending Bubble vocabulary alignment) as application
@@ -90,6 +98,7 @@ tenant isolation basics.
id: CSOC-WP-0004-T03
status: todo
priority: high
+state_hub_task_id: "628243e0-732f-42c1-b4e3-9b8cd82ea530"
```
Write `docs/adr/ADR-0002-space-content-forgejo-markdown.md` deciding:
@@ -110,6 +119,7 @@ and linked from INTENT/SCOPE.
id: CSOC-WP-0004-T04
status: todo
priority: high
+state_hub_task_id: "77fa3454-6f2e-4a76-8a0c-ff7e13ca4b6a"
```
Implement a vertical slice:
@@ -128,6 +138,7 @@ markdown sourced from Forgejo (not Bubble).
id: CSOC-WP-0004-T05
status: todo
priority: medium
+state_hub_task_id: "30ed5def-2718-4379-834c-920e751e4d0b"
```
Minimal authoring or sync so content is not read-only forever:
@@ -146,36 +157,80 @@ and (if in-app write exists) a save produces a commit without secrets in git.
id: CSOC-WP-0004-T06
status: todo
priority: medium
+state_hub_task_id: "40a880d0-62b9-4ae4-ab3e-074e8901462a"
```
Document operator steps: create Forgejo org/repo, bind space, credentials env
names, smoke checklist on app.coulomb.social. Update `docs/deploy.md` and
`docs/identity/smoke.md` pointers as needed.
+## T07 — Principal diagnostics via user profile menu
+
+```task
+id: CSOC-WP-0004-T07
+status: done
+priority: high
+```
+
+Keep the current principal card fields available as **detail information**
+reachable from the **user profile menu** in the app chrome (not as the primary
+post-login page body). Purpose: refine and diagnose identity wiring during
+ongoing user, group, role, and tenant management work.
+
+Include at least the present shell fields (and extend as claims become available):
+
+| Area | Examples |
+|------|----------|
+| Identity | display name, username, issuer, subject |
+| Platform user | user-engine id, user-engine source |
+| Tenancy | tenant id / claims |
+| Roles & groups | OIDC/groups/roles claims when present |
+| Authz | flex-auth / shell decision reason + decision id |
+| Session | assurance / AAL hints when present |
+
+UX:
+
+- Profile menu entry e.g. **Account** / **Session details** / **Identity**
+- Detail view at a stable path (e.g. `/account/` or `/account/session/`)
+- Readable for operators; no secrets (tokens, proxy secrets) ever rendered
+- Sign out remains on the menu
+
+**Done when:** after T01 app chrome exists, tegwick can open the profile menu →
+principal/session detail page and see the same diagnostic surface formerly on
+the signed-in card, without that card being the home page.
+
+Ship with or immediately after **T01** (same PR is fine).
+
+2026-08-11: `/account/session/` holds principal diagnostics (identity, UE,
+tenant, roles/groups, assurance, authz). Profile menu → **Session details**.
+Session stashes groups/roles/assurance at login (no secrets).
+
---
## Sequencing
```text
-T01 app home entry
- └─► T02 Space metadata
- └─► T03 content ADR
- └─► T04 read path (MVP value)
- ├─► T05 write/sync
- └─► T06 runbook
+T01 app home entry ──┬─► T07 profile menu principal diagnostics
+ └─► T02 Space metadata
+ └─► T03 content ADR
+ └─► T04 read path (MVP value)
+ ├─► T05 write/sync
+ └─► T06 runbook
```
-T01 can ship alone to fix the “stuck on login confirmation” UX immediately.
-T03 should land before large T04 investment if write-model choices are unclear;
-a **provisional** ADR is enough to start T04 against a single seed repo.
+T01 (+ T07) can ship alone to fix the “stuck on login confirmation” UX while
+keeping identity diagnostics one click away. T03 should land before large T04
+investment if write-model choices are unclear; a **provisional** ADR is enough
+to start T04 against a single seed repo.
## Acceptance (workplan)
1. Post-login journey is product-shaped (app home + spaces), not identity-debug-only.
-2. Spaces exist as tenant-keyed app records.
-3. Space page content is markdown backed by Forgejo with a working read path.
-4. Bubble migration is still not required for demos on app.coulomb.social.
-5. CSOC-WP-0001 can map Bubble pages onto the ADR layout when migration starts.
+2. Principal/session diagnostics remain available from the user profile menu (T07).
+3. Spaces exist as tenant-keyed app records.
+4. Space page content is markdown backed by Forgejo with a working read path.
+5. Bubble migration is still not required for demos on app.coulomb.social.
+6. CSOC-WP-0001 can map Bubble pages onto the ADR layout when migration starts.
## Related