apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: demo-sites-pvc
  namespace: home-apps
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 10Gi
  storageClassName: nfs-client
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: demo-service
  namespace: home-apps
  labels:
    app: demo-service
spec:
  replicas: 1
  selector:
    matchLabels:
      app: demo-service
  template:
    metadata:
      labels:
        app: demo-service
    spec:
      containers:
        - name: caddy
          image: mirror.gcr.io/caddy:2
          ports:
            - containerPort: 80
              name: http
          volumeMounts:
            - name: caddy-config
              mountPath: /etc/caddy/Caddyfile
              subPath: Caddyfile
            - name: demo-data
              mountPath: /data/demos
            - name: error-page
              mountPath: /app/static/error-page.html
              subPath: error-page.html
          resources:
            requests:
              memory: 32Mi
              cpu: 50m
            limits:
              memory: 128Mi
              cpu: 200m

        - name: api
          # Image is updated automatically by .github/workflows/build-demo-service.yml
          # on every push that changes home-apps/demo-service/**
          image: ghcr.io/wahyd4/demo-manager:git-8aabf71
          imagePullPolicy: Always
          ports:
            - containerPort: 3000
              name: api
          env:
            - name: DEMO_ROOT
              value: /data/demos
            - name: DEMO_API_KEY
              value: hermes-demo-secret-key-change-me
            - name: OAUTH_PROXY_URL
              value: https://pass.junv.cc
          volumeMounts:
            - name: demo-data
              mountPath: /data/demos
            - name: error-page
              mountPath: /app/error-page.html
              subPath: error-page.html
          resources:
            requests:
              memory: 64Mi
              cpu: 100m
            limits:
              memory: 256Mi
              cpu: 500m

      imagePullSecrets:
        - name: github-image-pull-secret

      volumes:
        - name: caddy-config
          configMap:
            name: demo-caddy-config
        - name: demo-data
          persistentVolumeClaim:
            claimName: demo-sites-pvc
        - name: error-page
          configMap:
            name: error-page-html
---
apiVersion: v1
kind: ConfigMap
metadata:
  name: error-page-html
  namespace: home-apps
data:
  error-page.html: |
    <!DOCTYPE html>
    <html lang="en">
    <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Unavailable</title>
    <style>
    *{margin:0;padding:0;box-sizing:border-box}
    body{font-family:-apple-system,BlinkMacSystemFont,"Segoe UI","Inter",sans-serif;background:#0b0f19;color:#8b949e;display:flex;align-items:center;justify-content:center;min-height:100vh;overflow:hidden}
    canvas{position:fixed;inset:0;z-index:0}
    .card{z-index:1;text-align:center;padding:48px 32px;max-width:420px}
    h1{font-size:26px;font-weight:600;color:#c9d1d9;margin-bottom:8px}
    p{font-size:14px;color:#6e7681;line-height:1.5}
    .login{margin-top:24px;display:inline-block;font-size:13px;color:#58a6ff;text-decoration:none;opacity:.7;transition:opacity .2s}
    .login:hover{opacity:1;text-decoration:underline}
    </style>
    </head>
    <body>
    <canvas id="c"></canvas>
    <div class="card">
      <h1>This page isn't available right now</h1>
      <p>Try again later.</p>
      <a class="login" id="loginLink" href="#">Log in</a>
    </div>
    <script>
    const c=document.getElementById('c'),x=c.getContext('2d');
    let w,h,particles=[];
    function resize(){w=c.width=innerWidth;h=c.height=innerHeight}
    resize();addEventListener('resize',resize);
    for(let i=0;i<50;i++)particles.push({
      x:Math.random()*w,y:Math.random()*h,r:Math.random()*2+1,
      vx:(Math.random()-.5)*.4,vy:(Math.random()-.5)*.4,
      a:Math.random()*.3+.1,h:Math.random()*360
    });
    function draw(t){
      x.clearRect(0,0,w,h);
      for(let p of particles){
        p.x+=p.vx;p.y+=p.vy;
        if(p.x<0)p.x=w;if(p.x>w)p.x=0;
        if(p.y<0)p.y=h;if(p.y>h)p.y=0;
        p.h=(p.h+.1)%360;
        x.beginPath();x.arc(p.x,p.y,p.r,0,Math.PI*2);
        x.fillStyle='hsla('+p.h+',60%,65%,'+p.a+')';x.fill();
      }
      for(let i=0;i<particles.length;i++){
        for(let j=i+1;j<particles.length;j++){
          const dx=particles[i].x-particles[j].x,dy=particles[i].y-particles[j].y,d=Math.sqrt(dx*dx+dy*dy);
          if(d<120){
            x.beginPath();x.moveTo(particles[i].x,particles[i].y);x.lineTo(particles[j].x,particles[j].y);
            x.strokeStyle='rgba(88,166,255,'+(.06*(1-d/120))+')';x.lineWidth=.5;x.stroke();
          }
        }
      }
      requestAnimationFrame(draw);
    }
    draw();
    document.getElementById('loginLink').addEventListener('click',function(e){
      e.preventDefault();
      location.href='https://pass.junv.cc/oauth2/start?rd='+encodeURIComponent(location.href);
    });
    </script>
    </body>
    </html>
---
apiVersion: v1
kind: Service
metadata:
  name: demo-service
  namespace: home-apps
spec:
  selector:
    app: demo-service
  ports:
    - port: 80
      targetPort: 80
      name: http
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: demo-service-ingress
  namespace: home-apps
  annotations:
    cert-manager.io/cluster-issuer: letsencrypt-prod
    kubernetes.io/tls-acme: "true"
spec:
  ingressClassName: nginx
  tls:
    - hosts:
        - demo.junv.cc
      secretName: demo-service-tls
  rules:
    - host: demo.junv.cc
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: demo-service
                port:
                  number: 80
