# AIPhone No・where Logicnoid Project — Backup / Restore Runbook

## 1. Purpose

This runbook defines backup and restore procedures for the AIPhone No・where Logicnoid production-near engine.

The objective is to preserve the operational engine, runtime state, audit receipts, public verification surface, OpenAPI contract, threat model, deployment documents, Nginx configuration, and systemd service unit.

## 2. Backup Scope

| Item | Path |
|---|---|
| Production env | /opt/gnx/aiphone-nowhere/.env.production |
| Engine source | /opt/gnx/aiphone-nowhere/engine/src/server.mjs |
| OpenAPI | /opt/gnx/aiphone-nowhere/engine/openapi/openapi.yaml |
| Runtime state | /opt/gnx/aiphone-nowhere/runtime/state.json |
| Audit log | /opt/gnx/aiphone-nowhere/runtime/audit.jsonl |
| Public surface | /opt/gnx/aiphone-nowhere/surface/public |
| Readiness gate | /opt/gnx/aiphone-nowhere/docs/production-readiness-gate.md |
| Threat model | /opt/gnx/aiphone-nowhere/docs/threat-model.md |
| Deployment guide | /opt/gnx/aiphone-nowhere/docs/deployment-guide.md |
| systemd unit | /etc/systemd/system/gnx-aiphone.service |
| Nginx config | /etc/nginx/conf.d/aiphone-nowhere.conf |

## 3. Backup Location

Backups are stored under:

/opt/gnx/aiphone-nowhere/backups/runtime

Backup artifacts:

- aiphone-backup-YYYYMMDD-HHMMSS.tar.gz
- aiphone-backup-YYYYMMDD-HHMMSS.sha256

The archive and manifest must remain chmod 600 because the archive includes production secrets.

## 4. Backup Command

Run:

/opt/gnx/aiphone-nowhere/engine/tools/backup-runtime.sh

Expected result:

- Backup archive is created.
- SHA256 manifest is created.
- sha256sum -c returns OK.

## 5. Backup Verification

Run:

LATEST_BACKUP="$(ls -t /opt/gnx/aiphone-nowhere/backups/runtime/aiphone-backup-*.tar.gz | head -1)"
LATEST_MANIFEST="${LATEST_BACKUP%.tar.gz}.sha256"
sha256sum -c "$LATEST_MANIFEST"

List archive contents:

tar -tzf "$LATEST_BACKUP" | sort

## 6. Restore Dry-run

Run:

LATEST_BACKUP="$(ls -t /opt/gnx/aiphone-nowhere/backups/runtime/aiphone-backup-*.tar.gz | head -1)"
/opt/gnx/aiphone-nowhere/engine/tools/restore-dry-run.sh "$LATEST_BACKUP"

Expected result:

- Restore dry-run integrity: PASS
- Restore required files: PASS
- Restore engine syntax: PASS

## 7. Full Restore Procedure

Use this procedure only during an actual restore event.

1. Stop the engine.

sudo systemctl stop gnx-aiphone

2. Create an emergency pre-restore backup if the filesystem is still readable.

/opt/gnx/aiphone-nowhere/engine/tools/backup-runtime.sh

3. Select the backup archive.

LATEST_BACKUP="$(ls -t /opt/gnx/aiphone-nowhere/backups/runtime/aiphone-backup-*.tar.gz | head -1)"

4. Verify integrity.

sha256sum -c "${LATEST_BACKUP%.tar.gz}.sha256"

5. Extract into a temporary directory.

RESTORE_TMP="$(mktemp -d)"
tar -xzf "$LATEST_BACKUP" -C "$RESTORE_TMP"

6. Restore product files.

sudo cp -a "$RESTORE_TMP/opt/gnx/aiphone-nowhere/.env.production" /opt/gnx/aiphone-nowhere/.env.production
sudo cp -a "$RESTORE_TMP/opt/gnx/aiphone-nowhere/engine/src/server.mjs" /opt/gnx/aiphone-nowhere/engine/src/server.mjs
sudo cp -a "$RESTORE_TMP/opt/gnx/aiphone-nowhere/engine/openapi/openapi.yaml" /opt/gnx/aiphone-nowhere/engine/openapi/openapi.yaml
sudo cp -a "$RESTORE_TMP/opt/gnx/aiphone-nowhere/runtime/state.json" /opt/gnx/aiphone-nowhere/runtime/state.json
sudo cp -a "$RESTORE_TMP/opt/gnx/aiphone-nowhere/runtime/audit.jsonl" /opt/gnx/aiphone-nowhere/runtime/audit.jsonl

7. Restore public files.

sudo cp -a "$RESTORE_TMP/opt/gnx/aiphone-nowhere/surface/public/." /opt/gnx/aiphone-nowhere/surface/public/

8. Restore docs.

sudo cp -a "$RESTORE_TMP/opt/gnx/aiphone-nowhere/docs/." /opt/gnx/aiphone-nowhere/docs/

9. Restore system files.

sudo cp -a "$RESTORE_TMP/etc/systemd/system/gnx-aiphone.service" /etc/systemd/system/gnx-aiphone.service
sudo cp -a "$RESTORE_TMP/etc/nginx/conf.d/aiphone-nowhere.conf" /etc/nginx/conf.d/aiphone-nowhere.conf

10. Restore permissions.

sudo chmod 600 /opt/gnx/aiphone-nowhere/.env.production
sudo chown -R ubuntu:ubuntu /opt/gnx/aiphone-nowhere

11. Validate syntax and configuration.

node --check /opt/gnx/aiphone-nowhere/engine/src/server.mjs
sudo nginx -t
sudo systemctl daemon-reload

12. Restart services.

sudo systemctl restart gnx-aiphone
sudo systemctl reload nginx

13. Verify service health.

curl -sS https://logicnoid.kr/health/ready | jq

14. Run full evidence-chain verification.

/tmp/aiphone-pass-check-https.sh

15. Run admin signed challenge verification.

/tmp/aiphone-admin-challenge-check.sh

## 8. Recovery Acceptance Criteria

| Gate | Required Result |
|---|---|
| Engine syntax | PASS |
| Nginx config | PASS |
| systemd active | PASS |
| HTTPS health | PASS |
| Full evidence chain | PASS |
| Admin Signed Challenge | PASS |
| Audit receipt retrieval | PASS |
| No raw MSISDN storage check | PASS |

## 9. Security Rules

- Backup archives include production secrets.
- Backup archives must not be copied to public web paths.
- Backup archives must remain chmod 600.
- Backup archives must not be emailed or sent through chat.
- .env.production must not be exposed.
- AIPHONE_SECRET_PEPPER must not be rotated without a migration plan.
- AIPHONE_ADMIN_SECRET must not be rotated without invalidating active admin sessions.
- Audit logs must be preserved during restore unless explicitly approved.

## 10. Non-claims

This runbook does not claim offsite backup automation is complete.

This runbook does not claim S3 Object Lock, KMS-backed backup encryption, or multi-region disaster recovery is complete.

Those remain production hardening candidates.

## 11. Current Status

Backup script: PASS

Backup archive creation: PASS

SHA256 manifest: PASS

Restore dry-run: PASS

Backup/Restore Runbook: PASS
