7 Commits

Author SHA1 Message Date
58248897db fix: lower CPU limit to 200m to fit rolling update within tenant quota
Some checks failed
Release / release (push) Failing after 7m23s
2026-04-30 00:19:18 +02:00
b42ded93f6 feat: add DEMO env var to seed demo data on startup
Some checks failed
Release / release (push) Failing after 7m24s
2026-04-29 23:05:05 +02:00
dcb4a92afd fix(deploy): use generic 'http' sectionName for HTTP→HTTPS redirect route 2026-04-29 22:19:51 +02:00
6b296460dd fix(ci): add context: . to Docker build-push step in release workflow
All checks were successful
Release / release (push) Successful in 4m7s
2026-04-29 21:48:06 +02:00
ee98d6844a fix(frontend): add @types/node, fix Playwright base.extend type in fixtures
Some checks failed
Release / release (push) Failing after 1m27s
2026-04-29 21:42:32 +02:00
bae4ff24ea fix(ci): run svelte-kit sync before pnpm check to generate .svelte-kit/tsconfig.json
Some checks failed
Release / release (push) Failing after 56s
2026-04-29 21:28:21 +02:00
03a1e70df3 fix(deploy): correct HTTPRoute parentRefs, cert-manager annotation, imagePullSecrets
Some checks failed
Release / release (push) Failing after 56s
- httproute.yaml: name=default namespace=nginx-gateway (was: itsh-gateway, no namespace)
- httproute.yaml: add cert-manager.io/cluster-issuer annotation for TLS cert issuance
- httproute.yaml: parameterise sectionNames and parentRefs through values
- deployment.yaml: render imagePullSecrets from values (itsh-registry pull secret)
- values.yaml: add parentRefs, annotations, httpRedirectSectionName, imagePullSecrets
2026-04-29 21:24:13 +02:00
10 changed files with 88 additions and 22 deletions

View File

@@ -46,6 +46,9 @@ jobs:
- name: Install frontend deps
run: pnpm --dir frontend install --frozen-lockfile
- name: Generate SvelteKit types
run: pnpm --dir frontend exec svelte-kit sync
- name: Install Playwright browsers
run: pnpm --dir frontend exec playwright install --with-deps chromium

View File

@@ -48,6 +48,9 @@ jobs:
- name: Install frontend deps
run: pnpm --dir frontend install --frozen-lockfile
- name: Generate SvelteKit types
run: pnpm --dir frontend exec svelte-kit sync
- name: Type check (frontend)
run: pnpm --dir frontend exec tsgo --version && pnpm --dir frontend check
@@ -70,6 +73,7 @@ jobs:
- name: Build and push image
uses: docker/build-push-action@v6
with:
context: .
push: true
tags: |
${{ env.IMAGE }}:${{ github.ref_name }}

View File

