Read-only mirrors. Development, issues and pull requests are on GitHub.

summaryrefslogtreecommitdiffhomepage
path: root/Documents/OPERATIONS.md
blob: ce1a4ee2b6aa3eb43af095a97cd8be4e67d2f4a0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
<!-- SPDX-FileCopyrightText: 2026 Progmasoft <support@progmasoft.com> -->
<!-- SPDX-License-Identifier: AGPL-3.0-or-later WITH AdditionRef-Progmasoft-Patent-Grant-1.1 -->

# Tala website operations

This runbook covers only the language website, the documentation sites of the
compiler, the formatter and the linter, the redirect of the build system's former
site, and the not-yet-open forum page.
The account site, corporate site, and package service have their own repositories
and deployments. A redirect from an old package hostname is retained for
compatibility, but it does not make package functions part of this website.

## Route ownership

| Host and path | Owner | Current treatment |
| --- | --- | --- |
| `tala.run/`, `/docs/overview`, `/docs/getting-started`, `/docs/syntax` | Vue language site | Live |
| `talac.tala.run/docs/*` | Vue build, compiler documentation | Live |
| `tazel.tala.run/*` | Redirect | Permanent redirect to `tazel.net`, Tazel's own site: `/docs/commands` and `/docs/project-file` to `tazel.net/docs/reference/` with the same name, other `/docs/` paths to `tazel.net/docs`, the rest to the same path |
| `tala.run/api/v1/site` | ASP.NET Core language API | Live; the only proxied API path |
| `forum.tala.run/` | Static placeholder | Live; noindex |
| `www.tala.run` | Redirect | Permanent redirect to `tala.run` |
| `xsharp-lang.xyz`, `www`, `docs`, `spec` | Former domain | Permanent redirect to the same path of `tala.run` |
| `forum.xsharp-lang.xyz` | Former domain | Permanent redirect to `forum.tala.run` |
| `viget.xsharp-lang.xyz/*` | Legacy redirect | Permanent redirect to the package host |

tala.run has no ViGet host; the registry lives at `viget.progmasoft.com`.

The sites are served with `ops/nginx/tala.conf`. While it is switched to
`ops/nginx/tala-maintenance.conf`, the routes of the three sites answer 503 and
`/api/v1/site` is not exposed. One certificate, `/etc/letsencrypt/live/tala.run/`,
covers tala.run, www.tala.run, talac.tala.run, tazel.tala.run and forum.tala.run;
the former domain keeps its own certificates for its redirects.

Do not use a catch-all `/api/` proxy for this service. The production Nginx
configuration proxies exactly `/api/v1/site`; other `/api/` paths return 404.
The API process binds only to `127.0.0.1`, on port 5086 unless `PORT` says
otherwise; the checked-in systemd unit sets `PORT=5086`, matching the Nginx proxy.
Its `/health` endpoint is for local process checks, not an advertised public
route.

## Local gates

Run the frontend checks from `frontend/`:

```text
npm ci
npm run check
npm run format:check
npm test
npm run build
```

Run the backend gates from the repository root with the .NET 10 SDK:

```text
dotnet restore Progmasoft.Tala.Website.slnx --locked-mode
dotnet build Progmasoft.Tala.Website.slnx --configuration Release --no-restore
dotnet test --project backend/Progmasoft.Tala.Website.Api.Tests/Progmasoft.Tala.Website.Api.Tests.csproj --configuration Release --no-build
dotnet publish backend/Progmasoft.Tala.Website.Api/Progmasoft.Tala.Website.Api.csproj --configuration Release --output publish
```

The build is the documentation gate: a public declaration without its
documentation comment fails it. Package versions are pinned in the
`packages.lock.json` of each project.

The frontend tests assert canonical metadata, sitemap membership, asset shape,
forum non-indexing, and the absence of retired site links. The API tests
assert site-only API behavior, health, read-only operation, and missing account
and registry routes. These gates are necessary but not a substitute for a
browser review of both themes, all four languages, and narrow screens.

## Asset checks

The source brand file is the supplied Tala SVG. The wide, transparent
composition is used in the hero. The leopard-only crop is used for favicon
and the small header mark so the animal remains legible at small sizes. The
social preview is a 1280 × 640 PNG with an intentional background. It is
separate from the Progmasoft corporate mark.

Before publication, verify that:

