chore(repo): consolidate local env and clean root files
This commit is contained in:
31
.env.example
Normal file
31
.env.example
Normal file
@@ -0,0 +1,31 @@
|
||||
# Copy to `.env` and fill real values before local backend runs or deploy work:
|
||||
# cp .env.example .env
|
||||
|
||||
# Backend runtime
|
||||
APP_JWT_SECRET="replace-with-at-least-32-bytes"
|
||||
APP_ADMIN_USERNAMES=""
|
||||
APP_AUTH_REGISTRATION_INVITE_CODE=""
|
||||
|
||||
# DogeCloud API credentials
|
||||
YOYUZH_DOGECLOUD_API_BASE_URL="https://api.dogecloud.com"
|
||||
YOYUZH_DOGECLOUD_API_ACCESS_KEY="replace-me"
|
||||
YOYUZH_DOGECLOUD_API_SECRET_KEY="replace-me"
|
||||
YOYUZH_DOGECLOUD_S3_REGION="automatic"
|
||||
|
||||
# Frontend / storage deploy scopes
|
||||
YOYUZH_DOGECLOUD_FRONT_SCOPE="yoyuzh-front"
|
||||
YOYUZH_DOGECLOUD_FRONT_TTL_SECONDS="3600"
|
||||
YOYUZH_DOGECLOUD_FRONT_PREFIX=""
|
||||
YOYUZH_DOGECLOUD_STORAGE_SCOPE="yoyuzh-files"
|
||||
YOYUZH_DOGECLOUD_STORAGE_TTL_SECONDS="3600"
|
||||
YOYUZH_DOGECLOUD_ANDROID_SCOPE="yoyuzh-files"
|
||||
YOYUZH_ANDROID_RELEASE_PREFIX="android/releases"
|
||||
|
||||
# Server access and deploy metadata
|
||||
YOYUZH_SERVER_HOST="replace-me"
|
||||
YOYUZH_SERVER_USER="replace-me"
|
||||
YOYUZH_SERVER_PASSWORD="replace-me"
|
||||
YOYUZH_BACKEND_SYSTEMD_SERVICE="my-site-api.service"
|
||||
YOYUZH_BACKEND_REMOTE_JAR_PATH="/opt/yoyuzh/yoyuzh-portal-backend.jar"
|
||||
YOYUZH_BACKEND_REMOTE_ENV_FILE="/opt/yoyuzh/app.env"
|
||||
YOYUZH_BACKEND_REMOTE_CONFIG="/opt/yoyuzh/application-prod.yml"
|
||||
@@ -1,39 +0,0 @@
|
||||
# 复制本文件为 `.env.oss.local` 后再填写真实值:
|
||||
# cp .env.oss.example .env.oss.local
|
||||
#
|
||||
# 发布命令:
|
||||
# node scripts/deploy-front-oss.mjs
|
||||
#
|
||||
# 仅预览将要上传的文件:
|
||||
# node scripts/deploy-front-oss.mjs --skip-build --dry-run
|
||||
|
||||
# 说明:文件名仍叫 `.env.oss.local`,但内容已经切换为多吉云临时密钥配置。
|
||||
|
||||
# 多吉云服务端 API AccessKey / SecretKey。
|
||||
# 不要把真实值提交到 git。
|
||||
YOYUZH_DOGECLOUD_API_ACCESS_KEY="YOUR_DOGECLOUD_ACCESS_KEY"
|
||||
YOYUZH_DOGECLOUD_API_SECRET_KEY="YOUR_DOGECLOUD_SECRET_KEY"
|
||||
|
||||
# 可选:多吉云服务端 API 地址。
|
||||
YOYUZH_DOGECLOUD_API_BASE_URL="https://api.dogecloud.com"
|
||||
|
||||
# 多吉云 S3 兼容区域。多吉云官方文档建议使用 automatic。
|
||||
YOYUZH_DOGECLOUD_S3_REGION="automatic"
|
||||
|
||||
# 前端静态站点的逻辑桶名 / scope。
|
||||
# 你的当前桶建议填写 `yoyuzh-front`。
|
||||
YOYUZH_DOGECLOUD_FRONT_SCOPE="yoyuzh-front"
|
||||
|
||||
# 可选:前端发布拿临时密钥的有效期,单位秒。
|
||||
YOYUZH_DOGECLOUD_FRONT_TTL_SECONDS="3600"
|
||||
|
||||
# 可选:上传到桶内的子目录。
|
||||
# 为空表示直接上传到桶根目录。
|
||||
YOYUZH_DOGECLOUD_FRONT_PREFIX=""
|
||||
|
||||
# Android APK 发布默认走文件桶;如需单独逻辑桶,可显式填写。
|
||||
YOYUZH_DOGECLOUD_STORAGE_SCOPE="yoyuzh-files"
|
||||
YOYUZH_DOGECLOUD_ANDROID_SCOPE="yoyuzh-files"
|
||||
|
||||
# APK 与元数据在文件桶中的发布前缀。
|
||||
YOYUZH_ANDROID_RELEASE_PREFIX="android/releases"
|
||||
@@ -1,9 +0,0 @@
|
||||
YOYUZH_DOGECLOUD_API_BASE_URL="https://api.dogecloud.com"
|
||||
YOYUZH_DOGECLOUD_API_ACCESS_KEY="eb8e79012b435492"
|
||||
YOYUZH_DOGECLOUD_API_SECRET_KEY="3b9f241e61762f382ab2b6f88b9b4345"
|
||||
YOYUZH_DOGECLOUD_S3_REGION="automatic"
|
||||
YOYUZH_DOGECLOUD_FRONT_SCOPE="yoyuzh-front"
|
||||
YOYUZH_DOGECLOUD_FRONT_TTL_SECONDS="3600"
|
||||
YOYUZH_DOGECLOUD_FRONT_PREFIX=""
|
||||
YOYUZH_DOGECLOUD_STORAGE_SCOPE="yoyuzh-files"
|
||||
YOYUZH_DOGECLOUD_STORAGE_TTL_SECONDS="3600"
|
||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -19,6 +19,9 @@ frontend-dev.err.log
|
||||
.vscode/
|
||||
.idea/
|
||||
.gemini/
|
||||
.env
|
||||
.env.local
|
||||
.env.*.local
|
||||
.codex/*
|
||||
!.codex/config.toml
|
||||
!.codex/agents/
|
||||
|
||||
@@ -14,6 +14,7 @@ This repository is split across a Java backend, a Vite/React frontend, a small `
|
||||
- `backend/`: Spring Boot 3.3.8, Java 17, Maven, domain packages under `com.yoyuzh.{auth,cqu,files,config,common}`.
|
||||
- `front/`: Vite 6, React 19, TypeScript, Tailwind CSS v4, route/page code under `src/pages`, reusable UI under `src/components`, shared logic under `src/lib`.
|
||||
- `docs/`: currently contains implementation plans under `docs/superpowers/plans/`.
|
||||
- `docs/agents/`: supplementary agent / handoff docs. Keep root `AGENTS.md` as the entrypoint and put extra collaboration notes there instead of scattering more root files.
|
||||
- `scripts/`: deployment, migration, smoke, and local startup helpers.
|
||||
|
||||
## Command source of truth
|
||||
@@ -120,7 +121,7 @@ Important:
|
||||
|
||||
## Repo-specific guardrails
|
||||
|
||||
- Do not run `npm` commands at the repository root. This repo has a root `package-lock.json` but no root `package.json`.
|
||||
- Do not run `npm` commands at the repository root. The repository root is not an application package; frontend commands belong under `front/`.
|
||||
- Frontend API proxying is defined in `front/vite.config.ts`, with `VITE_BACKEND_URL` defaulting to `http://localhost:8080`.
|
||||
- Backend local development behavior is split between `backend/src/main/resources/application.yml` and `application-dev.yml`; the `dev` profile uses H2 and mock CQU data.
|
||||
- Backend tests already exist under `backend/src/test/java/com/yoyuzh/...`; prefer adding or updating tests in the matching package.
|
||||
|
||||
147
CLAUDE.md
147
CLAUDE.md
@@ -1,138 +1,75 @@
|
||||
# CLAUDE.md
|
||||
|
||||
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
||||
This file provides guidance to Claude Code and similar agents when working in this repository.
|
||||
|
||||
## Session Startup
|
||||
|
||||
Read these files in order before planning, coding, reviewing, or deploying:
|
||||
1. `memory.md` — current project state and handoff context
|
||||
2. `docs/architecture.md` — authoritative system-level source of truth
|
||||
3. `docs/api-reference.md` — backend endpoint and auth boundary reference
|
||||
4. `AGENTS.md` — role routing rules and hard guardrails
|
||||
|
||||
1. `memory.md`
|
||||
2. `docs/architecture.md`
|
||||
3. `docs/api-reference.md`
|
||||
4. `AGENTS.md`
|
||||
|
||||
Use `docs/agents/handoff.md` only as supplemental background when the primary docs are not enough.
|
||||
|
||||
## Project Overview
|
||||
|
||||
**yoyuzh.xyz** — full-stack personal site with four functional areas:
|
||||
- Personal cloud drive (netdisk)
|
||||
- P2P browser-to-browser file transfer (快传 / quick-transfer)
|
||||
- Account system with invite-code registration
|
||||
- Admin console
|
||||
`yoyuzh.xyz` is a full-stack personal site focused on:
|
||||
|
||||
Frontend is hosted on Aliyun OSS (static). Backend runs as `my-site-api.service` on a Linux server at `1.14.49.201`, jar at `/opt/yoyuzh/yoyuzh-portal-backend.jar`.
|
||||
- account/auth flows
|
||||
- personal cloud drive
|
||||
- quick transfer
|
||||
- admin console
|
||||
- Capacitor Android shell
|
||||
|
||||
## Commands
|
||||
|
||||
**Do not run `npm` at the repo root.** The root has no real `package.json`.
|
||||
Do not run frontend business commands from the repository root.
|
||||
|
||||
### Frontend (`cd front`)
|
||||
|
||||
```bash
|
||||
npm run dev # Vite dev server on port 3000
|
||||
npm run build # Production build
|
||||
npm run preview # Preview built output
|
||||
npm run lint # tsc --noEmit (this IS the type-check; no ESLint)
|
||||
npm run test # node --import tsx --test src/**/*.test.ts
|
||||
npm run clean # rm -rf dist
|
||||
npm run dev
|
||||
npm run build
|
||||
npm run preview
|
||||
npm run clean
|
||||
npm run lint
|
||||
npm run test
|
||||
```
|
||||
|
||||
### Backend (`cd backend`)
|
||||
|
||||
```bash
|
||||
mvn spring-boot:run # Default profile (MySQL)
|
||||
mvn spring-boot:run -Dspring-boot.run.profiles=dev # Dev profile (H2, mock data)
|
||||
mvn spring-boot:run
|
||||
mvn spring-boot:run -Dspring-boot.run.profiles=dev
|
||||
mvn test
|
||||
mvn package # Produces backend/target/yoyuzh-portal-backend-0.0.1-SNAPSHOT.jar
|
||||
mvn package
|
||||
```
|
||||
|
||||
There is no backend lint or typecheck command.
|
||||
There is no dedicated backend lint or typecheck command.
|
||||
|
||||
### Deploy
|
||||
|
||||
```bash
|
||||
node scripts/deploy-front-oss.mjs # Build + upload frontend to Aliyun OSS
|
||||
node scripts/deploy-front-oss.mjs --dry-run # Preview without uploading
|
||||
node scripts/deploy-front-oss.mjs --skip-build # Upload only
|
||||
```
|
||||
Requires OSS credentials from env vars or `.env.oss.local`.
|
||||
|
||||
Backend deploy: `mvn package`, then SCP the jar to `/opt/yoyuzh/yoyuzh-portal-backend.jar` on the server and restart `my-site-api.service`. No checked-in backend deploy script exists.
|
||||
|
||||
## Architecture
|
||||
|
||||
### Tech Stack
|
||||
| Layer | Technology |
|
||||
|---|---|
|
||||
| Frontend | React 19, TypeScript, Vite 6, Tailwind CSS v4, react-router-dom v7 |
|
||||
| Admin UI | react-admin v5 (lazy-loaded at `/admin/*`) |
|
||||
| Backend | Spring Boot 3.3.8, Java 17, Maven, Spring Security + JWT |
|
||||
| ORM | Spring Data JPA / Hibernate |
|
||||
| DB (prod) | MySQL 8 |
|
||||
| DB (dev) | H2 (in-file, MySQL compat mode via `application-dev.yml`) |
|
||||
| File storage | Aliyun OSS (`yoyuzh-files2`, Chengdu region) |
|
||||
|
||||
### Frontend Structure (`front/src/`)
|
||||
- `App.tsx` — router entrypoint
|
||||
- `lib/` — pure logic modules, each with a co-located `*.test.ts`
|
||||
- `api.ts` — all backend API calls
|
||||
- `session.ts` — JWT session management
|
||||
- `transfer-runtime.ts`, `transfer-protocol.ts` — WebRTC logic
|
||||
- `files-upload.ts` — upload orchestration
|
||||
- `pages/` — page-level components (`Files.tsx`, `Transfer.tsx`, `TransferReceive.tsx`, `Login.tsx`, `Overview.tsx`, `FileShare.tsx`)
|
||||
- `admin/` — react-admin console with custom `data-provider.ts`
|
||||
- `components/layout/`, `components/ui/` — shared UI primitives
|
||||
- `auth/AuthProvider.tsx` — auth context
|
||||
|
||||
Frontend API proxy: all `/api/*` calls during dev proxy to `VITE_BACKEND_URL` (default `http://localhost:8080`) via `front/vite.config.ts`. Production hardcodes `https://api.yoyuzh.xyz/api` in `front/.env.production`.
|
||||
|
||||
### Backend Package Structure (`com.yoyuzh`)
|
||||
- `auth` — JWT, login, register, refresh token, single-device session enforcement
|
||||
- `files` — file metadata CRUD, upload/download, share links; `files/storage/` abstracts local vs OSS
|
||||
- `transfer` — quick-transfer signaling API only (no file content relay)
|
||||
- `admin` — admin-only user/file management APIs
|
||||
- `config` — `SecurityConfig`, CORS, `JwtAuthenticationFilter`
|
||||
- `common` — shared exceptions and utilities
|
||||
|
||||
### Key Design Decisions
|
||||
- **Single-device login**: `activeSessionId` in user DB record matched against `sid` JWT claim on every request. New login invalidates old device's access token immediately.
|
||||
- **Quick-transfer**: backend is signaling-only. File bytes travel via WebRTC `DataChannel` between browsers — no server bandwidth consumed. Offline mode uploads to OSS for 7-day retention.
|
||||
- **File storage abstraction**: `FileContentStorage` interface decouples metadata logic from disk/OSS. Upload flow: `initiate` → direct OSS upload → `complete`. Falls back to proxy upload on failure.
|
||||
- **Invite-code registration**: single-use codes auto-rotate after consumption; current code displayed in admin console.
|
||||
|
||||
### Security Boundaries (`SecurityConfig`)
|
||||
- Public: `/api/auth/**`, `/api/transfer/**`, `GET /api/files/share-links/{token}`
|
||||
- Requires auth: `/api/files/**`, `/api/user/**`, `/api/admin/**`
|
||||
|
||||
## Testing
|
||||
|
||||
Frontend tests live next to the module they test (`src/lib/api.test.ts` beside `src/lib/api.ts`). Run a single test file:
|
||||
```bash
|
||||
cd front && node --import tsx --test src/lib/api.test.ts
|
||||
node scripts/deploy-front-oss.mjs
|
||||
node scripts/deploy-front-oss.mjs --dry-run
|
||||
node scripts/deploy-front-oss.mjs --skip-build
|
||||
node scripts/deploy-android-apk.mjs
|
||||
node scripts/deploy-android-release.mjs
|
||||
```
|
||||
|
||||
Backend tests mirror the main package structure under `backend/src/test/java/com/yoyuzh/`. Run a single test class:
|
||||
```bash
|
||||
cd backend && mvn test -Dtest=ClassName
|
||||
```
|
||||
The deploy scripts now prefer the repository root `.env` file and keep `.env.oss.local` only as a legacy fallback.
|
||||
|
||||
Dev profile (`-Dspring-boot.run.profiles=dev`) uses H2; H2 console available at `http://localhost:8080/h2-console`.
|
||||
## Repo Conventions
|
||||
|
||||
## Codex Agent Roles
|
||||
|
||||
Agents are defined in `.codex/agents/` and configured in `.codex/config.toml`. Use the workflow from `AGENTS.md`:
|
||||
|
||||
| Agent | Role | Mode |
|
||||
|---|---|---|
|
||||
| `orchestrator` | Default coordinator, routes to specialists | read-only |
|
||||
| `planner` | File-level and command plans before code changes | read-only |
|
||||
| `explorer` | Maps code paths and existing behavior | read-only |
|
||||
| `implementer` | Owns code edits and nearby test updates | read-write |
|
||||
| `tester` | Runs repo-backed commands, reports failures | read-only |
|
||||
| `reviewer` | Reviews diffs for bugs, regressions, test gaps | read-only |
|
||||
| `deployer` | Builds and publishes frontend to OSS; packages backend jar for SSH delivery | read-write |
|
||||
|
||||
Default workflow: orchestrator → planner (if multi-file) → explorer (if behavior unclear) → implementer → tester → reviewer → deployer.
|
||||
- Root `.env` is the shared local secrets and deploy-config entrypoint.
|
||||
- `.env.example` is the template.
|
||||
- `memory.md` is the main continuity file.
|
||||
- `docs/agents/` stores only the supplemental handoff doc; `CLAUDE.md` itself stays at the repository root.
|
||||
|
||||
## Known Constraints
|
||||
|
||||
- VS Code "final field not initialized" errors on backend are Lombok/Java LS false positives — check Lombok extension and annotation processor, not source code.
|
||||
- Frontend chunk size warnings from Vite do not block builds or deploys.
|
||||
- `api.yoyuzh.xyz` has TLS/SNI instability on some networks; this is not a backend code issue.
|
||||
- Production frontend bundle hardcodes the API base URL — API subdomain issues surface as "network error" or "login failed" on the frontend.
|
||||
- Server credentials are in local file `账号密码.txt`; never commit or output their contents.
|
||||
- Frontend production still hardcodes `https://api.yoyuzh.xyz/api` in `front/.env.production`.
|
||||
- Vite build chunk warnings do not currently block release.
|
||||
- Backend service metadata and SSH-related secrets have been consolidated into root `.env`; do not echo those values in normal responses.
|
||||
|
||||
@@ -1,280 +0,0 @@
|
||||
# 项目交接说明
|
||||
|
||||
更新时间:2026-03-18
|
||||
项目根目录:`/Users/mac/Documents/my_site`
|
||||
|
||||
## 1. 项目概况
|
||||
|
||||
这是一个前后端分离的个人门户项目:
|
||||
|
||||
- 前端:`front/`
|
||||
- 后端:`backend/`
|
||||
- 线上主站:`https://yoyuzh.xyz`
|
||||
- 线上 API:`https://api.yoyuzh.xyz`
|
||||
|
||||
主要功能:
|
||||
|
||||
- 登录 / 注册
|
||||
- 网盘文件列表与最近文件
|
||||
- 教务相关接口(课表 / 成绩)
|
||||
|
||||
## 2. 当前线上架构
|
||||
|
||||
当前建议保持的生产架构是:
|
||||
|
||||
- `yoyuzh.xyz`:继续走 OSS / ESA,负责静态站点
|
||||
- `api.yoyuzh.xyz`:直接指向后端服务器,不要继续走 ESA 代理
|
||||
|
||||
原因:
|
||||
|
||||
- 主站静态资源走 ESA 没问题
|
||||
- API 一旦走 ESA,之前出现过:
|
||||
- `525 Origin SSL Handshake Error`
|
||||
- `ERR_CONNECTION_CLOSED`
|
||||
- `ERR_EMPTY_RESPONSE`
|
||||
- 当前最稳方案是“静态站加速,API 直连”
|
||||
|
||||
## 3. 当前前端生产配置
|
||||
|
||||
文件:
|
||||
|
||||
- `front/.env.production`
|
||||
|
||||
当前应保持为:
|
||||
|
||||
```env
|
||||
VITE_API_BASE_URL="https://api.yoyuzh.xyz/api"
|
||||
VITE_ROUTER_MODE="hash"
|
||||
VITE_ENABLE_DEV_LOGIN="false"
|
||||
```
|
||||
|
||||
说明:
|
||||
|
||||
- 不要再切回同域 `/api`,除非以后重新正确配置边缘转发
|
||||
- 目前生产前端已经恢复为直连 `api.yoyuzh.xyz`
|
||||
|
||||
## 4. 当前已完成的前端改动
|
||||
|
||||
### 4.1 登录页
|
||||
|
||||
`front/src/pages/Login.tsx`
|
||||
|
||||
- 已替换为模板版登录 / 注册页
|
||||
- 登录调用:`POST /auth/login`
|
||||
- 注册调用:`POST /auth/register`
|
||||
- 登录成功后写入 session 并跳转 `/overview`
|
||||
|
||||
### 4.2 网络错误处理
|
||||
|
||||
`front/src/lib/api.ts`
|
||||
|
||||
- 对网络错误统一包装为更清晰的前端错误
|
||||
- 登录和只读接口有轻量重试机制
|
||||
- 当前策略是“尽量兜底,但不要把登录拖到 7-8 秒”
|
||||
|
||||
### 4.3 登录成功与总览初始化失败拆分提示
|
||||
|
||||
相关文件:
|
||||
|
||||
- `front/src/lib/session.ts`
|
||||
- `front/src/pages/Overview.tsx`
|
||||
- `front/src/pages/overview-state.ts`
|
||||
|
||||
已做:
|
||||
|
||||
- 登录成功后会标记一次“post-login pending”
|
||||
- `/overview` 初始化失败时,会提示“登录已成功,但总览加载失败”
|
||||
- 避免把 overview 并发初始化失败误判成登录失败
|
||||
|
||||
## 5. 当前后端与服务器状态
|
||||
|
||||
通过 SSH 已确认:
|
||||
|
||||
- `my-site-api.service` 正常运行
|
||||
- 后端本机 `127.0.0.1:8080` 正常
|
||||
- 服务器本机直打登录接口返回 `200`
|
||||
- Nginx 正常反代 `api.yoyuzh.xyz -> 127.0.0.1:8080`
|
||||
|
||||
服务器上关键配置:
|
||||
|
||||
- Nginx:`/etc/nginx/sites-enabled/my-site-api`
|
||||
- 后端配置:`/opt/yoyuzh/application-prod.yml`
|
||||
- 服务名:`my-site-api.service`
|
||||
|
||||
## 6. 线上排查结论
|
||||
|
||||
### 6.1 已确认不是后端业务慢
|
||||
|
||||
在服务器本机测试结果:
|
||||
|
||||
- `POST http://127.0.0.1:8080/api/auth/login` 约 `95ms`
|
||||
- `POST https://api.yoyuzh.xyz/api/auth/login` 从服务器发起约 `681ms`
|
||||
|
||||
所以:
|
||||
|
||||
- 后端本身不是“登录 5 秒”的根因
|
||||
|
||||
### 6.2 之前登录很慢的主要原因
|
||||
|
||||
更像是以下问题叠加:
|
||||
|
||||
- 旧 DNS / 旧代理链路未收敛
|
||||
- API 域名曾被 ESA 代理,导致 TLS / 回源问题
|
||||
- 浏览器前链路偶发 `ERR_CONNECTION_CLOSED`
|
||||
|
||||
### 6.3 当前更可信的状态
|
||||
|
||||
服务器日志已经看到真实浏览器请求成功:
|
||||
|
||||
- `OPTIONS /api/auth/login` => `200`
|
||||
- `POST /api/auth/login` => `200`
|
||||
- `/api/user/profile` => `200`
|
||||
- `/api/files/recent` => `200`
|
||||
- `/api/files/list` => `200`
|
||||
- `/api/cqu/*` => `200`
|
||||
|
||||
因此:
|
||||
|
||||
- 现在如果仍有个别客户端不稳定,优先怀疑本地 DNS / 浏览器缓存 / 本地网络链路
|
||||
|
||||
## 7. DNS / ESA 方面的重要结论
|
||||
|
||||
### 7.1 过去踩过的坑
|
||||
|
||||
不要再轻易做下面这件事:
|
||||
|
||||
- 让 `yoyuzh.xyz/api/*` 通过 ESA 回源到 API
|
||||
|
||||
之前已经明确踩到:
|
||||
|
||||
- `/api/*` 误回 OSS,报 `403 NonCnameForbidden`
|
||||
- 回源 HTTPS 握手失败,报 `525 Origin SSL Handshake Error`
|
||||
|
||||
### 7.2 当前建议
|
||||
|
||||
- `yoyuzh.xyz`:可以继续 ESA
|
||||
- `api.yoyuzh.xyz`:不要走 ESA 代理
|
||||
|
||||
### 7.3 用户侧现象
|
||||
|
||||
曾出现:
|
||||
|
||||
- 无痕模式能登录
|
||||
- 本机 `dig` 还查到旧的 `198.18.0.148`
|
||||
|
||||
这说明某一阶段存在 DNS 传播不一致。
|
||||
如果下一个 Codex 遇到“浏览器能用,命令行不行”的情况,先查 DNS 链路,不要直接改代码。
|
||||
|
||||
## 8. OSS 前端部署方式
|
||||
|
||||
已经写好自动部署脚本:
|
||||
|
||||
- `scripts/deploy-front-oss.mjs`
|
||||
- 配套库:`scripts/oss-deploy-lib.mjs`
|
||||
- 配置模板:`.env.oss.example`
|
||||
|
||||
### 8.1 本地使用方式
|
||||
|
||||
先准备:
|
||||
|
||||
```bash
|
||||
cp .env.oss.example .env.oss.local
|
||||
```
|
||||
|
||||
然后填入 OSS 参数。
|
||||
|
||||
### 8.2 发布命令
|
||||
|
||||
```bash
|
||||
./scripts/deploy-front-oss.mjs
|
||||
```
|
||||
|
||||
### 8.3 只看将要上传什么
|
||||
|
||||
```bash
|
||||
./scripts/deploy-front-oss.mjs --skip-build --dry-run
|
||||
```
|
||||
|
||||
### 8.4 部署逻辑
|
||||
|
||||
脚本会:
|
||||
|
||||
- 读取 `.env.oss.local`
|
||||
- 构建 `front/dist`
|
||||
- 上传到 OSS
|
||||
- 自动设置缓存头
|
||||
|
||||
缓存策略:
|
||||
|
||||
- `index.html` => `no-cache`
|
||||
- `assets/*` => `public,max-age=31536000,immutable`
|
||||
|
||||
## 9. 测试账号
|
||||
|
||||
开发测试账号文档:
|
||||
|
||||
- `开发测试账号.md`
|
||||
|
||||
常用账号:
|
||||
|
||||
- `portal-demo / portal123456`
|
||||
|
||||
注意:
|
||||
|
||||
- 这些开发账号只在特定环境下才会自动初始化
|
||||
- 如果线上账号密码不对,不要默认认为后端坏了
|
||||
|
||||
## 10. SSH 与敏感信息
|
||||
|
||||
有 SSH 凭据文件:
|
||||
|
||||
- `账号密码.txt`
|
||||
|
||||
下一个 Codex 可以读取该文件用于 SSH,但不要在普通交互回复里直接回显其中的明文密码。
|
||||
|
||||
## 11. 推荐的排查顺序
|
||||
|
||||
如果后续又出现“登录失败 / 网络连接异常”,按这个顺序排:
|
||||
|
||||
1. 先查前端当前生产包是否正确
|
||||
- 看 `https://yoyuzh.xyz/` 的 `index.html`
|
||||
- 确认引用的是最新构建产物
|
||||
|
||||
2. 再查 API 域名是否直连服务器
|
||||
- `dig +short api.yoyuzh.xyz`
|
||||
- `curl -vkI https://api.yoyuzh.xyz/`
|
||||
|
||||
3. 再查服务器本机和 systemd
|
||||
- `systemctl status my-site-api`
|
||||
- `curl http://127.0.0.1:8080/...`
|
||||
|
||||
4. 最后查 Nginx access/error log
|
||||
- `/var/log/nginx/access.log`
|
||||
- `/var/log/nginx/error.log`
|
||||
|
||||
不要上来就改前端逻辑。
|
||||
|
||||
## 12. 当前最重要的改进建议
|
||||
|
||||
### 短期建议
|
||||
|
||||
- 保持 API 直连,不再给 `api.yoyuzh.xyz` 套 ESA
|
||||
- 用现有自动部署脚本发布前端
|
||||
|
||||
### 中期建议
|
||||
|
||||
- 给后端加一个明确的健康检查接口,比如 `/api/healthz`
|
||||
- 给 Nginx access log 加 upstream timing 和 request id
|
||||
|
||||
### 长期建议
|
||||
|
||||
- 如果未来还想做同域 `/api`,要单独做一轮边缘转发设计
|
||||
- 先确保:
|
||||
- 源站类型正确
|
||||
- 不会回 OSS
|
||||
- 不会再发生 `525`
|
||||
|
||||
## 13. 给下一个 Codex 的一句话总结
|
||||
|
||||
当前项目已经从“链路混乱”恢复到“后端基本正常、主站正常、前端直连 API”的状态。
|
||||
接手时优先维持现状,不要贸然重新启用 ESA 的 `/api` 回源方案。
|
||||
29
README.md
29
README.md
@@ -14,7 +14,7 @@
|
||||
|
||||
- 用户注册与登录
|
||||
- 邀请码注册
|
||||
- 同账号仅允许一台设备同时登录
|
||||
- 同账号支持桌面端与移动端同时在线
|
||||
- 个人资料管理
|
||||
|
||||
### 网盘
|
||||
@@ -71,6 +71,7 @@
|
||||
├── backend/ Spring Boot 后端
|
||||
├── front/ React 前端
|
||||
├── docs/ 计划与文档
|
||||
├── docs/agents/ agent 补充交接文档
|
||||
├── scripts/ 部署与辅助脚本
|
||||
├── data/ 本地数据或辅助文件
|
||||
└── 模板/ 页面参考模板
|
||||
@@ -88,16 +89,30 @@
|
||||
|
||||
### 1. 启动后端
|
||||
|
||||
先准备根目录环境变量:
|
||||
|
||||
```bash
|
||||
cp .env.example .env
|
||||
```
|
||||
|
||||
填好 `APP_JWT_SECRET` 后,在当前 shell 里加载:
|
||||
|
||||
```bash
|
||||
set -a
|
||||
source .env
|
||||
set +a
|
||||
```
|
||||
|
||||
```bash
|
||||
cd backend
|
||||
APP_JWT_SECRET=<至少32字节的密钥> mvn spring-boot:run
|
||||
mvn spring-boot:run
|
||||
```
|
||||
|
||||
如果要使用本地开发配置:
|
||||
|
||||
```bash
|
||||
cd backend
|
||||
APP_JWT_SECRET=<至少32字节的密钥> mvn spring-boot:run -Dspring-boot.run.profiles=dev
|
||||
mvn spring-boot:run -Dspring-boot.run.profiles=dev
|
||||
```
|
||||
|
||||
说明:
|
||||
@@ -144,6 +159,8 @@ mvn package
|
||||
|
||||
## 环境变量
|
||||
|
||||
推荐把本地密钥和部署配置统一维护在仓库根目录 `.env`,模板在 `.env.example`。
|
||||
|
||||
### 后端必填
|
||||
|
||||
```env
|
||||
@@ -171,7 +188,7 @@ YOYUZH_DOGECLOUD_S3_REGION=automatic
|
||||
|
||||
### 前端发布配置
|
||||
|
||||
前端发布脚本会从环境变量或 `.env.oss.local` 中读取多吉云 API 凭据,再动态换取临时 S3 密钥。前端静态桶应填写逻辑桶名 `yoyuzh-front`,不要直接把底层 `s3Bucket` 写死到配置里。
|
||||
前端发布脚本会优先从仓库根目录 `.env` 读取多吉云 API 凭据,再动态换取临时 S3 密钥;旧 `.env.oss.local` 只保留兼容回退读取。前端静态桶应填写逻辑桶名 `yoyuzh-front`,不要直接把底层 `s3Bucket` 写死到配置里。
|
||||
|
||||
常用变量:
|
||||
|
||||
@@ -188,8 +205,8 @@ YOYUZH_ANDROID_RELEASE_PREFIX=android/releases
|
||||
|
||||
参考文件:
|
||||
|
||||
- `.env.oss.example`
|
||||
- `.env.oss.local`
|
||||
- `.env.example`
|
||||
- `.env`
|
||||
|
||||
## 部署
|
||||
|
||||
|
||||
@@ -15,17 +15,24 @@
|
||||
|
||||
## 启动
|
||||
|
||||
推荐先在仓库根目录准备并加载 `.env`:
|
||||
|
||||
```bash
|
||||
cp .env.example .env
|
||||
set -a
|
||||
source ../.env
|
||||
set +a
|
||||
```
|
||||
|
||||
默认配置:
|
||||
|
||||
```bash
|
||||
APP_JWT_SECRET=<至少32字节的随机密钥> \
|
||||
mvn spring-boot:run
|
||||
```
|
||||
|
||||
本地联调建议使用 `dev` 环境:
|
||||
|
||||
```bash
|
||||
APP_JWT_SECRET=<至少32字节的随机密钥> \
|
||||
mvn spring-boot:run -Dspring-boot.run.profiles=dev
|
||||
```
|
||||
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
{
|
||||
"registries": {
|
||||
"@shadcn": "https://ui.shadcn.com/r/styles/default/{name}.json",
|
||||
"@react-bits": "https://reactbits.dev/r/{name}.json"
|
||||
}
|
||||
}
|
||||
36
docs/agents/handoff.md
Normal file
36
docs/agents/handoff.md
Normal file
@@ -0,0 +1,36 @@
|
||||
# 项目交接补充
|
||||
|
||||
更新时间:2026-04-06
|
||||
|
||||
这份文档只记录补充性的交接和运维提示;一切当前状态仍优先以 `memory.md`、`docs/architecture.md`、`docs/api-reference.md` 为准。
|
||||
|
||||
## 当前主线
|
||||
|
||||
- 产品方向已经从旧教务切到“网盘 + 快传 + 管理台 + Android 壳”
|
||||
- 前端静态站发布走 `node scripts/deploy-front-oss.mjs`
|
||||
- Android APK 发包走 `node scripts/deploy-android-apk.mjs`
|
||||
- 后端交付仍是 `cd backend && mvn package` 后手动上传 jar 并重启服务
|
||||
|
||||
## 本地配置整理
|
||||
|
||||
- 根目录 `.env` 已收口多吉云 API 凭据、服务器 SSH 信息和常用部署元信息
|
||||
- `.env.example` 作为模板保留在仓库中
|
||||
- 旧的 `.env.oss.local` 仅作为兼容回退读取,不再是主入口
|
||||
|
||||
## 线上运维关键信息
|
||||
|
||||
- 后端服务名:`my-site-api.service`
|
||||
- 后端 jar 路径:`/opt/yoyuzh/yoyuzh-portal-backend.jar`
|
||||
- 后端环境变量文件:`/opt/yoyuzh/app.env`
|
||||
- 后端额外配置文件:`/opt/yoyuzh/application-prod.yml`
|
||||
- API 域名:`https://api.yoyuzh.xyz`
|
||||
- 主站域名:`https://yoyuzh.xyz`
|
||||
|
||||
## 遇到线上登录/网络异常时先看什么
|
||||
|
||||
1. 前端当前生产包是否是最新资源
|
||||
2. `api.yoyuzh.xyz` 的 DNS / TLS / 反向代理是否正常
|
||||
3. `my-site-api.service` 是否正常运行
|
||||
4. 服务端和 Nginx 日志里是否已有真实请求
|
||||
|
||||
不要在没有确认链路问题前先改前端业务逻辑。
|
||||
@@ -410,5 +410,12 @@
|
||||
1. `memory.md`
|
||||
2. `docs/architecture.md`
|
||||
3. `docs/api-reference.md`
|
||||
4. `backend/src/main/java/com/yoyuzh/config/SecurityConfig.java`
|
||||
5. 对应业务模块的 `Controller + Service`
|
||||
4. `AGENTS.md`
|
||||
5. `CLAUDE.md`
|
||||
6. `backend/src/main/java/com/yoyuzh/config/SecurityConfig.java`
|
||||
7. 对应业务模块的 `Controller + Service`
|
||||
|
||||
补充说明:
|
||||
|
||||
- 根目录 `.env` 现在是本地密钥和部署参数的统一入口
|
||||
- 额外的交接背景可查看 `docs/agents/handoff.md`
|
||||
|
||||
@@ -87,6 +87,7 @@
|
||||
### 2.3 文档与脚本
|
||||
|
||||
- `docs/`: 实现计划与补充文档
|
||||
- `docs/agents/`: 补充性的 agent / handoff 文档;根目录 `CLAUDE.md` 与 `AGENTS.md` 仍是入口
|
||||
- `scripts/`: 前端静态站发布、对象存储迁移和本地辅助脚本
|
||||
|
||||
## 3. 模块划分
|
||||
@@ -402,6 +403,7 @@ Android 壳补充说明:
|
||||
- 仓库根目录没有 `package.json`,不要在根目录执行 `npm`
|
||||
- 前端命令只从 `front/package.json` 读取
|
||||
- 后端命令只从 `backend/pom.xml` 读取
|
||||
- 根目录 `.env` 是当前统一的本地密钥与部署配置入口;`.env.example` 是模板,旧 `.env.oss.local` 仅保留兼容回退
|
||||
- 前端 `npm run lint` 实际是 `tsc --noEmit`
|
||||
- 后端没有单独 lint 命令
|
||||
- 本仓库大量使用 Lombok,VS Code 若出现“final 字段未初始化”之类误报,优先检查 Lombok 扩展、Java Language Server 和 annotation processor
|
||||
@@ -414,9 +416,14 @@ Android 壳补充说明:
|
||||
2. `docs/architecture.md`
|
||||
3. `docs/api-reference.md`
|
||||
4. `AGENTS.md`
|
||||
5. `CLAUDE.md`
|
||||
|
||||
如果要继续某个具体功能,再进入对应模块的:
|
||||
|
||||
- 前端页面文件
|
||||
- 后端 Controller / Service
|
||||
- 紧邻测试文件
|
||||
|
||||
如果需要额外的交接背景,再补读:
|
||||
|
||||
- `docs/agents/handoff.md`
|
||||
|
||||
@@ -33,7 +33,7 @@ Important:
|
||||
- `npm run lint` is the current TypeScript check because it runs `tsc --noEmit`.
|
||||
- There is no separate ESLint script.
|
||||
- There is no separate `typecheck` script beyond `npm run lint`.
|
||||
- OSS publishing uses `scripts/deploy-front-oss.mjs`, which reads credentials from environment variables or `.env.oss.local`.
|
||||
- OSS publishing uses `scripts/deploy-front-oss.mjs`, which reads credentials from environment variables or the repository root `.env` file, with `.env.oss.local` kept only as a legacy fallback.
|
||||
|
||||
## Frontend rules
|
||||
|
||||
|
||||
10
memory.md
10
memory.md
@@ -37,7 +37,10 @@
|
||||
- 2026-04-03 Android 更新链路已改为“APK 存在文件桶独立路径 `android/releases/`,后端 `/api/app/android/latest` 读取 `android/releases/latest.json` 返回带版本号的后端下载地址,`/api/app/android/download` 直接分发 APK 字节流”;这样 App 内检查更新和 Web 下载都不会再误用前端静态桶旧包,也不依赖对象存储预签名下载
|
||||
- 2026-04-03 网盘已新增回收站:`DELETE /api/files/{id}` 现在会把文件或整个目录树软删除进回收站,默认保留 10 天;前端桌面网盘页在左侧目录栏最下方新增“回收站”入口,移动端网盘页头也可进入回收站查看并恢复
|
||||
- 2026-04-05 Git 远程已从 GitHub 迁到自建私有 Gitea:`https://git.yoyuzh.xyz/yoyuz/my_site.git`;当前本地 `main` 已推到新的 `origin/main`
|
||||
- 2026-04-05 因为仓库现在是私人仓库,`.gitignore` 已放开 `账号密码.txt`、`开发测试账号.md`、`.env.local`、`.env.*.local`、`.env.oss.local`、`front/.env.production` 等私有配置文件,后续可以直接纳入版本控制
|
||||
- 2026-04-06 已把本地项目密钥和部署元信息统一收口到仓库根目录 `.env`,模板文件改为 `.env.example`;前端 / Android 发布脚本现在优先读取 `.env`,旧 `.env.oss.local` 只作为兼容回退,不再作为主入口
|
||||
- 2026-04-06 已删除根目录 `账号密码.txt`,服务器 SSH 登录信息改为放在根目录 `.env`
|
||||
- 2026-04-06 已把补充型 handoff 文档收口到 `docs/agents/handoff.md`;`CLAUDE.md` 继续保留在根目录作为 agent 入口,额外的 `NEXT_CODEX_HANDOFF.md` 与目录说明文档已删除
|
||||
- 2026-04-06 已确认前端当前只是在源码层使用 `front/src/components/ui/*` 组件,不依赖根目录 `shadcn` CLI;因此已删除根目录 `package.json`、`package-lock.json`、`components.json` 和根目录 `node_modules`
|
||||
- 根目录 README 已重写为中文公开版 GitHub 风格
|
||||
- VS Code 工作区已补 `.vscode/settings.json`、`.vscode/extensions.json`、`lombok.config`,并在 `backend/pom.xml` 显式声明了 Lombok annotation processor
|
||||
- 进行中:
|
||||
@@ -75,6 +78,7 @@
|
||||
- [ ] 前端构建仍有 chunk size warning,目前不阻塞发布,但后续可以考虑做更细的拆包
|
||||
- [ ] 线上前端 bundle 当前仍内嵌 `https://api.yoyuzh.xyz/api`,API 子域名异常时会直接表现为“网络异常/登录失败”
|
||||
- [ ] 当前 Android 工程里的 Google Maven 镜像改动有一部分落在生成/依赖文件中;如果后续升级 Capacitor 或重新 `npm install`,需要重新确认 `front/android/build.gradle`、`front/android/capacitor-cordova-android-plugins/build.gradle`、`front/node_modules/@capacitor/android/capacitor/build.gradle` 的仓库源仍指向可访问镜像
|
||||
- [ ] 根目录目前仍有 `开发测试账号.md`、`需求文档.md`、`模板/` 等非运行时资料,后续如需继续瘦身可再决定是否迁入 `docs/` 或单独资料目录
|
||||
|
||||
## 关键约束
|
||||
(只写这个任务特有的限制,区别于项目通用规则)
|
||||
@@ -82,6 +86,7 @@
|
||||
- 前端真实命令以 `front/package.json` 为准;`npm run lint` 实际是 `tsc --noEmit`
|
||||
- 后端真实命令以 `backend/pom.xml` / `backend/README.md` 为准;常用的是 `mvn test` 和 `mvn package`
|
||||
- 修改文件时默认用 `apply_patch`
|
||||
- 根目录 `.env` 现在是本地密钥、部署参数和服务器 SSH 元信息的统一入口;`.env.example` 是模板,`.env.oss.local` 不再作为主入口
|
||||
- 已知线上后端服务名是 `my-site-api.service`
|
||||
- 已知线上后端运行包路径是 `/opt/yoyuzh/yoyuzh-portal-backend.jar`
|
||||
- 已知新服务器公网 IP 是 `1.14.49.201`
|
||||
@@ -110,13 +115,14 @@
|
||||
- Android 调试 APK 当前输出路径:`front/android/app/build/outputs/apk/debug/app-debug.apk`
|
||||
- Android APK 独立发包命令:
|
||||
- `node scripts/deploy-android-release.mjs`
|
||||
- 服务器登录信息保存在本地 `账号密码.txt`,不要把内容写进文档或对外输出
|
||||
- 服务器登录信息保存在根目录 `.env`,不要把内容写进文档或对外输出
|
||||
|
||||
## 参考资料
|
||||
(相关链接、文档片段、背景资料)
|
||||
- 根目录说明: `README.md`
|
||||
- 后端说明: `backend/README.md`
|
||||
- 仓库协作规范: `AGENTS.md`
|
||||
- agent / handoff 补充文档: `docs/agents/handoff.md`
|
||||
- 前端/后端工作区配置: `.vscode/settings.json`、`.vscode/extensions.json`
|
||||
- Lombok 配置: `lombok.config`
|
||||
- 最近关键实现位置:
|
||||
|
||||
4603
package-lock.json
generated
4603
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -1,5 +0,0 @@
|
||||
{
|
||||
"devDependencies": {
|
||||
"shadcn": "^4.1.0"
|
||||
}
|
||||
}
|
||||
@@ -9,13 +9,12 @@ import {
|
||||
createAwsV4Headers,
|
||||
encodeObjectKey,
|
||||
getCacheControl,
|
||||
loadRepoEnv,
|
||||
normalizeEndpoint,
|
||||
parseSimpleEnv,
|
||||
requestDogeCloudTemporaryS3Session,
|
||||
} from './oss-deploy-lib.mjs';
|
||||
|
||||
const repoRoot = process.cwd();
|
||||
const envFilePath = path.join(repoRoot, '.env.oss.local');
|
||||
const apkSourcePath = path.join(repoRoot, 'front', 'android', 'app', 'build', 'outputs', 'apk', 'debug', 'app-debug.apk');
|
||||
|
||||
function parseArgs(argv) {
|
||||
@@ -24,24 +23,6 @@ function parseArgs(argv) {
|
||||
};
|
||||
}
|
||||
|
||||
async function loadEnvFileIfPresent() {
|
||||
try {
|
||||
const raw = await fs.readFile(envFilePath, 'utf-8');
|
||||
const values = parseSimpleEnv(raw);
|
||||
for (const [key, value] of Object.entries(values)) {
|
||||
if (!process.env[key]) {
|
||||
process.env[key] = value;
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
if (error && typeof error === 'object' && 'code' in error && error.code === 'ENOENT') {
|
||||
return;
|
||||
}
|
||||
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
function requireEnv(name) {
|
||||
const value = process.env[name];
|
||||
if (!value) {
|
||||
@@ -133,7 +114,7 @@ async function uploadFile({
|
||||
|
||||
async function main() {
|
||||
const {dryRun} = parseArgs(process.argv.slice(2));
|
||||
await loadEnvFileIfPresent();
|
||||
await loadRepoEnv({repoRoot});
|
||||
|
||||
const androidScope = getAndroidReleaseScope();
|
||||
if (!androidScope) {
|
||||
|
||||
@@ -13,16 +13,15 @@ import {
|
||||
getFrontendSpaAliasKeys,
|
||||
getCacheControl,
|
||||
getContentType,
|
||||
loadRepoEnv,
|
||||
listFiles,
|
||||
normalizeEndpoint,
|
||||
parseSimpleEnv,
|
||||
requestDogeCloudTemporaryS3Session,
|
||||
} from './oss-deploy-lib.mjs';
|
||||
|
||||
const repoRoot = process.cwd();
|
||||
const frontDir = path.join(repoRoot, 'front');
|
||||
const distDir = path.join(frontDir, 'dist');
|
||||
const envFilePath = path.join(repoRoot, '.env.oss.local');
|
||||
|
||||
function parseArgs(argv) {
|
||||
return {
|
||||
@@ -31,24 +30,6 @@ function parseArgs(argv) {
|
||||
};
|
||||
}
|
||||
|
||||
async function loadEnvFileIfPresent() {
|
||||
try {
|
||||
const raw = await fs.readFile(envFilePath, 'utf-8');
|
||||
const values = parseSimpleEnv(raw);
|
||||
for (const [key, value] of Object.entries(values)) {
|
||||
if (!process.env[key]) {
|
||||
process.env[key] = value;
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
if (error && typeof error === 'object' && 'code' in error && error.code === 'ENOENT') {
|
||||
return;
|
||||
}
|
||||
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
function requireEnv(name) {
|
||||
const value = process.env[name];
|
||||
if (!value) {
|
||||
@@ -156,7 +137,7 @@ async function uploadSpaAliases({
|
||||
async function main() {
|
||||
const {dryRun, skipBuild} = parseArgs(process.argv.slice(2));
|
||||
|
||||
await loadEnvFileIfPresent();
|
||||
await loadRepoEnv({repoRoot});
|
||||
|
||||
const apiAccessKey = requireEnv('YOYUZH_DOGECLOUD_API_ACCESS_KEY');
|
||||
const apiSecretKey = requireEnv('YOYUZH_DOGECLOUD_API_SECRET_KEY');
|
||||
|
||||
@@ -299,3 +299,28 @@ export function parseSimpleEnv(rawText) {
|
||||
|
||||
return parsed;
|
||||
}
|
||||
|
||||
export async function loadRepoEnv({
|
||||
repoRoot,
|
||||
candidateFileNames = ['.env.local', '.env', '.env.oss.local'],
|
||||
}) {
|
||||
for (const fileName of candidateFileNames) {
|
||||
const filePath = path.join(repoRoot, fileName);
|
||||
|
||||
try {
|
||||
const raw = await fs.readFile(filePath, 'utf-8');
|
||||
const values = parseSimpleEnv(raw);
|
||||
for (const [key, value] of Object.entries(values)) {
|
||||
if (!process.env[key]) {
|
||||
process.env[key] = value;
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
if (error && typeof error === 'object' && 'code' in error && error.code === 'ENOENT') {
|
||||
continue;
|
||||
}
|
||||
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user