<feed xmlns='http://www.w3.org/2005/Atom'>
<title>progmaweb/ops/README.md, branch feature/oauth-application-types</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>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>Return a failed Google callback to sign-in and correct stale statements</title>
<updated>2026-10-16T03:00:57+00:00</updated>
<author>
<name>Leitwolf11</name>
</author>
<published>2026-10-16T03:00:57+00:00</published>
<link rel='alternate' type='text/html' href='https://git.progmasoft.com/progmaweb/commit/?id=bc653270652c1ab44d2144ddd17ae49b404e7cd2'/>
<id>bc653270652c1ab44d2144ddd17ae49b404e7cd2</id>
<content type='text'>
A Google callback that could not finish ended in an unhandled 500: a
visitor who declined on Google's consent screen, a callback whose state
cookie had expired, and a direct request to the callback path all got an
empty error page. The account API document already promised a redirect
to /login?google=failed for a failed callback; the handler of the Google
scheme now does that through OnRemoteFailure. Three new tests cover a
callback without state, a declined consent and a forged state.

Three statements no longer matched the sites:

- the bug report template still named the catalog paths without the
  language and the build system; they are /langs/tala/&lt;Publisher&gt;/&lt;Name&gt;/
  and /dslplugins/tazel/&lt;Publisher&gt;/&lt;Name&gt;/;
- the operations guide placed Tala content on xsharp-lang.xyz, which only
  redirects to tala.run now;
- the architecture guide described the ViGet routing before the catalogs
  per language and build system: it now gives the rewrites of /langs/tala
  and /dslplugins/tazel, the redirects of /langs and /dslplugins, three
  indexed ViGet pages and a sitemap with the home page and both catalogs.
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
A Google callback that could not finish ended in an unhandled 500: a
visitor who declined on Google's consent screen, a callback whose state
cookie had expired, and a direct request to the callback path all got an
empty error page. The account API document already promised a redirect
to /login?google=failed for a failed callback; the handler of the Google
scheme now does that through OnRemoteFailure. Three new tests cover a
callback without state, a declined consent and a forged state.

Three statements no longer matched the sites:

- the bug report template still named the catalog paths without the
  language and the build system; they are /langs/tala/&lt;Publisher&gt;/&lt;Name&gt;/
  and /dslplugins/tazel/&lt;Publisher&gt;/&lt;Name&gt;/;
- the operations guide placed Tala content on xsharp-lang.xyz, which only
  redirects to tala.run now;
- the architecture guide described the ViGet routing before the catalogs
  per language and build system: it now gives the rewrites of /langs/tala
  and /dslplugins/tazel, the redirects of /langs and /dslplugins, three
  indexed ViGet pages and a sitemap with the home page and both catalogs.
</pre>
</div>
</content>
</entry>
<entry>
<title>Call the language Tala on the Progmasoft and ViGet pages</title>
<updated>2026-10-12T03:19:10+00:00</updated>
<author>
<name>Leitwolf11</name>
</author>
<published>2026-10-12T03:19:10+00:00</published>
<link rel='alternate' type='text/html' href='https://git.progmasoft.com/progmaweb/commit/?id=b71e93b547e9f6425cc83b121f01e7d82b88079f'/>
<id>b71e93b547e9f6425cc83b121f01e7d82b88079f</id>
<content type='text'>
The language Visual X# is now Tala. The Progmasoft home page, the ViGet
pages, the dashboard and the two footers name it so in the four languages of
the site; the project file is BUILD.kts, and the source link leads to
Progmasoft/tala. The README, the operations and localization documents and
the issue templates follow.

The localization document said that a left-to-right mark follows the name of
the language in Hebrew text. That was for the `#` of the old name; the
sentence now speaks of names that end in a symbol.

The links to xsharp-lang.xyz stay: the language site is still served there.
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
The language Visual X# is now Tala. The Progmasoft home page, the ViGet
pages, the dashboard and the two footers name it so in the four languages of
the site; the project file is BUILD.kts, and the source link leads to
Progmasoft/tala. The README, the operations and localization documents and
the issue templates follow.

The localization document said that a left-to-right mark follows the name of
the language in Hebrew text. That was for the `#` of the old name; the
sentence now speaks of names that end in a symbol.

The links to xsharp-lang.xyz stay: the language site is still served there.
</pre>
</div>
</content>
</entry>
<entry>
<title>Keep accounts and sessions in PostgreSQL</title>
<updated>2026-10-06T19:53:46+00:00</updated>
<author>
<name>Leitwolf11</name>
</author>
<published>2026-10-06T19:53:46+00:00</published>
<link rel='alternate' type='text/html' href='https://git.progmasoft.com/progmaweb/commit/?id=1c986ff99b3c8f349e4a63c0e922276ddf7dc836'/>
<id>1c986ff99b3c8f349e4a63c0e922276ddf7dc836</id>
<content type='text'>
The account API kept everything in the memory of its process, so every
restart and every deployment of the API deleted all accounts and signed
everyone out.