1. The leopard is not cropped at either its nose or lower outline.
2. The full wordmark is readable in the hero at desktop and mobile widths.
3. The light theme has adequate contrast, including links and focus rings.
4. The social PNG matches the approved Tala identity.
5. No page unintentionally uses a Progmasoft corporate logo.

## Link checks

All source links should target the current `Progmasoft/tala` default
branch. In particular, check the `Spec/`, `Documents/BUILDING.md`,
`Documents/CLI.md`, and `Examples/` targets after any repository move.
The routes of each site are listed in the route table above; tazel.tala.run answers each with a 308 to tazel.net. A retired login, registration, or package route must
not reappear in the site shell.

The forum placeholder links back to the language domain and to the compiler
repository. While the main domain is in maintenance, that home link may
intentionally lead to the maintenance response. Do not silently replace the
link with a different brand domain.

## Forum placeholder deployment

The forum is deliberately a static document. It has no form, identity flow,
post model, database, or discussion endpoint. It shows its notice in the
language of the browser and has a theme button; both work entirely in the
browser. The page and its server response both carry
noindex signals. The Nginx policy only allows same-origin CSS, JavaScript, and
images; it does not need `unsafe-inline`.

Files under `forum/` are deployed as a unit. Deploying `index.html` without
its version-matched `site.css`, `site.js`, and two SVG files can leave a
half-styled page or controls that no longer work. `index.html` refers to the
stylesheet and the script with a `?v=` value; change that value whenever either
file changes, because a CDN in front of the host can keep serving the old file,
or a cached "not found", for hours. The forum Nginx config
permits only those named static paths. After copying, restore SELinux labels,
validate the Nginx configuration, then reload Nginx. Do not turn SELinux off
to work around a labeling mistake.

Check the public URL for HTTP 200 and for these response properties:

- `X-Robots-Tag: noindex, nofollow`;
- Content Security Policy with same-origin script and style sources;
- `site.css`, `site.js`, and the leopard SVG returning HTTP 200;
- no login, registration, posting, or package UI;
- no language menu, and the notice in the language of the browser, English for
  a browser whose language has no translation; and
- a working light-mode control.

The forum can be deployed while the main language domain is in
maintenance. Opening the real forum later is a separate product decision.

## Releasing the main site

On the server the site lives in one directory:

```text
/srv/xsharp/website/
  current/
    frontend/     contents of frontend/dist
    forum/        the five forum files
    site-api/     the published ASP.NET Core API
    backend/      the legacy .NET process of Progmaweb's ViGet status route
  previous-<timestamp>/   the release before, kept for rollback
```

`current` is a real directory, not a symbolic link. A release replaces it by
renaming:

1. Build the frontend and publish the API from the commit being released, and
   run the local gates.
2. On the server, copy `current` to a new directory next to it with
   `cp -a`, which keeps owners, modes and SELinux labels, and replace the
   changed parts inside the copy. Unpack archives with `--no-same-owner` and
   run `chown -R root:root` on the replaced parts: an archive made on a
   developer machine carries that machine's user and group IDs, which name
   no account on the server, or a different one. Install Nginx and systemd
   files with LF line endings.
3. Start the new API on a free loopback port as the service user with
   `PORT=<port> dotnet site-api/Progmasoft.Tala.Website.Api.dll`, request
   `/health` and `/api/v1/site`, and stop it.
4. Rename `current` to `previous-<timestamp>` and the new directory to
   `current`.
5. Run `restorecon -R` on `current/frontend`, `current/forum` and
   `current/site-api`.
6. Restart the API service, then check the public routes from outside.

Step 5 has to come after step 4. The SELinux rules that let Nginx read the
files are bound to the paths below `current`. Run on a staging path,
`restorecon` gives the files the default label of that path, and Nginx then
answers 403 or 500 for every file. Do not switch SELinux to permissive to get
around a label.

A CDN in front of the host caches static files, `robots.txt` included, for
hours. After a release, a changed file at an unchanged URL can look stale from
outside while the server already has the new one; compare with a request made
on the server itself before concluding that a release failed.

## Maintenance mode

`ops/nginx/tala-maintenance.conf` answers the three sites with 503 and keeps
the legacy redirect working. `ops/nginx/tala.conf` serves them. Keep the
two mutually exclusive in the live Nginx include directory. Building the Vue
bundle or deploying the forum does not by itself authorize switching between
them.

