<feed xmlns='http://www.w3.org/2005/Atom'>
<title>progmaweb/ops/nginx, branch main</title>
<subtitle>The site and account service of Progmasoft: a Next.js frontend and an ASP.NET Core API.</subtitle>
<link rel='alternate' type='text/html' href='https://git.progmasoft.com/progmaweb/'/>
<entry>
<title>Merge remote-tracking branch 'origin/main' into security/cloudflare-real-ip</title>
<updated>2026-11-08T22:18:34+00:00</updated>
<author>
<name>Leitwolf11</name>
</author>
<published>2026-11-08T22:18:34+00:00</published>
<link rel='alternate' type='text/html' href='https://git.progmasoft.com/progmaweb/commit/?id=c0bafe9050161ea6ca0c49f54897f908ca16ce84'/>
<id>c0bafe9050161ea6ca0c49f54897f908ca16ce84</id>
<content type='text'>
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
</pre>
</div>
</content>
</entry>
<entry>
<title>Rate-limit sign-in by visitor behind Cloudflare and stop forwarding h2c</title>
<updated>2026-11-08T21:38:47+00:00</updated>
<author>
<name>Leitwolf11</name>
</author>
<published>2026-11-08T21:38:47+00:00</published>
<link rel='alternate' type='text/html' href='https://git.progmasoft.com/progmaweb/commit/?id=66f3cc196a9b91d471a90e021b12630100181c4a'/>
<id>66f3cc196a9b91d471a90e021b12630100181c4a</id>
<content type='text'>
Cloudflare proxies the Progmasoft hosts, so Nginx saw a Cloudflare edge as
its peer and appended that edge to X-Forwarded-For. The API takes the last
hop as the client, so the account-auth limit (12 attempts in 3 minutes) was
counted per edge: 38 failed sign-ins from one address in a row were all
answered with 401, none with 429, and unrelated visitors behind one edge
shared a bucket.

- ops/nginx/cloudflare-real-ip.conf trusts CF-Connecting-IP only from the
  published Cloudflare ranges; a direct peer keeps its own address, so the
  header cannot be forged around Cloudflare. With it installed the 13th
  failed sign-in gets 429, a forged X-Forwarded-For changes nothing, and
  another address is not affected.
- Every proxied location forwarded the client's Upgrade header with
  "Connection: upgrade" on each request. Only a WebSocket upgrade is now
  forwarded; other requests carry no Upgrade and an empty Connection.
- c8 reached glob 13 (GHSA-3g3m-2fjr-6pw4) and minimatch 10
  (GHSA-g3hv-75wg-m249) through test-exclude; both are overridden to the
  fixed majors. pnpm audit reports nothing, coverage, lint and check pass.
- The CodeQL action pins carry their exact version comment (v4.38.2).
- ops/README.md describes the address handling and no longer names a
  script that left the repository with AI Support.

Co-Authored-By: Claude Opus 5.5 &lt;noreply@anthropic.com&gt;
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Cloudflare proxies the Progmasoft hosts, so Nginx saw a Cloudflare edge as
its peer and appended that edge to X-Forwarded-For. The API takes the last
hop as the client, so the account-auth limit (12 attempts in 3 minutes) was
counted per edge: 38 failed sign-ins from one address in a row were all
answered with 401, none with 429, and unrelated visitors behind one edge
shared a bucket.

- ops/nginx/cloudflare-real-ip.conf trusts CF-Connecting-IP only from the
  published Cloudflare ranges; a direct peer keeps its own address, so the
  header cannot be forged around Cloudflare. With it installed the 13th
  failed sign-in gets 429, a forged X-Forwarded-For changes nothing, and
  another address is not affected.
- Every proxied location forwarded the client's Upgrade header with
  "Connection: upgrade" on each request. Only a WebSocket upgrade is now
  forwarded; other requests carry no Upgrade and an empty Connection.
- c8 reached glob 13 (GHSA-3g3m-2fjr-6pw4) and minimatch 10
  (GHSA-g3hv-75wg-m249) through test-exclude; both are overridden to the
  fixed majors. pnpm audit reports nothing, coverage, lint and check pass.
- The CodeQL action pins carry their exact version comment (v4.38.2).
- ops/README.md describes the address handling and no longer names a
  script that left the repository with AI Support.

