Web epic status rebaseline — 2026-08-25
WEB-01 through WEB-04 (#30–#33) and the canonical local gate #27 are complete. The remaining Web critical path is now only:
flowchart LR
C34["#34 apply Web foundation/runtime\nimmutable explicit-intent image"] --> C35["#35 real Telegram OIDC\ntwo-tenant cloud/browser E2E"] --> R14["#14 release hardening"]
#34 has implementation/Terraform/publication support in main, but its live foundation apply, Web secret loading, DNS/certificate/container evidence and rollback smoke require operator-owned Yandex backend/tfvars/deployment-lock inputs. Image publication is no longer an implicit effect of every green main CI run; #71 requires an explicit deployment/publication intent.
#35 repeats the already-closed local canonical/isolation proof against real Telegram OIDC and cloud resources. It no longer blocks #27, which is closed; it remains a cloud release gate for #14.
Architecture remains unchanged: one private Go BFF with embedded static Svelte assets; Node is build-only; Python is absent. No subscription-worker credential is added to the Web container. The new attached-worker path is tracked separately by #72 and joins Web only through authenticated resource/status APIs after its owner/security contracts exist.


Parent architecture
Outcome
Deliver a small authenticated WebUI as the second Sessionless frontend. A user signs in with Telegram, Sessionless resolves that external identity to its internal user and tenant memberships, and the browser can access only canonical sessions authorized for the selected tenant.
The WebUI is a frontend/projection over Sessionless canonical state. It does not import Telegram chat history, make Telegram authoritative for product sessions, or introduce a WebUI-owned conversation store.
Decision summary
adapter-static.tenant_id.web.dev.sessionless.triborg.devin the delegated Yandex DNS zone.Why this shape
Svelte's official static adapter emits deployable static files, so SSR is unnecessary for this authenticated application shell: SvelteKit static generation.
Yandex Serverless Containers accept an arbitrary AMD64 containerized HTTP server, scale instances for requests and allow zero provisioned instances. A static Svelte build embedded in the Go binary gives one immutable artifact and one same-origin security boundary: Serverless Containers, runtime, limits.
Telegram now documents a standard OIDC Authorization Code flow with PKCE and JWKS validation. This is preferred over the archived iframe login widget: Log In With Telegram.
System diagram
flowchart LR Browser["Browser<br/>static Svelte UI"] --> Gateway["API Gateway<br/>web.dev.sessionless.triborg.dev"] Gateway --> BFF["Private Go web-bff<br/>embedded UI + JSON API"] BFF --> OIDC["Telegram OIDC<br/>auth/code + token + JWKS"] BFF --> YDB["YDB Serverless<br/>auth sessions + canonical metadata"] BFF --> Storage["Object Storage<br/>payloads and attachments"] BFF --> App["Canonical application services<br/>sessions/events/runs/quota"] App --> YDB App --> StorageAuthentication and tenant resolution
sequenceDiagram actor U as User participant W as Svelte WebUI participant B as Go BFF participant T as Telegram OIDC participant D as YDB U->>W: Sign in with Telegram W->>B: GET /auth/telegram/start B->>D: Store hashed state, PKCE verifier, nonce and expiry B-->>U: Redirect to Telegram authorization endpoint U->>T: Approve login T-->>B: Authorization code + state B->>D: Consume one-time login challenge B->>T: Exchange code using PKCE T-->>B: ID token B->>B: Verify signature, iss, aud, exp, nonce B->>D: Resolve Telegram subject to internal user and memberships alt no existing authorized membership B-->>U: 403; instruct user to initialize via the bot else authorized membership B->>D: Store hashed opaque web session B-->>U: Secure HttpOnly SameSite cookie end U->>B: Request/select tenant B->>D: Validate membership and load tenant-scoped state B-->>U: Authorized canonical dataRules:
subidentifies a Telegram external identity; it is not atenant_id.tenant_id.Web session and CSRF contract
__Host-Secure, HttpOnly, SameSite=Lax cookie with Path=/ and no Domain attribute.Pre-tenant auth lookup is an explicit exception to tenant-first keys: login challenge and session keys use a random digest prefix to avoid hot ranges. After the session resolves a membership, all product access is tenant-scoped.
Minimal YDB additions
web_login_challenges(shard, state_hash): PKCE verifier, nonce, redirect target, created/expires/consumed timestamps; short TTL.web_auth_sessions(shard, session_hash): user, active tenant, authentication provider/subject reference, membership security version, issued/seen/idle/absolute/revoked timestamps; TTL.MVP WebUI surface
The browser does not proxy large uploads through the container. Serverless Container HTTP requests are limited to 3.5 MB, so the BFF issues a short-lived tenant-bound Object Storage upload intent and validates the resulting object before committing an event: container limits, Object Storage Presign API. Prefer the IAM-authenticated Yandex Presign API from the container metadata identity; do not add a static S3 key unless a verified API limitation forces a separately reviewed fallback.
API boundary
Initial same-origin routes:
Handlers call frontend-neutral ports introduced by #20–#26. Resource IDs are opaque selectors; authorization is rechecked for every request.
Deployment
web-bffservice account with only container invocation runtime, YDB table access, Lockbox payload access, logging and bounded Object Storage permissions required by the implemented routes.web-bffServerless Container and a dedicated API Gateway/custom certificate forweb.dev.sessionless.triborg.dev.go:embed.Local and cloud verification
APP_ENV=localguard; it must refuse to run in cloud modes.Decomposition
Nominal estimate: 37 SP / 23 engineering days, before reserve.
gantt title Authenticated serverless WebUI track dateFormat YYYY-MM-DD axisFormat %d %b excludes weekends section Contracts and identity WEB-01 contracts and threat model (#30) :crit, w1, 2026-08-05, 2d WEB-02 Go OIDC BFF and sessions (#31) :crit, w2, after w1, 5d section Product and UI WEB-03 canonical Web API (#32) :crit, w3, after w2, 5d WEB-04 Svelte UI (#33) :crit, w4, after w3, 5d section Cloud and gate WEB-05 serverless deployment (#34) :w5, after w4, 3d WEB-06 isolation/cloud E2E (#35) :crit, w6, after w5, 3d WebUI gate :milestone, webgate, after w6, 0dThe dates show a single-engineer dependency baseline. WEB-04 can build against the WEB-01 contract fixtures while WEB-02/03 are in progress; WEB-05 Terraform work can begin after #12 independently of the final UI bundle.
Dependency direction
flowchart TD S20["#20 canonical contracts"] --> W1["WEB-01 contracts"] W1 --> W2["WEB-02 auth BFF"] S21["#21 canonical schema"] --> W2 W2 --> W3["WEB-03 canonical Web API"] S24["#24 stateless context"] --> W3 S26["#26 listing/history API"] --> W3 W1 --> W4["WEB-04 Svelte UI"] W2 --> W4 W3 --> W4 C12["#12 cloud foundation"] --> W5["WEB-05 deployment"] W2 --> W5 W4 --> W5 W3 --> W6["WEB-06 E2E"] W4 --> W6 W5 --> W6 W6 --> S27["#27 cross-frontend gate"] W6 --> R14["#14 release hardening"]WEB-01 and the UI shell may start before Telegram ingress #17. The WebUI track does not depend on the external Telegram update edge #17/#18: Telegram OIDC is a separate browser identity channel. Live Telegram message delivery remains a later integration/release gate.
Acceptance criteria
tenant_id, session ID, OIDC callback, CSRF token or upload key cannot cross tenant boundaries.Non-goals