fix: release v0.2.1 lesson deletes and large uploads

- Raise Traefik read timeout to 1h (compose dev/prod + k3s HelmChartConfig)
  so admin video uploads up to 200MB no longer 502 mid-upload.
- Migration 0029: cascade watch/quiz history on lesson delete and unlink
  dependent lessons, so removing a lesson or chapter stops 500ing.
- Add the Apollo cluster Helm overlay (values-apollo.yaml) for the deployed
  environment.
- k3s Traefik chart config also enables access logs, cross-namespace
  IngressRoutes, and fixes the Prometheus scrape port.

Bump appVersion/product.go/values tags to 0.2.1; chart version 0.2.3.
This commit is contained in:
ahp
2026-10-16 09:44:23 +03:30
parent 22d92c133d
commit 533cee7e9d
9 changed files with 163 additions and 7 deletions
+1 -1
View File
@@ -10,7 +10,7 @@
</p> </p>
<p align="center"> <p align="center">
<a href="https://github.com/Panahifarah/pargar/releases/tag/v0.2.0"><img src="https://img.shields.io/github/v/tag/Panahifarah/pargar?label=release&color=5B4CDB" alt="release" /></a> <a href="https://github.com/Panahifarah/pargar/releases/tag/v0.2.1"><img src="https://img.shields.io/github/v/tag/Panahifarah/pargar?label=release&color=5B4CDB" alt="release" /></a>
<a href="LICENSE"><img src="https://img.shields.io/badge/license-AGPL--3.0-5B4CDB" alt="AGPL-3.0" /></a> <a href="LICENSE"><img src="https://img.shields.io/badge/license-AGPL--3.0-5B4CDB" alt="AGPL-3.0" /></a>
</p> </p>
+2 -2
View File
@@ -583,7 +583,7 @@ func (s *Server) handleMeta(w http.ResponseWriter, r *http.Request) {
} }
func appBuild() (version, built string) { func appBuild() (version, built string) {
version = "0.2.0" version = "0.2.1"
built = "dev" built = "dev"
info, ok := debug.ReadBuildInfo() info, ok := debug.ReadBuildInfo()
if !ok { if !ok {
@@ -594,7 +594,7 @@ func appBuild() (version, built string) {
built = setting.Value[:10] built = setting.Value[:10]
} }
if setting.Key == "vcs.revision" && len(setting.Value) >= 7 { if setting.Key == "vcs.revision" && len(setting.Value) >= 7 {
version = "0.2.0+" + setting.Value[:7] version = "0.2.1+" + setting.Value[:7]
} }
} }
return version, built return version, built
@@ -0,0 +1,26 @@
-- 0029_lesson_delete_cascades.sql
-- Make deleting a lesson (directly, or via its chapter) work cleanly.
--
-- Previously only mcq_questions cascaded; watch/quiz history blocked the delete
-- with a 500. Progress/history rows now go away with the lesson, while lessons
-- that merely *required* the deleted one are unlinked (never deleted).
ALTER TABLE watch_sessions DROP CONSTRAINT IF EXISTS watch_sessions_lesson_id_fkey;
ALTER TABLE watch_sessions ADD CONSTRAINT watch_sessions_lesson_id_fkey
FOREIGN KEY (lesson_id) REFERENCES lessons(id) ON DELETE CASCADE;
ALTER TABLE watch_heartbeats DROP CONSTRAINT IF EXISTS watch_heartbeats_lesson_id_fkey;
ALTER TABLE watch_heartbeats ADD CONSTRAINT watch_heartbeats_lesson_id_fkey
FOREIGN KEY (lesson_id) REFERENCES lessons(id) ON DELETE CASCADE;
ALTER TABLE lesson_progress DROP CONSTRAINT IF EXISTS lesson_progress_lesson_id_fkey;
ALTER TABLE lesson_progress ADD CONSTRAINT lesson_progress_lesson_id_fkey
FOREIGN KEY (lesson_id) REFERENCES lessons(id) ON DELETE CASCADE;
ALTER TABLE quiz_attempts DROP CONSTRAINT IF EXISTS quiz_attempts_lesson_id_fkey;
ALTER TABLE quiz_attempts ADD CONSTRAINT quiz_attempts_lesson_id_fkey
FOREIGN KEY (lesson_id) REFERENCES lessons(id) ON DELETE CASCADE;
ALTER TABLE lessons DROP CONSTRAINT IF EXISTS lessons_requires_lesson_id_fkey;
ALTER TABLE lessons ADD CONSTRAINT lessons_requires_lesson_id_fkey
FOREIGN KEY (requires_lesson_id) REFERENCES lessons(id) ON DELETE SET NULL;
+3
View File
@@ -63,6 +63,9 @@ services:
- --entrypoints.web.http.redirections.entrypoint.permanent=true - --entrypoints.web.http.redirections.entrypoint.permanent=true
- --entrypoints.web.http.aliasHeadersStrategy=delete - --entrypoints.web.http.aliasHeadersStrategy=delete
- --entrypoints.websecure.http.aliasHeadersStrategy=delete - --entrypoints.websecure.http.aliasHeadersStrategy=delete
# Allow slow, large uploads (admin video ≤ 200MB); default is 60s.
- --entrypoints.web.transport.respondingTimeouts.readTimeout=3600
- --entrypoints.websecure.transport.respondingTimeouts.readTimeout=3600
# Dev: Traefik default certificate (browser warning expected on localhost). # Dev: Traefik default certificate (browser warning expected on localhost).
- --api.dashboard=true - --api.dashboard=true
- --api.insecure=true - --api.insecure=true
+3
View File
@@ -71,6 +71,9 @@ services:
- --entrypoints.web.http.redirections.entrypoint.permanent=true - --entrypoints.web.http.redirections.entrypoint.permanent=true
- --entrypoints.web.http.aliasHeadersStrategy=delete - --entrypoints.web.http.aliasHeadersStrategy=delete
- --entrypoints.websecure.http.aliasHeadersStrategy=delete - --entrypoints.websecure.http.aliasHeadersStrategy=delete
# Allow slow, large uploads (admin video ≤ 200MB); default is 60s.
- --entrypoints.web.transport.respondingTimeouts.readTimeout=3600
- --entrypoints.websecure.transport.respondingTimeouts.readTimeout=3600
- --certificatesresolvers.le.acme.email=${ACME_EMAIL:?ACME_EMAIL must be set} - --certificatesresolvers.le.acme.email=${ACME_EMAIL:?ACME_EMAIL must be set}
- --certificatesresolvers.le.acme.storage=/data/acme.json - --certificatesresolvers.le.acme.storage=/data/acme.json
- --certificatesresolvers.le.acme.httpchallenge=true - --certificatesresolvers.le.acme.httpchallenge=true
+2 -2
View File
@@ -2,8 +2,8 @@ apiVersion: v2
name: pargar name: pargar
description: Pargar gated LMS - Go API, Next.js frontend, Postgres, Redis, S3-compatible storage description: Pargar gated LMS - Go API, Next.js frontend, Postgres, Redis, S3-compatible storage
type: application type: application
version: 0.2.2 version: 0.2.3
appVersion: "0.2.0" appVersion: "0.2.1"
keywords: keywords:
- lms - lms
- pargar - pargar
+81
View File
@@ -0,0 +1,81 @@
backend:
autoscaling:
enabled: false
env:
devMode: "false"
donationEnabled: "true"
otelEndpoint: http://tempo.infra.svc.cluster.local:4318
physicalCertEnabled: "false"
seedCurriculum: "false"
existingSecret: pargar-app
image:
pullPolicy: IfNotPresent
repository: pargar-backend
tag: 0.2.1
metrics:
serviceMonitor:
enabled: true
interval: 30s
podDisruptionBudget:
enabled: true
minAvailable: 1
replicaCount: 3
resources:
limits:
cpu: "1"
memory: 512Mi
requests:
cpu: 100m
memory: 128Mi
backup:
enabled: true
persistence:
size: 2Gi
retentionDays: 7
schedule: 0 3 * * *
certManager:
enabled: false
frontend:
autoscaling:
enabled: false
image:
pullPolicy: IfNotPresent
repository: pargar-frontend
tag: 0.2.1
podDisruptionBudget:
enabled: false
replicaCount: 2
resources:
limits:
cpu: "1"
memory: 512Mi
requests:
cpu: 100m
memory: 128Mi
global:
domain: pargar.panahifar.ir
frontendOrigins: https://pargar.panahifar.ir
imageRegistry: ""
publicUrl: https://pargar.panahifar.ir
imagePullSecrets: []
ingress:
enabled: true
tls:
enabled: true
existingSecret: pargar-wildcard-tls
useIngressRoute: true
networkPolicy:
enabled: false
postgres:
enabled: true
persistence:
size: 10Gi
redis:
enabled: true
persistence:
size: 2Gi
rustfs:
consoleEnable: false
enabled: true
persistence:
size: 20Gi
+2 -2
View File
@@ -22,7 +22,7 @@ backend:
replicaCount: 2 replicaCount: 2
image: image:
repository: backend repository: backend
tag: "0.2.0" tag: "0.2.1"
pullPolicy: IfNotPresent pullPolicy: IfNotPresent
existingSecret: pargar-app existingSecret: pargar-app
env: env:
@@ -49,7 +49,7 @@ frontend:
replicaCount: 2 replicaCount: 2
image: image:
repository: frontend repository: frontend
tag: "0.2.0" tag: "0.2.1"
pullPolicy: IfNotPresent pullPolicy: IfNotPresent
resources: resources:
requests: requests:
+43
View File
@@ -0,0 +1,43 @@
# k3s Traefik customisation (HelmChartConfig for the built-in `traefik` chart).
#
# Apply with: kubectl apply -f deploy/k3s/traefik-helmchartconfig.yaml
#
# Why: Traefik's entrypoint `readTimeout` defaults to 60s and covers reading the
# *entire request including the body*. Admin video uploads (up to 200MB) that take
# longer than 60s were cut off with a 502 before reaching the backend. Raise it to
# 1 hour (use 0 to disable entirely).
apiVersion: helm.cattle.io/v1
kind: HelmChartConfig
metadata:
name: traefik
namespace: kube-system
spec:
failurePolicy: reinstall
valuesContent: |-
# ACCESSLOG tile -> ON; access logs go to container stdout (kubectl logs).
# Key is logs.access.enabled on the chart k3s ships (40.1.5);
# the top-level accessLog.enabled only exists on newer chart versions.
logs:
access:
enabled: true
# Allow IngressRoutes to reference Services living in other namespaces,
# e.g. argocd-server in `argocd`.
providers:
kubernetesCRD:
allowCrossNamespace: true
deployment:
podAnnotations:
# fix: metrics entrypoint listens on :9100, annotation said 8082
prometheus.io/port: "9100"
prometheus.io/scrape: "true"
# Allow slow, large uploads (admin video upload ≤ 200MB) to finish.
# Default is 60s; 3600s = 1h. Set to 0 to disable the cap.
ports:
web:
transport:
respondingTimeouts:
readTimeout: 3600
websecure:
transport:
respondingTimeouts:
readTimeout: 3600