Start here →
AGENTS.md·SPEC_INDEX.md·ARCHITECTURE.md.
| Field | Value |
|---|---|
| Module id | application-details-and-actions |
| Source path(s) | src/pages/applications/, app-detail/action components, action API routes, src/lib/add-bot-*.ts |
| Doc kind | Module spec |
| Coverage score | 100% assessed 2026-07-24; 14/14 mandatory fields PRESENT, existing detail-route found/not-found evidence verified |
| Generated from | module-spec @ 0.2.1 |
| generated_by / approved_by / updated_at | codex (gpt-5.6) / repository owner scope approval / 2026-07-24 |
| Validation status | pass-with-warnings; validator claude-opus-4-8-1m (runtime independent of codex), target HEAD b9c7321ee3642bdb0137734e187a102a7f5de9be, assessed 2026-07-24; 0 Blocking, 0 Important, 0 Medium, 2 Minor; full suite environment-blocked (Node 24 + registry pending) |
The app detail page, URL/analytics helpers, action APIs, stores/components, and tests define current behavior. The earlier add-bot plan was verified against this implementation.
| Source material | Scope | Decision | Disposition |
|---|---|---|---|
| Add Bot flow specification | UI/API/state/analytics | verified/corrected | Current modal, auth, rooms, membership/message actions and analytics |
| Current page/helpers/tests | detail/actions | authoritative | Requirements, flow, failures, tests |
/applications/[appId] server-renders normalized application detail content and conditionally exposes actions such as bot addition, messaging, native integration connection, authorization removal, webhooks, embedded app access, and external links. React/Astro components use same-origin action APIs and concern-specific stores.
Owns application-detail presentation and user actions tied to one catalog application; data source normalization, global auth, and webhook persistence remain elsewhere.
Astro dynamic page, Astro/React components, Nano Stores, same-origin APIs, adapter helpers, Vitest.
src/pages/applications/[appId].astro
src/components/
├── AppDetailsHero.astro
├── AppDetailsDescription.astro
├── AddBotModal.astro
├── EmbeddedAppModal.astro
└── RequiresAdminModal.astro
src/pages/api/{auth-status,check-authorization,rooms,create-membership,send-direct-message,validate-embedded-app-access}.ts
| File | Holds |
|---|---|
src/pages/applications/[appId].astro | SSR lookup, page composition, action gating |
src/lib/app-details-urls.ts | safe/detail action URL construction |
src/lib/add-bot-urls.ts | add-bot route/body helpers |
src/lib/add-bot-analytics.ts | event construction |
| action API route files | auth, validation, upstream mutation |
src/stores/appDetailsStore.ts, roomsStore.ts | browser state |
| Contract ID | Type | Surface | Purpose | Compatibility | Detail | Root |
|---|---|---|---|---|---|---|
application.detail | HTTP | GET /applications/:appId | Render detail page | URL/metadata/action stability | page file | CONTRACTS.md |
application.auth-status | HTTP | auth/authorization check APIs | Gate actions | additive JSON | API files | CONTRACTS.md |
application.add-bot | HTTP | rooms/membership/message APIs | Complete bot flow | body/status stable | API files | CONTRACTS.md |
application.embedded-access | HTTP | embedded access API | Gate embedded launch | reason/status stable | API file | CONTRACTS.md |
Synchronized app lookup, auth/session, Webex/Hydra APIs, media helpers, stores/notifications, URL safety, analytics, middleware/CSRF.
| ID | WHAT | WHY | Source Evidence | Test Evidence | Gaps | Confidence |
|---|---|---|---|---|---|---|
APP-R-001 | Detail route MUST validate/resolve appId, render current normalized data with canonical SEO, and return current not-found behavior when absent. | Keeps direct URLs SSR-complete and safe. | src/pages/applications/[appId].astro, src/lib/fetch-synced-data.ts, src/lib/seo.ts | playwright/tests/functional/apps/app-detail.spec.ts, tests/unit/lib/listing-app.test.ts, tests/unit/lib/seo.test.ts | none | PRESENT |
APP-R-002 | Action visibility/URLs MUST derive from normalized app type/capabilities and centralized helpers, not arbitrary CMS strings. | Prevents unsafe/inconsistent actions. | src/components/AppDetailsHero.astro, src/lib/app-details-urls.ts, src/lib/add-bot-urls.ts | tests/unit/lib/app-details-urls.test.ts, tests/unit/lib/add-bot-urls.test.ts | none | PRESENT |
APP-R-003 | Add Bot MUST require authentication, load rooms, validate room/message inputs, create membership or direct message through same-origin protected APIs, and report success/failure. | Completes the user action without exposing tokens or false success. | src/components/AddBotModal.astro, src/pages/api/rooms.ts, src/pages/api/create-membership.ts, src/pages/api/send-direct-message.ts | tests/unit/lib/api-bot.test.ts, tests/unit/stores/roomsStore.test.ts | full live E2E external | PRESENT |
APP-R-004 | Embedded app access MUST evaluate server-side user/app policy and fail closed on configured service/token errors. | Prevents unauthorized launch. | src/pages/api/validate-embedded-app-access.ts, src/components/EmbeddedAppModal.astro | tests/unit/lib/api-validate-embedded-app-access.test.ts | external policy integration | PRESENT |
APP-R-005 | Analytics MUST use centralized event/property builders and must not include credentials or sensitive session data. | Preserves telemetry compatibility and privacy. | src/lib/add-bot-analytics.ts, src/lib/analytics.ts | tests/unit/lib/add-bot-analytics.test.ts, tests/unit/lib/analytics.test.ts | end-to-end delivery external | PRESENT |
The page is SSR-first. Normalized application data selects component variants and action affordances. Complex action flows hydrate only their islands/stores. All protected calls go through App Hub APIs, which apply session/CSRF/input controls and proxy to upstream clients.
flowchart LR
URL --> DetailPage --> SyncRead["Redis/sync lookup"]
SyncRead --> View["SSR detail components"]
View --> Action["React/modal action"]
Action --> Store
Action --> LocalAPI
LocalAPI --> Auth --> Webex
| Operation group | Diagram | Failure coverage |
|---|---|---|
| Detail render | ID → data → SSR | invalid/missing application |
| Add bot | auth → rooms → membership/message | unauthenticated, invalid input, upstream error |
| Embedded launch | access evaluation → modal/navigation | not configured, token/fetch denial |
sequenceDiagram
participant U as User
participant D as Detail UI
participant A as App Hub API
participant W as Webex
U->>D: Add bot
D->>A: GET rooms
A->>W: authorized rooms
W-->>A: rooms
A-->>D: items
U->>D: choose room / direct message
D->>A: protected POST
alt success
A->>W: membership/message
W-->>D: success
else failure
A-->>D: stable error
end
sequenceDiagram
participant B as Browser
participant P as Detail page
participant R as Synchronized catalog
B->>P: GET /applications/:appId
P->>P: validate identifier
P->>R: lookup friendly/raw id
alt found
R-->>P: normalized application
P-->>B: SSR detail + canonical metadata/actions
else missing
R-->>P: null
P-->>B: current not-found response
end
sequenceDiagram
participant U as User
participant M as Embedded app modal
participant A as Access API
participant S as Settings service
U->>M: request launch
M->>A: GET access for app id
A->>A: session/token/app validation
opt configured authenticated policy
A->>S: evaluate user access
end
alt allowed
A-->>M: allowed true
M-->>U: launch
else denied/error
A-->>M: allowed false + reason
M-->>U: remain closed/error
end
classDiagram
class DetailPage
class DetailComponents
class ActionModal
class AppDetailsStore
class RoomsStore
class ApiRoutes
DetailPage --> DetailComponents
DetailComponents --> ActionModal
ActionModal --> AppDetailsStore
ActionModal --> RoomsStore
ActionModal --> ApiRoutes
src/pages/applications/[appId].astro.src/components/AddBotModal.astro, src/pages/api/create-membership.ts, src/pages/api/send-direct-message.ts.src/pages/api/validate-embedded-app-access.ts, src/pages/integration/[integrationId]/connect.ts.appDetailsStore holds current app/loading/error/embedded-access; roomsStore holds room list, membership and direct-message action errors. Modal visibility is coordinated by modal/client scripts and store state where applicable.
stateDiagram-v2
[*] --> SSRReady
SSRReady --> AuthRequired: protected action unauthenticated
SSRReady --> LoadingAction: valid action
LoadingAction --> Success: upstream success
LoadingAction --> Error: validation/upstream failure
AuthRequired --> SSRReady: login complete
Error --> LoadingAction: retry
Success --> SSRReady: dismiss
| Condition | Signal | Recovery |
|---|---|---|
| Unknown app | 404/not-found | correct URL |
| Unauthenticated action | login/auth-required UI | login then retry |
| Invalid room/message/app ID | 400 browser-safe error | correct input |
| Upstream rejection | mapped error/notification | inspect permission, retry |
| Embedded access denied | {allowed:false, reason} | do not launch |
id, friendlyId, clientId, and bot username are different identifiers.SSR detail pages maximize direct-navigation/SEO reliability, while selectively hydrated action flows add coordination complexity across components, stores, and protected APIs.
Test URL/analytics helpers, auth/action API validation and status mapping, store transitions, modal/component states, SSR build, and authenticated E2E where service test users are available.
| Behavior | Evidence | Gap |
|---|---|---|
| detail route found/not-found | playwright/tests/functional/apps/app-detail.spec.ts | none |
| URL/analytics | add-bot/app-detail helper tests | none |
| action APIs | API bot/auth/embedded tests | live upstream |
| stores/UI | rooms/appDetails/component tests | full journey environment-dependent |
ARCHITECTURE.mdSECURITY.md.sdd/manifest.json