PostgresAccountStore implements IAccountStore on PostgreSQL through Npgsql.
The three uniqueness rules are unique constraints, so two requests that race
for one name, address or Google identity are decided by the database. A
refused account is an ordinary answer, not an exception, and the rules are
reported in the order the in-memory store reports them. A session refers to
its account, and a session of an account that is not stored is refused; the
in-memory store now refuses it as well.

The schema is a list of numbered steps. The service takes the missing ones
when it starts, in one transaction under an advisory lock, and does not
start when the database cannot be reached or is newer than the release.
/health answers 503 while the database does not answer.

ConnectionStrings:Accounts selects PostgreSQL. A production service that is
given no database does not start; keeping accounts in memory there has to
be asked for with Accounts:Store=Memory. Development and the tests keep the
in-memory store by default.

The store gains RemoveExpiredSessionsAsync, and a background service calls
it at the start and once an hour: a session whose token is never presented
again no longer keeps its row for ever.

PostgreSQL keeps a timestamp to the microsecond. The store cuts a moment to
that precision and returns what it stored, and the service uses the
returned account, so the creation time in the registration response equals
the one every later read returns.

Tests. AccountStoreContractTests states the rules once and runs them on
both stores. Further tests cover the schema steps applied concurrently and a
database that is too new, the choice of the store from the configuration,
the removal of expired sessions, and an account with its session surviving
a restart of the service over HTTP. The PostgreSQL tests read their
database from PROGMAWEB_TEST_POSTGRES and work in a schema of their own
each. Without the variable they are skipped; CI starts PostgreSQL 16 for
them, and a test fails the run when the variable is missing there.

Operations. ops/README.md describes the database: the Unix socket with peer
authentication, so that no password exists, the one-time preparation, and
rollback across a schema step. The service unit starts after PostgreSQL.
docs/LIMITATIONS.md no longer lists the in-memory store and now lists the
missing backup and the missing deletion of accounts.
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
The account API kept everything in the memory of its process, so every
restart and every deployment of the API deleted all accounts and signed
everyone out.

PostgresAccountStore implements IAccountStore on PostgreSQL through Npgsql.
The three uniqueness rules are unique constraints, so two requests that race
for one name, address or Google identity are decided by the database. A
refused account is an ordinary answer, not an exception, and the rules are
reported in the order the in-memory store reports them. A session refers to
its account, and a session of an account that is not stored is refused; the
in-memory store now refuses it as well.

The schema is a list of numbered steps. The service takes the missing ones
when it starts, in one transaction under an advisory lock, and does not
start when the database cannot be reached or is newer than the release.
/health answers 503 while the database does not answer.

ConnectionStrings:Accounts selects PostgreSQL. A production service that is
given no database does not start; keeping accounts in memory there has to
be asked for with Accounts:Store=Memory. Development and the tests keep the
in-memory store by default.

The store gains RemoveExpiredSessionsAsync, and a background service calls
it at the start and once an hour: a session whose token is never presented
again no longer keeps its row for ever.

PostgreSQL keeps a timestamp to the microsecond. The store cuts a moment to
that precision and returns what it stored, and the service uses the
returned account, so the creation time in the registration response equals
the one every later read returns.

Tests. AccountStoreContractTests states the rules once and runs them on
both stores. Further tests cover the schema steps applied concurrently and a
database that is too new, the choice of the store from the configuration,
the removal of expired sessions, and an account with its session surviving
a restart of the service over HTTP. The PostgreSQL tests read their
database from PROGMAWEB_TEST_POSTGRES and work in a schema of their own
each. Without the variable they are skipped; CI starts PostgreSQL 16 for
them, and a test fails the run when the variable is missing there.

Operations. ops/README.md describes the database: the Unix socket with peer
authentication, so that no password exists, the one-time preparation, and
rollback across a schema step. The service unit starts after PostgreSQL.
docs/LIMITATIONS.md no longer lists the in-memory store and now lists the
missing backup and the missing deletion of accounts.
</pre>
</div>
</content>
</entry>
<entry>
<title>Document the architecture, the account API, localization and limitations</title>
<updated>2026-10-03T15:18:50+00:00</updated>
<author>
<name>Leitwolf11</name>
</author>
<published>2026-10-03T15:18:50+00:00</published>
<link rel='alternate' type='text/html' href='https://git.progmasoft.com/progmaweb/commit/?id=ba237e5ce9f50cd9e586697417c1d636e3cd129c'/>
<id>ba237e5ce9f50cd9e586697417c1d636e3cd129c</id>
<content type='text'>
The repository had a README and two operations notes. This adds the
documents a contributor or operator needs and corrects what had gone stale.

