[Unit] Description=Curriculum Project Hub (Feishu agent + cph) After=network-online.target postgresql.service Wants=network-online.target # ADR-0018: refuse to start when the configured OS sandbox binary disappears # after installation. Deployment preflight validates the executable itself; # this start-time assertion keeps later package/host changes fail-closed. AssertPathExists=__BWRAP_BIN__ [Service] Type=simple User=__SERVICE_USER__ Group=__SERVICE_GROUP__ WorkingDirectory=__HUB_DIR__ EnvironmentFile=__ENV_FILE__ Environment=HOME=__SERVICE_HOME__ Environment=XDG_STATE_HOME=__STATE_DIR__ Environment=XDG_CACHE_HOME=__CACHE_DIR__ Environment=PATH=__RUNTIME_PATH__ UMask=0027 # Run prisma migrations before each start, then launch the Hub. ExecStartPre=__NODE_BIN__ __HUB_DIR__/node_modules/prisma/build/index.js migrate deploy --schema __HUB_DIR__/prisma/schema.prisma ExecStart=__NODE_BIN__ __HUB_DIR__/dist/server.js Restart=on-failure RestartSec=5 # Graceful shutdown: lark ws close + in-flight runs. KillSignal=SIGTERM TimeoutStopSec=30 # Hardening: no new privileges. ProtectSystem/ProtectHome are NOT set here — # they would break cph's render-cache extraction (~/.cache/cph/) and the # bwrap user-namespace setup. The OS-level sandbox (ADR-0018) is the hard # boundary; systemd hardening is kept minimal to avoid interfering with it. NoNewPrivileges=true [Install] WantedBy=multi-user.target