@@ -13,6 +13,17 @@ pub async fn init() -> Result<SqlitePool, sqlx::Error> {
Ok(pool)
}
pub async fn maybe_seed_demo(pool: &SqlitePool) {
if std::env::var("DEMO").as_deref() != Ok("true") {
return;
}
let seed = include_str!("../demo/demo_seed.sql");
match sqlx::raw_sql(seed).execute(pool).await {
Ok(_) => tracing::info!("DEMO seed applied"),
Err(e) => tracing::warn!("DEMO seed failed: {e}"),
}
}
#[cfg(test)]
mod tests {
use super::*;

View File

@@ -29,6 +29,7 @@ async fn main() {
}
let pool = db::init().await.expect("db init failed");
db::maybe_seed_demo(&pool).await;
let static_dir = std::env::var("STATIC_DIR")
.unwrap_or_else(|_| "../frontend/build".into());

View File

@@ -16,6 +16,10 @@ spec:
{{- include "tutortool.selectorLabels" . | nindent 8 }}
spec:
serviceAccountName: {{ include "tutortool.serviceAccountName" . }}
{{- with .Values.imagePullSecrets }}
imagePullSecrets:
{{- toYaml . | nindent 8 }}
{{- end }}
securityContext:
fsGroup: 1000
containers:
@@ -29,6 +33,10 @@ spec:
value: {{ .Values.env.DATABASE_URL | quote }}
- name: STATIC_DIR
value: {{ .Values.env.STATIC_DIR | quote }}
{{- range $k, $v := .Values.env.extra }}
- name: {{ $k }}
value: {{ $v | quote }}
{{- end }}
- name: JWT_SECRET
valueFrom:
secretKeyRef:

View File

@@ -5,10 +5,17 @@ metadata:
namespace: {{ .Release.Namespace }}
labels:
{{- include "tutortool.labels" . | nindent 4 }}
{{- with .Values.httpRoute.annotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
spec:
parentRefs:
- name: itsh-gateway
sectionName: {{ .Values.httpRoute.sectionName }}
{{- range .Values.httpRoute.parentRefs }}
- name: {{ .name }}
namespace: {{ .namespace }}
sectionName: {{ $.Values.httpRoute.sectionName }}
{{- end }}
hostnames:
{{- range .Values.httpRoute.hostnames }}
- {{ . | quote }}
@@ -31,8 +38,11 @@ metadata:
{{- include "tutortool.labels" . | nindent 4 }}
spec:
parentRefs:
- name: itsh-gateway
sectionName: http-tutor-puchstein-dev
{{- range .Values.httpRoute.parentRefs }}
- name: {{ .name }}
namespace: {{ .namespace }}
sectionName: {{ $.Values.httpRoute.httpRedirectSectionName }}
{{- end }}
hostnames:
{{- range .Values.httpRoute.hostnames }}
- {{ . | quote }}

View File

@@ -20,17 +20,26 @@ resources:
cpu: 50m
memory: 64Mi
limits:
cpu: 500m
cpu: 200m
memory: 256Mi
pvc:
storageClassName: hcloud-volumes
storage: 1Gi
imagePullSecrets:
- name: itsh-registry
httpRoute:
annotations:
cert-manager.io/cluster-issuer: letsencrypt-prod
parentRefs:
- name: default
namespace: nginx-gateway
hostnames:
- tutor.puchstein.dev
sectionName: https-tutor-puchstein-dev
httpRedirectSectionName: http
# JWT_SECRET provisioned as a pre-existing K8s Secret named here.
# Do not set jwtSecretValue in committed values — provision via kubectl manually.
@@ -39,6 +48,9 @@ jwtSecretName: tutortool-jwt
env:
DATABASE_URL: sqlite:/data/attendance.db
STATIC_DIR: /app/frontend/build
extra: {}
# extra:
# DEMO: "true" # seeds demo data on startup (idempotent, INSERT OR IGNORE)
vpa:
enabled: false

View File

@@ -13,6 +13,7 @@
},
"devDependencies": {
"@playwright/test": "^1.59.1",
"@types/node": "latest",
"@sveltejs/adapter-static": "latest",
"@sveltejs/kit": "latest",
"@sveltejs/vite-plugin-svelte": "latest",

View File

@@ -13,13 +13,16 @@ importers:
version: 1.59.1
'@sveltejs/adapter-static':
specifier: latest
version: 3.0.10(@sveltejs/kit@2.58.0(@sveltejs/vite-plugin-svelte@7.0.0(svelte@5.55.5)(vite@8.0.10))(svelte@5.55.5)(typescript@6.0.3)(vite@8.0.10))
version: 3.0.10(@sveltejs/kit@2.58.0(@sveltejs/vite-plugin-svelte@7.0.0(svelte@5.55.5)(vite@8.0.10(@types/node@25.6.0)))(svelte@5.55.5)(typescript@6.0.3)(vite@8.0.10(@types/node@25.6.0)))
'@sveltejs/kit':
specifier: latest
version: 2.58.0(@sveltejs/vite-plugin-svelte@7.0.0(svelte@5.55.5)(vite@8.0.10))(svelte@5.55.5)(typescript@6.0.3)(vite@8.0.10)
version: 2.58.0(@sveltejs/vite-plugin-svelte@7.0.0(svelte@5.55.5)(vite@8.0.10(@types/node@25.6.0)))(svelte@5.55.5)(typescript@6.0.3)(vite@8.0.10(@types/node@25.6.0))
'@sveltejs/vite-plugin-svelte':
specifier: latest
version: 7.0.0(svelte@5.55.5)(vite@8.0.10)
version: 7.0.0(svelte@5.55.5)(vite@8.0.10(@types/node@25.6.0))
'@types/node':
specifier: latest
version: 25.6.0
'@typescript/native-preview':
specifier: ^7.0.0-dev
version: 7.0.0-dev.20260428.1
@@ -34,7 +37,7 @@ importers:
version: 6.0.3
vite:
specifier: latest
version: 8.0.10
version: 8.0.10(@types/node@25.6.0)
packages:
@@ -223,6 +226,9 @@ packages:
'@types/estree@1.0.8':
resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==}
'@types/node@25.6.0':
resolution: {integrity: sha512-+qIYRKdNYJwY3vRCZMdJbPLJAtGjQBudzZzdzwQYkEPQd+PJGixUL5QfvCLDaULoLv+RhT3LDkwEfKaAkgSmNQ==}
'@types/trusted-types@2.0.7':
resolution: {integrity: sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==}
@@ -515,6 +521,9 @@ packages:
engines: {node: '>=14.17'}
hasBin: true
undici-types@7.19.2:
resolution: {integrity: sha512-qYVnV5OEm2AW8cJMCpdV20CDyaN3g0AjDlOGf1OW4iaDEx8MwdtChUp4zu4H0VP3nDRF/8RKWH+IPp9uW0YGZg==}
vite@8.0.10:
resolution: {integrity: sha512-rZuUu9j6J5uotLDs+cAA4O5H4K1SfPliUlQwqa6YEwSrWDZzP4rhm00oJR5snMewjxF5V/K3D4kctsUTsIU9Mw==}
engines: {node: ^20.19.0 || >=22.12.0}
@@ -678,15 +687,15 @@ snapshots:
dependencies:
acorn: 8.16.0
'@sveltejs/adapter-static@3.0.10(@sveltejs/kit@2.58.0(@sveltejs/vite-plugin-svelte@7.0.0(svelte@5.55.5)(vite@8.0.10))(svelte@5.55.5)(typescript@6.0.3)(vite@8.0.10))':
'@sveltejs/adapter-static@3.0.10(@sveltejs/kit@2.58.0(@sveltejs/vite-plugin-svelte@7.0.0(svelte@5.55.5)(vite@8.0.10(@types/node@25.6.0)))(svelte@5.55.5)(typescript@6.0.3)(vite@8.0.10(@types/node@25.6.0)))':
dependencies:
'@sveltejs/kit': 2.58.0(@sveltejs/vite-plugin-svelte@7.0.0(svelte@5.55.5)(vite@8.0.10))(svelte@5.55.5)(typescript@6.0.3)(vite@8.0.10)
'@sveltejs/kit': 2.58.0(@sveltejs/vite-plugin-svelte@7.0.0(svelte@5.55.5)(vite@8.0.10(@types/node@25.6.0)))(svelte@5.55.5)(typescript@6.0.3)(vite@8.0.10(@types/node@25.6.0))
'@sveltejs/kit@2.58.0(@sveltejs/vite-plugin-svelte@7.0.0(svelte@5.55.5)(vite@8.0.10))(svelte@5.55.5)(typescript@6.0.3)(vite@8.0.10)':
'@sveltejs/kit@2.58.0(@sveltejs/vite-plugin-svelte@7.0.0(svelte@5.55.5)(vite@8.0.10(@types/node@25.6.0)))(svelte@5.55.5)(typescript@6.0.3)(vite@8.0.10(@types/node@25.6.0))':
dependencies:
'@standard-schema/spec': 1.1.0
'@sveltejs/acorn-typescript': 1.0.9(acorn@8.16.0)
'@sveltejs/vite-plugin-svelte': 7.0.0(svelte@5.55.5)(vite@8.0.10)
'@sveltejs/vite-plugin-svelte': 7.0.0(svelte@5.55.5)(vite@8.0.10(@types/node@25.6.0))
'@types/cookie': 0.6.0
acorn: 8.16.0
cookie: 0.6.0
@@ -698,18 +707,18 @@ snapshots:
set-cookie-parser: 3.1.0
sirv: 3.0.2
svelte: 5.55.5
vite: 8.0.10
vite: 8.0.10(@types/node@25.6.0)
optionalDependencies:
typescript: 6.0.3
'@sveltejs/vite-plugin-svelte@7.0.0(svelte@5.55.5)(vite@8.0.10)':
'@sveltejs/vite-plugin-svelte@7.0.0(svelte@5.55.5)(vite@8.0.10(@types/node@25.6.0))':
dependencies:
deepmerge: 4.3.1
magic-string: 0.30.21
obug: 2.1.1
svelte: 5.55.5
vite: 8.0.10
vitefu: 1.1.3(vite@8.0.10)
vite: 8.0.10(@types/node@25.6.0)
vitefu: 1.1.3(vite@8.0.10(@types/node@25.6.0))
'@tybys/wasm-util@0.10.1':
dependencies:
@@ -720,6 +729,10 @@ snapshots:
'@types/estree@1.0.8': {}
'@types/node@25.6.0':
dependencies:
undici-types: 7.19.2
'@types/trusted-types@2.0.7': {}
'@typescript/native-preview-darwin-arm64@7.0.0-dev.20260428.1':
@@ -958,7 +971,9 @@ snapshots:
typescript@6.0.3: {}
vite@8.0.10:
undici-types@7.19.2: {}
vite@8.0.10(@types/node@25.6.0):
dependencies:
lightningcss: 1.32.0
picomatch: 4.0.4
@@ -966,10 +981,11 @@ snapshots:
rolldown: 1.0.0-rc.17
tinyglobby: 0.2.16
optionalDependencies:
'@types/node': 25.6.0
fsevents: 2.3.3
vitefu@1.1.3(vite@8.0.10):
vitefu@1.1.3(vite@8.0.10(@types/node@25.6.0)):
optionalDependencies:
vite: 8.0.10
vite: 8.0.10(@types/node@25.6.0)
zimmerframe@1.1.4: {}

View File

@@ -1,4 +1,4 @@
import { test as base, expect } from '@playwright/test';
import { test as base, expect, type Page } from '@playwright/test';
import * as fs from 'fs';
import * as path from 'path';
import { fileURLToPath } from 'url';
@@ -16,7 +16,7 @@ function getBaseURL(): string {
}
// Extends base test with a beforeEach that resets DB to clean seed state
export const test = base.extend<{ page: Parameters<Parameters<typeof base>[1]>[0]['page'] }>({
export const test = base.extend<{ page: Page }>({
page: async ({ page }, use) => {
const baseURL = getBaseURL();
const res = await page.request.post(`${baseURL}/__test__/reset`);