chore: settle the public domain and move off port 3000
The application is published at horaires.ita-ito.com. One origin serves both the panel and the browser, so the OIDC callback, the image URL the device is handed and the documentation all follow from this single name. Port 3000 is already taken by the facture_ocr stack on the development machine, so the app listens on 3010 there and the reason is written next to the setting rather than left to be rediscovered. The fixtures and the frozen payload snapshot move to the real domain too: a contract snapshot carrying a hostname that never existed is a small puzzle left for whoever reads it next. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012cSY9pVhZmJUKNN7wf1Myd
This commit is contained in:
+5
-3
@@ -9,8 +9,10 @@
|
||||
# Nom de domaine public de l'app sur le VPS. Un seul domaine sert à la fois
|
||||
# l'écran et le navigateur : le callback OIDC, l'URL d'image envoyée au panneau
|
||||
# et les liens du README en dépendent tous. Doit rester cohérent avec AUTH_URL.
|
||||
APP_DOMAIN=horaires.loxi.ch
|
||||
# Port publié en local (dev). En production, Traefik s'en charge : aucun port publié.
|
||||
APP_DOMAIN=horaires.ita-ito.com
|
||||
# Port publié sur l'hôte. 3000 est déjà pris par la stack facture_ocr sur la
|
||||
# machine de développement, d'où 3010 ; en production Traefik s'en charge et
|
||||
# aucun port n'est publié.
|
||||
APP_PORT=3010
|
||||
APP_BIND=127.0.0.1
|
||||
TZ=Europe/Zurich
|
||||
@@ -34,7 +36,7 @@ TEST_DATABASE_URL=
|
||||
#
|
||||
# URI de redirection à déclarer dans Authentik (correspondance stricte) :
|
||||
# <AUTH_URL>/api/auth/callback/authentik
|
||||
AUTH_URL=https://horaires.loxi.ch
|
||||
AUTH_URL=https://horaires.ita-ito.com
|
||||
# Générer avec : openssl rand -base64 33
|
||||
AUTH_SECRET=
|
||||
|
||||
|
||||
@@ -47,7 +47,7 @@ par deux chemins qui ne se croisent jamais.
|
||||
│ GET /api/device/image/<hash>.bmp ← non devinable, immuable, cacheable
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────┐
|
||||
│ Next.js 16 (App Router, TS strict) trmnl.loxi.ch │
|
||||
│ Next.js 16 (App Router, TS strict) horaires.ita-ito.com │
|
||||
│ │
|
||||
│ lib/schedule/resolver.ts ← pur, sans I/O, 100 % testé
|
||||
│ lib/screen/viewmodel.ts ← Prisma → ScreenPayload (schema 1)
|
||||
@@ -250,7 +250,7 @@ e2e/*.spec.ts ← Playwright
|
||||
| `GET /api/device/image/<hash>.bmp` | — | l'image, `Cache-Control: immutable` |
|
||||
|
||||
**Appairage** (README, pas de reflash) : maintenir le bouton ~5 s → portail captif → Wi-Fi →
|
||||
*Advanced > Custom Server > Yes* → `https://trmnl.loxi.ch` **sans slash final**.
|
||||
*Advanced > Custom Server > Yes* → `https://horaires.ita-ito.com` **sans slash final**.
|
||||
|
||||
`refresh_rate` adaptatif, calculé à chaque `/api/display` : `refreshRateOpenSec` (600) si la
|
||||
boutique est ouverte ou ouvre dans l'heure, `refreshRateClosedSec` (7200) sinon, et raccourci
|
||||
@@ -314,7 +314,7 @@ change pas, badge + bouton « Réessayer ».
|
||||
|
||||
```
|
||||
DATABASE_URL POSTGRES_USER / PASSWORD / DB
|
||||
APP_DOMAIN # ex. trmnl.loxi.ch — callback OIDC + image_url ← À CONFIRMER
|
||||
APP_DOMAIN # ex. horaires.ita-ito.com — callback OIDC + image_url ← À CONFIRMER
|
||||
NEXTAUTH_URL NEXTAUTH_SECRET
|
||||
AUTHENTIK_ISSUER # https://auth.loxi.ch/application/o/<SLUG>/ ← À CONFIRMER
|
||||
AUTHENTIK_CLIENT_ID AUTHENTIK_CLIENT_SECRET
|
||||
@@ -412,8 +412,8 @@ npm run lint && npm run typecheck && npm run test -- --coverage
|
||||
|
||||
# 3. Contrat d'affichage, sans appareil
|
||||
npm run screen:preview # → aperçu 800×480 dans le navigateur
|
||||
curl -s localhost:3000/api/display -H "Access-Token: <clé du seed>" | jq
|
||||
curl -s localhost:3000/api/device/image/<hash>.bmp -o /tmp/screen.bmp
|
||||
curl -s localhost:3010/api/display -H "Access-Token: <clé du seed>" | jq
|
||||
curl -s localhost:3010/api/device/image/<hash>.bmp -o /tmp/screen.bmp
|
||||
file /tmp/screen.bmp # attendu : PC bitmap, 800 x 480 x 1
|
||||
|
||||
# 4. Non-régression horaires (le test qui compte)
|
||||
@@ -431,7 +431,7 @@ du jour, une modification faite depuis un téléphone apparaît au réveil suiva
|
||||
|
||||
## Points à confirmer
|
||||
|
||||
1. **Domaine public** de l'app sur le VPS (`trmnl.loxi.ch` ?) — nécessaire au callback OIDC
|
||||
1. **Domaine public** de l'app sur le VPS (`horaires.ita-ito.com` ?) — nécessaire au callback OIDC
|
||||
et à l'`image_url` servie à l'appareil.
|
||||
2. **Slug de l'application Authentik** et **nom du groupe admin**.
|
||||
3. **Clé API `llk_…`** pour `api.loxi.ch`, et confirmation que l'instance est bien joignable
|
||||
|
||||
+1
-1
@@ -29,7 +29,7 @@ export function publicBaseUrl(request?: Request): string {
|
||||
return domain.startsWith('http') ? domain.replace(/\/$/, '') : `https://${domain}`;
|
||||
}
|
||||
|
||||
return 'http://localhost:3000';
|
||||
return 'http://localhost:3010';
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -8,7 +8,7 @@ exports[`buildScreenPayload > matches the frozen payload contract 1`] = `
|
||||
"text_fr": "Fermeture exceptionnelle jeudi après-midi",
|
||||
},
|
||||
"generated_at": "2026-09-22T12:00:00+02:00",
|
||||
"logo_url": "https://trmnl.loxi.ch/brand/logo-eink.png",
|
||||
"logo_url": "https://horaires.ita-ito.com/brand/logo-eink.png",
|
||||
"schema": 1,
|
||||
"shop_name": "ITA ITO",
|
||||
"today": {
|
||||
|
||||
@@ -9,7 +9,7 @@ const PAYLOAD: ScreenPayload = {
|
||||
schema: 1,
|
||||
generated_at: '2026-09-22T12:00:00+02:00',
|
||||
shop_name: 'ITA ITO',
|
||||
logo_url: 'https://trmnl.loxi.ch/brand/logo-eink.png',
|
||||
logo_url: 'https://horaires.ita-ito.com/brand/logo-eink.png',
|
||||
today: {
|
||||
date_fr: 'Mardi 22 septembre',
|
||||
date_en: 'Tuesday 22 September',
|
||||
|
||||
@@ -37,7 +37,7 @@ function input(overrides: Partial<Parameters<typeof buildScreenPayload>[0]> = {}
|
||||
now: new Date('2026-09-22T10:00:00Z'),
|
||||
ctx: context(),
|
||||
shopName: 'ITA ITO',
|
||||
logoUrl: 'https://trmnl.loxi.ch/brand/logo-eink.png',
|
||||
logoUrl: 'https://horaires.ita-ito.com/brand/logo-eink.png',
|
||||
messages: [] as MessageCandidate[],
|
||||
...overrides,
|
||||
};
|
||||
|
||||
+1
-1
@@ -9,7 +9,7 @@
|
||||
"scripts": {
|
||||
"dev": "next dev --port 3010",
|
||||
"build": "next build",
|
||||
"start": "next start",
|
||||
"start": "next start --port ${PORT:-3010}",
|
||||
"lint": "eslint . --max-warnings 0",
|
||||
"typecheck": "tsc --noEmit",
|
||||
"test": "vitest run",
|
||||
|
||||
+1
-1
@@ -61,7 +61,7 @@ function payload(): ScreenPayload {
|
||||
now: new Date('2026-09-23T10:30:00Z'),
|
||||
ctx: CONTEXT,
|
||||
shopName: 'ITA ITO',
|
||||
logoUrl: 'https://trmnl.loxi.ch/brand/logo-eink.png',
|
||||
logoUrl: 'https://horaires.ita-ito.com/brand/logo-eink.png',
|
||||
messages: [
|
||||
{
|
||||
textFr: 'Fermeture exceptionnelle jeudi matin',
|
||||
|
||||
Reference in New Issue
Block a user