{"id":"IL-0577","org":"Ficilcom","date":"2026-09-25","docs":["https://neon.com/docs/introduction/history-window"],"title":{"en":"Ficilcom's production Neon PostgreSQL database was reset by prisma migrate reset meant for the local database","ko":"로컬 데이터베이스를 초기화하려던 prisma migrate reset 이 운영 Neon PostgreSQL 데이터베이스를 초기화했다"},"domain":["database"],"impact":{"scope":"The production database was reset and the service stopped for about an hour","users":"One customer's data was in the database; access logs showed almost no impact","region":"unknown"},"review":{"written_by":"session","reviewed_at":null,"reviewed_by":null},"lessons":{"en":"Memory after a long holiday cannot be trusted, so the state of unfinished work has to be written down instead. A destructive command should refuse to run when its target is not clearly local. That a backup feature exists does not mean the plan's history window is long enough, and the damage was small this time only because the service happened to be at an early stage.","ko":"글쓴이는 기억보다 기록을 믿어야 한다고 정리했다. 오래 손을 놓기 전에는 어중간한 상태를 남기지 않고, 남겨야 하면 메모로 적어 둔다. 데이터베이스를 지우는 명령은 접속 대상이 localhost 가 아니면 실행되지 않아야 한다. 운영 URL 은 개발자 컴퓨터에 두지 않고, AI 에이전트에도 금지 규칙을 둔다. Backup & Restore 는 기능이 있는지와 별도로, 쓰는 요금제의 기간으로 충분한지를 확인해야 한다. 글쓴이는 이번에 피해가 작았던 것은 서비스가 마침 초기였기 때문이라고 했다."},"related":[],"sources":[{"url":"https://zenn.dev/ficilcom/articles/prod_db_reset_incident","kind":"blog","archived":"https://web.archive.org/web/20260928051010/https://zenn.dev/ficilcom/articles/prod_db_reset_incident"}],"summary":{"en":"Ficilcom builds its product with Turborepo, Prisma and Neon (PostgreSQL). The database code lives in packages/database, and the same Prisma commands run against whatever the DATABASE_URL in that folder's .env points to, local or production; nothing guarded against this, and nothing checked that the URL was localhost before migrate reset. Before the holidays the engineer had run a migration against production and left the production DATABASE_URL in packages/database/.env. After the holidays the engineer did not remember this and ran the reset without checking, which reset the production database.\n\nThe engineer found Neon's Backup & Restore feature and used it to restore the database. On the Launch plan in use, the history window is 1 day by default and up to 7 days, and the history reached back one day, so the data could be recovered. The service was stopped for about an hour. The service was in its early launch phase with one customer's data, and access logs showed almost no impact.","ko":"Ficilcom 은 Turborepo, Prisma, Neon PostgreSQL 을 쓴다. 데이터베이스 관련 코드는 packages/database 에 모여 있고, 그 폴더의 .env 에 있는 DATABASE_URL 이 가리키는 곳이면 로컬이든 운영이든 같은 Prisma 명령이 실행된다. 이를 막는 장치는 없었고, migrate reset 전에 접속 대상이 localhost 인지 확인하는 처리도 없었다.\n\n엔지니어는 연휴 전에 운영 데이터베이스에 마이그레이션을 적용하고 운영 DATABASE_URL 을 .env 에 남긴 채 작업을 멈췄다. 연휴가 끝난 첫날 로컬 데이터베이스를 비우려고 prisma migrate reset 을 실행했고, 이 명령이 운영 데이터베이스를 초기화했다. 시드 데이터가 보이지 않는 것을 보고 실수를 알아챘다.\n\n엔지니어는 Neon 에서 백업을 찾았고 Backup & Restore 기능으로 데이터베이스를 되살렸다. Ficilcom 은 Neon 의 Launch 요금제를 쓰고 있어서 하루 전 시점까지 되돌릴 수 있었다. 서비스가 멈춘 시간은 1시간쯤이었다. 서비스 초기라 고객 데이터는 1건이었고, 접근 로그로 보면 영향은 거의 없었다."},"trigger":{"en":"The engineer ran prisma migrate reset believing it targeted the local database, while packages/database/.env still held the production DATABASE_URL left there from a production migration before the holidays.","ko":"엔지니어가 로컬 데이터베이스를 대상으로 한다고 믿고 prisma migrate reset 을 실행했는데, packages/database/.env 에 연휴 전에 넣어 둔 운영 DATABASE_URL 이 남아 있었다."},"severity":"unknown","symptoms":["data-loss"],"timeline":{"detected_after":null,"resolved_after":"1h"},"date_kind":"published","detection":{"en":"After the reset the engineer saw that the seed data did not seem to be present and realised the reset had hit production.","ko":"엔지니어가 prisma migrate reset 뒤에 넣은 시드 데이터가 로컬에 보이지 않는 것을 보고, 운영 데이터베이스를 초기화한 것을 알아챘다."},"components":["database"],"root_cause":"human-operation","remediation":[{"text":{"en":"Restored the production database with Neon's Backup & Restore","ko":"Neon 의 Backup & Restore 로 운영 데이터베이스를 되살렸다."}}],"action_items":[{"text":{"en":"Make local scripts check DATABASE_URL and refuse to run destructive commands against anything but localhost or 127.0.0.1","ko":"데이터베이스를 지우는 명령 앞에 DATABASE_URL 이 localhost 나 127.0.0.1 을 가리키는지 확인하고 아니면 멈추는 스크립트를 둔다."}},{"text":{"en":"Stop writing production connection strings in local .env files","ko":"로컬 .env 에 운영 데이터베이스의 접속 문자열을 쓰지 않는다."}},{"text":{"en":"Run production operations through CI or a secret manager","ko":"운영 데이터베이스를 대상으로 하는 작업은 CI 나 시크릿 매니저를 거쳐서 하도록 바꾼다."}},{"text":{"en":"Check local env files for production hosts such as *.neon.tech","ko":"개발자 컴퓨터의 env 파일에 *.neon.tech 같은 운영 호스트가 들어 있지 않은지 확인한다."}},{"text":{"en":"Check the Backup & Restore history window of the plan in use, and extend it or add separate backups if it is not enough","ko":"쓰는 요금제의 Backup & Restore 기간이 부족하면 이력 보관 기간을 늘리거나 따로 백업을 마련한다."}},{"text":{"en":"Before holidays or long breaks, remove the production URL from local env files","ko":"연휴처럼 오래 손을 놓기 전에 로컬 env 에서 운영 URL 을 지운다."}},{"text":{"en":"When stopping work midway, record how far it got in an issue or memo","ko":"작업이 중간에 멈추면 어디까지 했는지를 이슈나 메모에 남긴다."}},{"text":{"en":"Add rules that forbid coding agents from running destructive database commands unless the user asks in the current message","ko":"AI 에이전트 규칙에, 사용자가 그 메시지에서 분명히 요청하지 않으면 prisma migrate reset, db push --force-reset 같은 데이터베이스를 지우는 명령을 실행하지 않는다는 규칙을 넣는다."}}],"contributing":["no-safeguard-on-destructive-change"],"recurrence_of":null,"symptoms_text":{"en":"On the first working day after the Silver Week holidays, an engineer ran prisma migrate reset and then loaded seed data, intending to clean the local database before resuming work. The seed data did not seem to be there, and the engineer first suspected that the coding agent had skipped the step. The reset had in fact run against the production database.","ko":"실버 위크 연휴가 끝난 첫날, 엔지니어가 로컬 데이터베이스를 비우고 다시 시작하려고 prisma migrate reset 을 실행하고 시드 데이터를 넣었다. 그런데 시드 데이터가 들어가지 않은 것처럼 보였다.\n\n엔지니어는 처음에 AI 에이전트가 작업을 빼먹었다고 의심했다. 실제로는 로컬이 아니라 운영 데이터베이스가 초기화된 것이었다.\n\n연휴 전에 운영 데이터베이스에 마이그레이션을 적용하면서 packages/database/.env 에 운영 DATABASE_URL 을 넣었고, 그 값을 그대로 둔 채 연휴에 들어갔다. 연휴가 끝난 뒤 엔지니어는 접속 대상을 확인하지 않고 데이터베이스 명령을 실행했다."},"updated_at":"2026-11-14T12:34:22.347892Z","url":"https://benchlet.com/incidentlib/app/cases/IL-0577","org_slug":"ficilcom"}