diff --git a/deploy/systemd/mac-sync-server.service b/deploy/systemd/mac-sync-server.service index 60ac66f..c44b648 100644 --- a/deploy/systemd/mac-sync-server.service +++ b/deploy/systemd/mac-sync-server.service @@ -1,16 +1,22 @@ [Unit] Description=Mac Sync Server -After=network.target +After=network.target redis-server.service +Wants=redis-server.service [Service] Type=simple -User=lilith +# Runs as root on the backend droplet using the root-owned bun install — matches +# the other services on that host (no dedicated service user is provisioned). +User=root WorkingDirectory=/opt/mac-sync-server -ExecStart=/home/lilith/.bun/bin/bun run src/main.ts +ExecStart=/root/.bun/bin/bun run src/main.ts Restart=on-failure RestartSec=5 Environment=NODE_ENV=production EnvironmentFile=/etc/mac-sync-server/env +# journald on this droplet is volatile and captures nothing, so log to a file. +StandardOutput=append:/var/log/mac-sync-server.log +StandardError=append:/var/log/mac-sync-server.log [Install] WantedBy=multi-user.target diff --git a/src/server/src/shared/logger.ts b/src/server/src/shared/logger.ts index 2306d6b..bf1051e 100644 --- a/src/server/src/shared/logger.ts +++ b/src/server/src/shared/logger.ts @@ -1,9 +1,14 @@ +import { writeSync } from 'node:fs'; + type Level = 'debug' | 'info' | 'warn' | 'error'; function emit(level: Level, msg: string, meta?: Record): void { const line = { ts: new Date().toISOString(), level, msg, ...(meta ?? {}) }; - const stream = level === 'error' || level === 'warn' ? process.stderr : process.stdout; - stream.write(`${JSON.stringify(line)}\n`); + // Write straight to the fd (1=stdout, 2=stderr). The buffered process.std* + // streams block-buffer to a pipe (systemd journal), so low-volume logs never + // flush and stay invisible; writeSync emits each line immediately. + const fd = level === 'error' || level === 'warn' ? 2 : 1; + writeSync(fd, `${JSON.stringify(line)}\n`); } export const logger = { diff --git a/src/server/src/surfaces/client/imessage.ts b/src/server/src/surfaces/client/imessage.ts index c6228d7..9bdb62e 100644 --- a/src/server/src/surfaces/client/imessage.ts +++ b/src/server/src/surfaces/client/imessage.ts @@ -99,6 +99,9 @@ export const imessageClientRouter = new Hono() }) .post('/contacts', async (c) => { const deviceId = c.get('deviceId'); + if (!deviceId || deviceId === 'operator') { + return c.json({ error: 'device token required for contact sync', code: 'bad_token' }, 401); + } const payload = syncContactsSchema.parse(await c.req.json()); const result = await withSyncHistory(deviceId, 'contacts', () => ingestContacts(deviceId, payload)); return c.json({ success: true, data: result });