# certbot 一次性 DNS 挑战值(临时文件,不入库)
deploy/dns-txt-value.txt
+
+# v2 隔离部署产物(不入库)
+frontend/build-v2/
+backend/db/bcd_v2.db
# --- 路径自动修复逻辑 ---
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
-DATABASE_PATH = os.path.join(BASE_DIR, "a", "bcd.db")
-if not os.path.exists(DATABASE_PATH):
- DATABASE_PATH = os.path.join(BASE_DIR, "db", "bcd.db")
+# v2 等隔离部署可通过环境变量 WORDS_DB_PATH 指向独立数据库文件
+DATABASE_PATH = os.environ.get("WORDS_DB_PATH")
+if not DATABASE_PATH:
+ DATABASE_PATH = os.path.join(BASE_DIR, "a", "bcd.db")
+ if not os.path.exists(DATABASE_PATH):
+ DATABASE_PATH = os.path.join(BASE_DIR, "db", "bcd.db")
# --- 简单登录鉴权(单用户;账密可用环境变量覆盖,默认 Simba / Simba+0322)---
# 前端登录后持 token;所有 /api/*(除登录接口)必须带有效 token,否则 401。
-REACT_APP_API_BASE=
+REACT_APP_API_BASE=/v2
return (
<div className="app-shell">
{loggedIn ? (
- <Router>
+ <Router basename="/v2">
<SyncNotifications />
<Routes>
<Route path="/" element={<Home />} />
(err) => {
if (err.response && err.response.status === 401) {
clearToken();
- window.location.href = '/';
+ window.location.href = '/v2/';
}
return Promise.reject(err);
}
// 后端在 main.py 校验账密并签发 HMAC token;所有 /api/* 需携带该 token。
import { API_BASE } from './api';
-const TOKEN_KEY = 'words_auth_token';
+const TOKEN_KEY = 'words_auth_token_v2';
export function getToken() {
return localStorage.getItem(TOKEN_KEY) || '';
// - progress: 离线进度, keyPath=`${group_id}:${op_type}`, {key, group_id, op_type, completed_at, dirty}
// - meta: 元数据, keyPath=key (lastSyncAt, learnableGroups[])
-const DB_NAME = 'words-pwa';
+const DB_NAME = 'words-pwa-v2';
const DB_VERSION = 1;
let dbPromise = null;
// 注册 Service Worker (PWA 离线支持)
if ('serviceWorker' in navigator) {
window.addEventListener('load', () => {
- navigator.serviceWorker.register('/sw.js').catch(err => console.error('SW registration failed:', err));
+ navigator.serviceWorker.register('/v2/sw.js').catch(err => console.error('SW registration failed:', err));
// SW 接管页面后, 再触发一次同步+预取, 确保预取请求被 SW 拦截并写入缓存
navigator.serviceWorker.ready.then(() => {
if (isLoggedIn()) {