Before switching the main site from maintenance to public:

1. Review the copy in every published language against the public language
   Spec and current compiler behavior.
2. Confirm the homepage actually answers why the language exists and does
   not describe planned compiler work as a finished feature.
3. Verify the three route bodies, both themes, keyboard focus, and responsive
   widths in a real browser.
4. Confirm all GitHub destinations and the forum link respond correctly.
5. Run both build/test sets shown above.
6. Install the Vue `dist/` contents at the static root named in the Nginx
   config, preserving file permissions and SELinux labels.
7. Test the published API on loopback with the shared ASP.NET Core 10 runtime
   before replacing the running API service.
8. Confirm the old service's unrelated status function has moved to the
   correct owner before retiring the old process.
9. Make one explicit Nginx configuration switch, run `nginx -t`, and reload.
10. Check the public routes and headers again from outside the server.

The API service is not required for the static homepage render. If it is
not ready, do not pretend it is ready by rewriting the API path. Delay the
rollout or explicitly publish static pages without the API after reviewing
the impact of that decision.

## Legacy redirect during maintenance

The redirect hostname is intentionally split from the maintenance vhost.
Requests to `viget.xsharp-lang.xyz` must produce 308 to
`https://viget.progmasoft.com` and preserve path and query string, also while
the sites answer 503. The redirect certificate
uses the existing SAN entry for the old hostname. Do not remove the redirect
in the course of cleaning up language-site copy.

The redirect is part of the site config as well. It is routing
compatibility, not a ViGet API or a user-facing section of the language site.

## Rollback

Keep the previous release directory until the checks after a release pass. A
rollback of a release renames `current` away and `previous-<timestamp>` back to
`current`, runs `restorecon -R` on `current/frontend` and `current/forum`, and
restarts the API service.

Keep the prior Nginx configuration as well. Taking the main site offline
returns its vhost to maintenance, checks `nginx -t`, reloads Nginx, and
confirms the expected 503. The forum and legacy redirect should remain
unaffected.

Do not roll back by deleting certificates, disabling SELinux, or pointing
unrelated hostnames at the language frontend. If the API process fails,
inspect its systemd journal and local `/health` response, then restore the
previous service unit or leave the site in maintenance until the owner
boundary is clear.

## Monitoring and privacy

The main language routes answer 200, and `/api/v1/site` returns only the
website's non-sensitive state. The three sites answer 200 only for files and
for the routes of the application, `/` and `/docs/<page>`; every other path,
such as a scanner's `/wp-login.php`, answers 404, with the application as
the body so that a visitor still reaches the landing page. Expected forum responses are 200 for the five
static files and 404 for other paths. Expected legacy redirect responses are
308. In maintenance mode the main domain answers 503 with `Retry-After`. A 200
from a retired login or registry route is a regression.

Neither the static site nor the forum placeholder should send personal data
to a third-party analytics service. The content security policy allows
same-origin scripts only, so a script added by an intermediary is blocked by
the browser rather than run. Theme and language preferences are kept
locally in the browser. Nginx and API logs still need normal retention
and access-control practices, but this repository does not define an account
database or a user profile store.

## Post-release review

After a release, perform the same checks from a clean browser profile with no
saved language or theme choice. Confirm that the theme is dark and that the
language is the browser's when it is one of the four, and English otherwise.
Choose another language in the menu, navigate through the documentation
routes of all three sites, and confirm the choice persists on each host; a
choice is kept per host, because the browser keeps storage per origin. Choose Hebrew and confirm that text
runs right to left while the layout and the code blocks stay as they are.
Switch to light mode and repeat. The forum keeps its own theme key and follows
the browser language; it should not change the main site's settings.

Inspect the page source as well as the rendered page. The initial HTML has
English home metadata; JavaScript updates metadata after route and locale
changes. If search indexing of documentation routes requires fully rendered
route-specific HTML without JavaScript, add a deliberate prerendering step
and test its output before claiming that capability. Do not assume that a
client-side title update alone proves crawler behavior.

Check the published source link and licensing files after deployment. The
source link must identify the version actually published, not a different
application's repository. Keep the public logo and third-party font notices
with the artifact. A successful HTTP response without the right assets,
copy, and license information is not a complete rollout.