feat: Web Push 비활성 운영 설정을 준비한다

VAPID private key를 Compose secret으로 주입하고 Web Push를 기본 비활성으로 전달한다. 활성화 입력과 Compose 모델 검증, 운영 README를 함께 추가한다.
This commit is contained in:
2026-08-23 13:16:21 +00:00
parent 0c2b9632eb
commit 663e66b8f9
10 changed files with 129 additions and 2 deletions
+14
View File
@@ -49,6 +49,20 @@ export const validateComposeModel = (model, mode) => {
if (!artifactMount || artifactMount.read_only === true) {
errors.push('/srv/frontend-artifacts must be a writable runtime volume');
}
if (!['true', 'false'].includes(runtime.environment?.WEB_PUSH_ENABLED)) {
errors.push('WEB_PUSH_ENABLED must be literal true or false');
}
if (runtime.environment?.WEB_PUSH_VAPID_PRIVATE_KEY_FILE !== '/run/secrets/web_push_vapid_private_key') {
errors.push('WEB_PUSH_VAPID_PRIVATE_KEY_FILE must use the mounted Compose secret');
}
const webPushSecret = (Array.isArray(runtime.secrets) ? runtime.secrets : []).find(
(candidate) => candidate?.target === '/run/secrets/web_push_vapid_private_key',
);
if (!webPushSecret) errors.push('the VAPID private key must be mounted as a runtime secret');
if (runtime.environment?.WEB_PUSH_ENABLED === 'true') {
if (!runtime.environment?.WEB_PUSH_VAPID_SUBJECT) errors.push('WEB_PUSH_VAPID_SUBJECT must be configured');
if (!runtime.environment?.WEB_PUSH_VAPID_PUBLIC_KEY) errors.push('WEB_PUSH_VAPID_PUBLIC_KEY must be configured');
}
const caddyArtifactMount = (Array.isArray(caddy?.volumes) ? caddy.volumes : []).find(
(candidate) => candidate?.target === '/srv/frontend-artifacts',
);
+19
View File
@@ -108,6 +108,25 @@ export const validateEnvironment = (env) => {
errors.push('CORE_SSH_KNOWN_HOSTS_BASE64 must contain valid base64-encoded known_hosts data');
}
const webPushEnabled = env.WEB_PUSH_ENABLED?.trim() === 'true';
if (env.WEB_PUSH_ENABLED && !['true', 'false'].includes(env.WEB_PUSH_ENABLED.trim())) {
errors.push('WEB_PUSH_ENABLED must be true or false');
}
if (webPushEnabled) {
const subject = env.WEB_PUSH_VAPID_SUBJECT?.trim() ?? '';
const publicKey = env.WEB_PUSH_VAPID_PUBLIC_KEY?.trim() ?? '';
const privateKeyFile = env.WEB_PUSH_VAPID_PRIVATE_KEY_FILE?.trim() ?? '';
if (!/^(?:mailto:|https:\/\/)/i.test(subject) || isPlaceholder(subject)) {
errors.push('WEB_PUSH_VAPID_SUBJECT must be a non-placeholder mailto: or HTTPS contact');
}
if (!publicKey || isPlaceholder(publicKey)) {
errors.push('WEB_PUSH_VAPID_PUBLIC_KEY is required when Web Push is enabled');
}
if (!privateKeyFile || isPlaceholder(privateKeyFile) || privateKeyFile.endsWith('.example')) {
errors.push('WEB_PUSH_VAPID_PRIVATE_KEY_FILE is required when Web Push is enabled');
}
}
return errors;
};