Co-Authored-By: Claude Opus 5.5 &lt;noreply@anthropic.com&gt;
</pre>
</div>
</content>
</entry>
<entry>
<title>Remove Xide and ides.progmasoft.com</title>
<updated>2026-11-08T15:46:08+00:00</updated>
<author>
<name>Leitwolf11</name>
</author>
<published>2026-11-08T15:46:08+00:00</published>
<link rel='alternate' type='text/html' href='https://git.progmasoft.com/progmaweb/commit/?id=efa1f584205e93c292ea40b564d92a03f12ab33c'/>
<id>efa1f584205e93c292ea40b564d92a03f12ab33c</id>
<content type='text'>
Xide is no longer developed as of 2026-11-08 (Progmasoft/xide#29), so
Progmaweb stops presenting it:

- product.progmasoft.com: Xide leaves the catalog, its card and its
  detail page; /xide on the product host is a 404 like any unknown
  product. The catalog's description in every language names the Tala
  language with its tools and Catch3.
- ides.progmasoft.com served only the IDE list and the Xide page, so the
  whole site goes: the pages under app/ides, its texts in every
  language, idesRoute and its host in the proxy, and both nginx server
  blocks. The certificate of progmasoft.com no longer has to name it.

Tests: the catalog lists the remaining products and refuses xide.
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Xide is no longer developed as of 2026-11-08 (Progmasoft/xide#29), so
Progmaweb stops presenting it:

- product.progmasoft.com: Xide leaves the catalog, its card and its
  detail page; /xide on the product host is a 404 like any unknown
  product. The catalog's description in every language names the Tala
  language with its tools and Catch3.
- ides.progmasoft.com served only the IDE list and the Xide page, so the
  whole site goes: the pages under app/ides, its texts in every
  language, idesRoute and its host in the proxy, and both nginx server
  blocks. The certificate of progmasoft.com no longer has to name it.

Tests: the catalog lists the remaining products and refuses xide.
</pre>
</div>
</content>
</entry>
<entry>
<title>Show the Tazel plugins of ViGet, open the Gradle catalog, and route their files</title>
<updated>2026-10-29T09:32:23+00:00</updated>
<author>
<name>Leitwolf11</name>
</author>
<published>2026-10-29T09:32:23+00:00</published>
<link rel='alternate' type='text/html' href='https://git.progmasoft.com/progmaweb/commit/?id=3d1c6d52b830d201a68b0440a8a81c13b74c8b92'/>
<id>3d1c6d52b830d201a68b0440a8a81c13b74c8b92</id>
<content type='text'>
The API of the previous commit holds the catalog; this adds what people and
Tazel reach.

Pages:
- /dslplugins/tazel lists the published plugins, read from the API on its
  loopback address, and says when there is none.
- /dslplugins/tazel/&lt;Publisher&gt;/&lt;Name&gt; is the page of a plugin: its
  description, publisher, latest version, license, authors, homepage and
  repository, the plugins block that uses it, and every version with its
  date, plugin API, size, SHA-256, yanked mark and JAR.
- /dslplugins/gradle opens the Gradle catalog. It only lists: Gradle takes
  com.progmasoft.tazel.plugin from the Gradle Plugin Portal.
- The availability note says that Progmasoft publishes first and every
  account later. Texts are in the four languages of the site.

Nginx (ops/nginx/progmaweb.conf):
- On viget.progmasoft.com, index.json of a plugin goes to the API and the
  JARs come from /srv/viget/files with immutable caching; /api/ stays
  closed.
- maven.progmasoft.com serves /srv/maven, whose /tazel holds tazel-api.

ops/README.md describes the directories, their SELinux labels, the publish
and yank commands, and how a release of Tazel copies the API into the Maven
repository.

Tests cover the texts in every language, the plugins block, the Gradle list,
and that a page asks the API only for identifiers.
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
The API of the previous commit holds the catalog; this adds what people and
Tazel reach.

Pages:
- /dslplugins/tazel lists the published plugins, read from the API on its
  loopback address, and says when there is none.
- /dslplugins/tazel/&lt;Publisher&gt;/&lt;Name&gt; is the page of a plugin: its
  description, publisher, latest version, license, authors, homepage and
  repository, the plugins block that uses it, and every version with its
  date, plugin API, size, SHA-256, yanked mark and JAR.
- /dslplugins/gradle opens the Gradle catalog. It only lists: Gradle takes
  com.progmasoft.tazel.plugin from the Gradle Plugin Portal.
- The availability note says that Progmasoft publishes first and every
  account later. Texts are in the four languages of the site.

Nginx (ops/nginx/progmaweb.conf):
- On viget.progmasoft.com, index.json of a plugin goes to the API and the
  JARs come from /srv/viget/files with immutable caching; /api/ stays
  closed.
- maven.progmasoft.com serves /srv/maven, whose /tazel holds tazel-api.

ops/README.md describes the directories, their SELinux labels, the publish
and yank commands, and how a release of Tazel copies the API into the Maven
repository.

Tests cover the texts in every language, the plugins block, the Gradle list,
and that a page asks the API only for identifiers.
</pre>
</div>
</content>
</entry>
<entry>
<title>Redesign progmasoft.com and add the product catalog and product sites</title>
<updated>2026-10-23T08:29:43+00:00</updated>
<author>
<name>Leitwolf11</name>
</author>
<published>2026-10-23T08:29:43+00:00</published>
<link rel='alternate' type='text/html' href='https://git.progmasoft.com/progmaweb/commit/?id=20a55c4ccbb0f181346444a4c7f083e86389cf9c'/>
<id>20a55c4ccbb0f181346444a4c7f083e86389cf9c</id>
<content type='text'>
progmasoft.com presents Progmasoft as a pool of technology areas instead
of a list of products: languages and compilers, build and packages,
developer tools, quality and testing, identity and access, and
infrastructure. The page has a new hero, a bento of areas, principles and
a developers band that leads to the Progmasoft Console; the products are
one link away in their own catalog.

product.progmasoft.com lists Tala, talac, talafmt, talalint, Tazel, Xide
and Catch3, each with its own page (/tala-lang, /talac, ...) that leads
to the product's site and source. ides.progmasoft.com lists the IDEs and
hosts the Xide site at /xide; catch3.progmasoft.com is the Catch3 site.
The facts follow the READMEs and documentation of the product
repositories: Xide is marked as early work, and Catch3 states that it is
not an official Catch2 release.

The theme switch no longer freezes or flickers. The layout rendered
data-theme="light" on &lt;html&gt;, so every server re-render of the layout
(a language switch) set it back. The control also applied the theme in
an effect after the render while buttons animated their colours. The
attribute now belongs to the bootstrap script and the control alone; the
control applies the theme in the click, and transitions are off for the
two frames of the change.

All new text is in en-US, de-DE, ru-RU and he-IL. The old home messages
leave localization.ts. The proxy maps the new hosts through one table, and
nginx gains their virtual hosts.
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
progmasoft.com presents Progmasoft as a pool of technology areas instead
of a list of products: languages and compilers, build and packages,
developer tools, quality and testing, identity and access, and
infrastructure. The page has a new hero, a bento of areas, principles and
a developers band that leads to the Progmasoft Console; the products are
one link away in their own catalog.

product.progmasoft.com lists Tala, talac, talafmt, talalint, Tazel, Xide
and Catch3, each with its own page (/tala-lang, /talac, ...) that leads
to the product's site and source. ides.progmasoft.com lists the IDEs and
hosts the Xide site at /xide; catch3.progmasoft.com is the Catch3 site.
The facts follow the READMEs and documentation of the product
repositories: Xide is marked as early work, and Catch3 states that it is
not an official Catch2 release.

The theme switch no longer freezes or flickers. The layout rendered
data-theme="light" on &lt;html&gt;, so every server re-render of the layout
(a language switch) set it back. The control also applied the theme in
an effect after the render while buttons animated their colours. The
attribute now belongs to the bootstrap script and the control alone; the
control applies the theme in the click, and transitions are off for the
two frames of the change.

All new text is in en-US, de-DE, ru-RU and he-IL. The old home messages
leave localization.ts. The proxy maps the new hosts through one table, and
nginx gains their virtual hosts.
</pre>
</div>
</content>
</entry>
<entry>
<title>Move the OAuth pages to Next.js and split the authorize host and the console</title>
<updated>2026-10-23T08:02:39+00:00</updated>
<author>
<name>Leitwolf11</name>
</author>
<published>2026-10-23T08:02:39+00:00</published>
<link rel='alternate' type='text/html' href='https://git.progmasoft.com/progmaweb/commit/?id=9099e9fbb50d27b622362b0c2f0dda5085d1fa03'/>
<id>9099e9fbb50d27b622362b0c2f0dda5085d1fa03</id>
<content type='text'>
Progmasoft OAuth now runs on three hosts:

- credentials.progmasoft.com stays the issuer: discovery documents, key
  set, token, user information, revocation and introspection.
- authorize.progmasoft.com serves the pages people see: the
  authorization and end session endpoints (registered with OpenIddict as
  absolute URIs on that host), sign-in, the consent screen and the
  applications an account has allowed.
- console.progmasoft.com is the Progmasoft Console. Its overview links
  the areas; OAuth 2.1 tokens live under /credentials, with New token,
  then the application type, then its form.

The console has no sign-in of its own and never redirects. It uses the
Progmasoft account session, so production now shares that cookie with
progmasoft.com (__Secure-ProgmasoftSession, Domain=progmasoft.com,
HttpOnly, Secure, SameSite=Lax). Without AccountSessions:CookieDomain the
cookie stays host-only with the __Host- name, as in development and tests.

Application types replace the confidential/public switch: web,
single-page, desktop, mobile and service. Each type has its redirection
rules (RFC 8252), its secret or none, and its grants; only a service
uses client credentials and it registers no address or scope. The type is
kept as an application property and cannot change.

The HTML pages of the API are gone. The pages are Next.js pages in four
languages (en-US, de-DE, ru-RU, he-IL) that call JSON endpoints under
/api/v1/oauth. Requests that change state must come from the page's own
origin; antiforgery forms are no longer needed. The token, revocation and
user information endpoints answer CORS requests from the origins of
single-page applications, without credentials; the discovery documents
and the key set answer every origin.

The host filter keeps every path on its host. Nginx gains the authorize
and console virtual hosts, and the docs describe the hosts, the types and
the shared session.
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Progmasoft OAuth now runs on three hosts:

- credentials.progmasoft.com stays the issuer: discovery documents, key
  set, token, user information, revocation and introspection.
- authorize.progmasoft.com serves the pages people see: the
  authorization and end session endpoints (registered with OpenIddict as
  absolute URIs on that host), sign-in, the consent screen and the
  applications an account has allowed.
- console.progmasoft.com is the Progmasoft Console. Its overview links
  the areas; OAuth 2.1 tokens live under /credentials, with New token,
  then the application type, then its form.

The console has no sign-in of its own and never redirects. It uses the
Progmasoft account session, so production now shares that cookie with
progmasoft.com (__Secure-ProgmasoftSession, Domain=progmasoft.com,
HttpOnly, Secure, SameSite=Lax). Without AccountSessions:CookieDomain the
cookie stays host-only with the __Host- name, as in development and tests.

Application types replace the confidential/public switch: web,
single-page, desktop, mobile and service. Each type has its redirection
rules (RFC 8252), its secret or none, and its grants; only a service
uses client credentials and it registers no address or scope. The type is
kept as an application property and cannot change.

The HTML pages of the API are gone. The pages are Next.js pages in four
languages (en-US, de-DE, ru-RU, he-IL) that call JSON endpoints under
/api/v1/oauth. Requests that change state must come from the page's own
origin; antiforgery forms are no longer needed. The token, revocation and
user information endpoints answer CORS requests from the origins of
single-page applications, without credentials; the discovery documents
and the key set answer every origin.

The host filter keeps every path on its host. Nginx gains the authorize
and console virtual hosts, and the docs describe the hosts, the types and
the shared session.
</pre>
</div>
</content>
</entry>
<entry>
<title>Add Progmasoft OAuth, an OAuth 2.1 and OpenID Connect provider</title>
<updated>2026-10-23T01:49:52+00:00</updated>
<author>
<name>Leitwolf11</name>
</author>
<published>2026-10-23T01:49:52+00:00</published>
<link rel='alternate' type='text/html' href='https://git.progmasoft.com/progmaweb/commit/?id=cffc8d884ce3620b70c80a9ab98b8f1f03887402'/>
<id>cffc8d884ce3620b70c80a9ab98b8f1f03887402</id>
<content type='text'>
Progmasoft accounts can now sign in to any application, and any
developer can register one. The provider runs in the account API under
the Progmasoft.OAuth namespaces and answers on credentials.progmasoft.com.

Protocol: OpenIddict 7 (Apache-2.0) with its Entity Framework stores.
Authorization code with PKCE for every client, S256 only; refresh
tokens with rotation and no reuse leeway, so a replayed refresh token
revokes its chain; client credentials for confidential clients, without
account scopes. No implicit or password grant. Codes live 2 minutes,
access and identity tokens 15 minutes, refresh tokens 30 days. Signing
(RSA) and encryption keys are read from files in production and are
required there; other environments make keys per process.

Scopes, one grant each, as the consent page lists them: profile (the
account name), email (the sign-in address; email_verified is false,
since registration does not verify it), viget.packages.read,
viget.packages.publish and viget.packages.yank (access tokens for the
viget audience), and offline_access.

Pages, plain HTML without script, behind a content security policy that
allows the one stylesheet by digest: sign-in with the account password
(a cookie of its own, no account-site session), consent with the
application, its registering account and the return host, the developer
portal (register confidential or public clients, redirect address rules
from RFC 8252, scopes, client credentials, secret shown once and
rotatable, delete; 10 applications per account; other accounts'
applications are absent), and the applications an account has allowed,
with withdrawal that revokes their tokens. Forms carry antiforgery
tokens; return addresses stay on the host.

Storage: the oauth_* tables in the account database, created by a
numbered schema step like the account tables; the step is the script
Entity Framework generates for the model, and a test compares the two.
With the memory account store they live in a shared in-memory SQLite
database, which runs the bulk revocations the in-memory provider cannot.

A host filter keeps OAuth paths on the OAuth host and everything but
OAuth and /health off it. AllowedHosts names the new host, and a rate
limit policy covers the protocol endpoints and the portal. The Nginx
vhost for the host and the key set-up are in ops; docs/OAUTH.md is the
developer guide.

AccountService gains VerifyPasswordAsync, which LoginAsync now uses,
and FindAsync.

Verified: dotnet build with warnings as errors; dotnet test, 125 tests,
109 passed and 16 PostgreSQL tests skipped locally (CI runs them,
including a new one for the schema and refresh token chain revocation):
code flow with PKCE and the claims of each scope, single-use codes,
refresh rotation and reuse refusal, consent reuse and withdrawal, deny,
public client with a private-use scheme, client credentials, ViGet
audience by introspection, refusal without PKCE, of other flows and of
unpermitted scopes, unregistered redirect addresses, sign-in redirects
and prompt=none, the portal's address rules and ownership, secret
rotation, the page security policy, the host filter and the discovery
document.
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Progmasoft accounts can now sign in to any application, and any
developer can register one. The provider runs in the account API under
the Progmasoft.OAuth namespaces and answers on credentials.progmasoft.com.

Protocol: OpenIddict 7 (Apache-2.0) with its Entity Framework stores.
Authorization code with PKCE for every client, S256 only; refresh
tokens with rotation and no reuse leeway, so a replayed refresh token
revokes its chain; client credentials for confidential clients, without
account scopes. No implicit or password grant. Codes live 2 minutes,
access and identity tokens 15 minutes, refresh tokens 30 days. Signing
(RSA) and encryption keys are read from files in production and are
required there; other environments make keys per process.

Scopes, one grant each, as the consent page lists them: profile (the
account name), email (the sign-in address; email_verified is false,
since registration does not verify it), viget.packages.read,
viget.packages.publish and viget.packages.yank (access tokens for the
viget audience), and offline_access.

Pages, plain HTML without script, behind a content security policy that
allows the one stylesheet by digest: sign-in with the account password
(a cookie of its own, no account-site session), consent with the
application, its registering account and the return host, the developer
portal (register confidential or public clients, redirect address rules
from RFC 8252, scopes, client credentials, secret shown once and
rotatable, delete; 10 applications per account; other accounts'
applications are absent), and the applications an account has allowed,
with withdrawal that revokes their tokens. Forms carry antiforgery
tokens; return addresses stay on the host.

Storage: the oauth_* tables in the account database, created by a
numbered schema step like the account tables; the step is the script
Entity Framework generates for the model, and a test compares the two.
With the memory account store they live in a shared in-memory SQLite
database, which runs the bulk revocations the in-memory provider cannot.

A host filter keeps OAuth paths on the OAuth host and everything but
OAuth and /health off it. AllowedHosts names the new host, and a rate
limit policy covers the protocol endpoints and the portal. The Nginx
vhost for the host and the key set-up are in ops; docs/OAUTH.md is the
developer guide.

AccountService gains VerifyPasswordAsync, which LoginAsync now uses,
and FindAsync.

Verified: dotnet build with warnings as errors; dotnet test, 125 tests,
109 passed and 16 PostgreSQL tests skipped locally (CI runs them,
including a new one for the schema and refresh token chain revocation):
code flow with PKCE and the claims of each scope, single-use codes,
refresh rotation and reuse refusal, consent reuse and withdrawal, deny,
public client with a private-use scheme, client credentials, ViGet
audience by introspection, refusal without PKCE, of other flows and of
unpermitted scopes, unregistered redirect addresses, sign-in redirects
and prompt=none, the portal's address rules and ownership, secret
rotation, the page security policy, the host filter and the discovery
document.
</pre>
</div>
</content>
</entry>
<entry>
<title>Treat progmasoft.com as an HSTS-preloaded domain</title>
<updated>2026-10-15T15:30:31+00:00</updated>
<author>
<name>Leitwolf11</name>
</author>
<published>2026-10-15T15:30:31+00:00</published>
<link rel='alternate' type='text/html' href='https://git.progmasoft.com/progmaweb/commit/?id=bd83e9e0fba03a4436e4fcfdde33c1e04d1a9c8f'/>
<id>bd83e9e0fba03a4436e4fcfdde33c1e04d1a9c8f</id>
<content type='text'>
.com has no HSTS requirement of its own, but progmasoft.com is served as
if it had one:

- Every HTTPS server block of progmasoft.com, www, account and viget
  sends max-age=63072000; includeSubDomains; preload. The www redirect
  sent none before.
- Plain HTTP only answers the ACME challenge and otherwise redirects to
  HTTPS, now with a permanent 308 instead of 301.
- The API's own HSTS policy, which it adds to HTTPS responses outside
  development, carries the same values, so a proxied response never
  shows two different policies. A test checks the header.
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
.com has no HSTS requirement of its own, but progmasoft.com is served as
if it had one:

- Every HTTPS server block of progmasoft.com, www, account and viget
  sends max-age=63072000; includeSubDomains; preload. The www redirect
  sent none before.
- Plain HTTP only answers the ACME challenge and otherwise redirects to
  HTTPS, now with a permanent 308 instead of 301.
- The API's own HSTS policy, which it adds to HTTPS responses outside
  development, carries the same values, so a proxied response never
  shows two different policies. A test checks the header.
</pre>
</div>
</content>
</entry>
<entry>
<title>Move the ViGet package and DSL-plugin catalogs into Progmaweb as host-aware Next.js routes, add complete en-US and German content, persistent light and dark themes, catalog-specific metadata, robots and sitemap responses, and an Nginx ownership contract for viget.progmasoft.com.</title>
<updated>2026-09-09T17:28:06+00:00</updated>
<author>
<name>Leitwolf11</name>
</author>
<published>2026-09-09T17:28:06+00:00</published>
<link rel='alternate' type='text/html' href='https://git.progmasoft.com/progmaweb/commit/?id=3f84eee09b08e354f3c61da11ac1a9e00ca5a8ea'/>
<id>3f84eee09b08e354f3c61da11ac1a9e00ca5a8ea</id>
<content type='text'>
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
</pre>
</div>
</content>
</entry>
<entry>
<title>Harden Progmaweb identity, localization, and operations</title>
<updated>2026-09-07T18:31:05+00:00</updated>
<author>
<name>Leitwolf11</name>
</author>
<published>2026-09-07T18:31:05+00:00</published>
<link rel='alternate' type='text/html' href='https://git.progmasoft.com/progmaweb/commit/?id=171b443addac11e07559b6c4127e622341fe1961'/>
<id>171b443addac11e07559b6c4127e622341fe1961</id>
<content type='text'>
Adopt Patent Grant 1.1, make the apex host canonical while excluding account surfaces from indexing, move the Progmasoft mail boundary into its owning repository, migrate the .NET 10 tests to native MTP, and add persistent light/dark and en-US/de-DE preferences across corporate and account experiences.
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Adopt Patent Grant 1.1, make the apex host canonical while excluding account surfaces from indexing, move the Progmasoft mail boundary into its owning repository, migrate the .NET 10 tests to native MTP, and add persistent light/dark and en-US/de-DE preferences across corporate and account experiences.
</pre>
</div>
</content>
</entry>
</feed>
