chore: consolidate runtime data layout under single data/ root directory

Migrate all runtime artifacts (database, uploads, VAPID keys, locks, bot state, container workspaces, zip staging) from scattered locations (`var/`, `devplacepy/static/uploads/`) into a unified `data/` directory. Update `config.py` as single source of truth with `DATA_PATHS` registry and `ensure_data_dirs()`, add `devplace migrate-data` CLI command with CRC verification and idempotent relocation, adjust `.dockerignore`, `.env.example`, `.gitignore`, `Dockerfile`, `Makefile`, `README.md`, `AGENTS.md`, `CLAUDE.md`, and all import paths in `attachments.py` to reference `config.UPLOADS_DIR`/`ATTACHMENTS_DIR` instead of computing from `STATIC_DIR`.
This commit is contained in:
2026-06-13 19:06:43 +00:00
parent de745f7a75
commit 1294c95bed
24 changed files with 378 additions and 80 deletions
+3 -4
View File
@@ -1,9 +1,8 @@
# retoor <retoor@molodetz.nl>
import random
from pathlib import Path
from devplacepy.config import INTERNAL_GATEWAY_URL, INTERNAL_MODEL
from devplacepy.config import INTERNAL_GATEWAY_URL, INTERNAL_MODEL, BOT_DIR
BASE_URL_DEFAULT = "https://pravda.education"
API_URL_DEFAULT = INTERNAL_GATEWAY_URL
@@ -15,8 +14,8 @@ OUTPUT_COST_PER_1M_DEFAULT = 1.10
COST_WINDOW_SECONDS = 600
COST_WARMUP_SECONDS = 120
STATE_DIR = Path.home() / ".devplace_bots"
ARTICLE_REGISTRY_PATH = Path.home() / ".dpbot_article_registry.json"
STATE_DIR = BOT_DIR
ARTICLE_REGISTRY_PATH = BOT_DIR / "article_registry.json"
PROJECT_STATUSES = ["In Development", "Released"]
+9 -4
View File
@@ -6,7 +6,12 @@ import os
import uuid
from dataclasses import dataclass
from devplacepy.config import INTERNAL_GATEWAY_URL, INTERNAL_MODEL
from devplacepy.config import (
INTERNAL_GATEWAY_URL,
INTERNAL_MODEL,
DEVII_TASKS_DB,
DEVII_LESSONS_DB,
)
DEFAULT_AI_URL = INTERNAL_GATEWAY_URL
@@ -100,9 +105,9 @@ def load_settings() -> Settings:
),
log_level=os.environ.get("DEVII_LOG_LEVEL", "WARNING").upper(),
log_path=os.environ.get("DEVII_LOG_PATH", "devii.log"),
tasks_db_path=os.environ.get("DEVII_TASKS_DB", "devii_tasks.db"),
tasks_db_path=os.environ.get("DEVII_TASKS_DB", str(DEVII_TASKS_DB)),
scheduler_tick_seconds=float(os.environ.get("DEVII_SCHEDULER_TICK", "1.0")),
lessons_db_path=os.environ.get("DEVII_LESSONS_DB", "devii_lessons.db"),
lessons_db_path=os.environ.get("DEVII_LESSONS_DB", str(DEVII_LESSONS_DB)),
delegate_max_iterations=int(
os.environ.get(
"DEVII_DELEGATE_MAX_ITERATIONS", DEFAULT_DELEGATE_MAX_ITERATIONS
@@ -172,7 +177,7 @@ FIELD_RSEARCH_ENABLED = "devii_rsearch_enabled"
FIELD_RSEARCH_URL = "devii_rsearch_url"
FIELD_RSEARCH_TIMEOUT = "devii_rsearch_timeout"
LESSONS_DB_PATH = os.environ.get("DEVII_LESSONS_DB", "devii_lessons.db")
LESSONS_DB_PATH = os.environ.get("DEVII_LESSONS_DB", str(DEVII_LESSONS_DB))
def effective_daily_limit(
+3 -5
View File
@@ -4,7 +4,7 @@ import asyncio
import logging
import shutil
from devplacepy.config import DATA_DIR
from devplacepy.config import FORK_STAGING_DIR
from devplacepy import project_files
from devplacepy.content import create_content_item
from devplacepy.database import get_table, record_fork, delete_fork_relations
@@ -13,8 +13,6 @@ from devplacepy.utils import XP_PROJECT
logger = logging.getLogger(__name__)
STAGING_DIR = DATA_DIR / "fork_staging"
class ForkService(JobService):
kind = "fork"
@@ -115,7 +113,7 @@ class ForkService(JobService):
def _copy_files(
self, source_uid: str, new_uid: str, user: dict, job_uid: str
) -> int:
staging = STAGING_DIR / job_uid
staging = FORK_STAGING_DIR / job_uid
try:
project_files.export_to_dir(source_uid, "", staging)
return project_files.import_from_dir(
@@ -133,4 +131,4 @@ class ForkService(JobService):
logger.exception("fork rollback failed for %s", new_uid)
def cleanup(self, job: dict) -> None:
shutil.rmtree(STAGING_DIR / job["uid"], ignore_errors=True)
shutil.rmtree(FORK_STAGING_DIR / job["uid"], ignore_errors=True)
+3 -5
View File
@@ -7,15 +7,13 @@ import shutil
import sys
from pathlib import Path
from devplacepy.config import BASE_DIR, DATA_DIR
from devplacepy.config import BASE_DIR, ZIPS_DIR, ZIP_STAGING_DIR
from devplacepy import project_files
from devplacepy.services.jobs.base import JobService
from devplacepy.utils import generate_uid, slugify
logger = logging.getLogger(__name__)
ZIPS_DIR = DATA_DIR / "zips"
STAGING_DIR = DATA_DIR / "zip_staging"
WORKER_MODULE = "devplacepy.services.jobs.zip_worker"
@@ -40,7 +38,7 @@ class ZipService(JobService):
source = job["payload"].get("source", {})
uid = job["uid"]
staging = STAGING_DIR / uid
staging = ZIP_STAGING_DIR / uid
project_uid = source.get("project_uid", "")
fail_meta = {"project_uid": project_uid}
try:
@@ -131,4 +129,4 @@ class ZipService(JobService):
local_path = result.get("local_path")
if local_path:
Path(local_path).unlink(missing_ok=True)
shutil.rmtree(STAGING_DIR / job["uid"], ignore_errors=True)
shutil.rmtree(ZIP_STAGING_DIR / job["uid"], ignore_errors=True)