New, under docs/:
- README.md: index of the documentation.
- ARCHITECTURE.md: the two processes, the three hosts, the host-aware
  routing rules, the account flow and the trust boundaries.
- ACCOUNT-API.md: every endpoint with its request, responses and errors,
  the field rules, the Google flow outcome by outcome, cookies, limits and
  configuration. The responses were checked against a locally running API.
- LOCALIZATION.md: the four languages, how a page picks one, the cookie,
  how Hebrew text is laid out, and how to add a language.
- DEVELOPMENT.md: requirements, local setup, checks, tests, what each CI
  workflow enforces, the audit exception and the DocFX project.
- LIMITATIONS.md: what is missing or temporary, with the consequence of
  each: the in-memory account store, unverified addresses, no mail, no
  password change, the ignored returnTo parameter, the legacy ViGet status
  route, and that the API answers 500 to everything while the Google
  settings are empty.

Updated:
- README.md: languages, a documentation section, the local API command
  with its port, and the DocFX check.
- ops/README.md: restarting the API deletes every account, how to release
  a frontend-only change without that restart, and lessons from past
  releases.
- ops/mail/README.md: a status note that the API does not send mail yet.
- The pull request template names all four languages.

No source file changes.

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>
The repository had a README and two operations notes. This adds the
documents a contributor or operator needs and corrects what had gone stale.

New, under docs/:
- README.md: index of the documentation.
- ARCHITECTURE.md: the two processes, the three hosts, the host-aware
  routing rules, the account flow and the trust boundaries.
- ACCOUNT-API.md: every endpoint with its request, responses and errors,
  the field rules, the Google flow outcome by outcome, cookies, limits and
  configuration. The responses were checked against a locally running API.
- LOCALIZATION.md: the four languages, how a page picks one, the cookie,
  how Hebrew text is laid out, and how to add a language.
- DEVELOPMENT.md: requirements, local setup, checks, tests, what each CI
  workflow enforces, the audit exception and the DocFX project.
- LIMITATIONS.md: what is missing or temporary, with the consequence of
  each: the in-memory account store, unverified addresses, no mail, no
  password change, the ignored returnTo parameter, the legacy ViGet status
  route, and that the API answers 500 to everything while the Google
  settings are empty.

Updated:
- README.md: languages, a documentation section, the local API command
  with its port, and the DocFX check.
- ops/README.md: restarting the API deletes every account, how to release
  a frontend-only change without that restart, and lessons from past
  releases.
- ops/mail/README.md: a status note that the API does not send mail yet.
- The pull request template names all four languages.

No source file changes.

Co-Authored-By: Claude Opus 5.5 &lt;noreply@anthropic.com&gt;
</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>Make Progmaweb API activation SELinux-stable</title>
<updated>2026-09-07T22:29:57+00:00</updated>
<author>
<name>Leitwolf11</name>
</author>
<published>2026-09-07T22:29:57+00:00</published>
<link rel='alternate' type='text/html' href='https://git.progmasoft.com/progmaweb/commit/?id=41b6d47bd69e0545420612e1eebe9d01fb77be9e'/>
<id>41b6d47bd69e0545420612e1eebe9d01fb77be9e</id>
<content type='text'>
Invoke the framework-dependent API through the installed dotnet runtime instead of relying on a copied apphost inode retaining executable SELinux metadata. Document the production service contract so immutable releases activate consistently on the AlmaLinux host.
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Invoke the framework-dependent API through the installed dotnet runtime instead of relying on a copied apphost inode retaining executable SELinux metadata. Document the production service contract so immutable releases activate consistently on the AlmaLinux host.
</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>
<entry>
<title>Establish Progmasoft copyright ownership across the corporate website and account service, license all project-owned sources under AGPL-3.0-or-later, add the shared defensive Progmasoft patent grant with SPDX and REUSE coverage, preserve source-availability obligations, and align notices, npm and .NET package metadata, frontend, API, tests, deployment configuration, and repository documentation</title>
<updated>2026-08-29T08:01:02+00:00</updated>
<author>
<name>Leitwolf11</name>
</author>
<published>2026-08-29T08:01:02+00:00</published>
<link rel='alternate' type='text/html' href='https://git.progmasoft.com/progmaweb/commit/?id=c8073a82bbc8d39d8a45334bdcd969d00a3c3f1c'/>
<id>c8073a82bbc8d39d8a45334bdcd969d00a3c3f1c</id>
<content type='text'>
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
</pre>
</div>
</content>
</entry>
</feed>
