diff --git a/.kiro/specs/frontend-backend-separation/.config.kiro b/.kiro/specs/frontend-backend-separation/.config.kiro new file mode 100644 index 0000000..97ba296 --- /dev/null +++ b/.kiro/specs/frontend-backend-separation/.config.kiro @@ -0,0 +1 @@ +{"specId": "6761b341-a126-48c6-b6af-57b888694c48", "workflowType": "requirements-first", "specType": "feature"} \ No newline at end of file diff --git a/.kiro/specs/frontend-backend-separation/requirements.md b/.kiro/specs/frontend-backend-separation/requirements.md new file mode 100644 index 0000000..717a37b --- /dev/null +++ b/.kiro/specs/frontend-backend-separation/requirements.md @@ -0,0 +1,190 @@ +# 需求文档:前后端分离 — Java API 后端与 PostgreSQL 数据库 + +## 简介 + +本项目旨在将现有的 Next.js 前端生产管理子系统进行前后端分离改造。当前前端所有页面(设备列表、板卡管理、校准管理、固件库、授权管理、配置文件管理、维修工单、报废管理、设备登记、设备型号管理)均使用硬编码的模拟数据。需要搭建 Java Spring Boot 3.3.6 后端 API 服务和 PostgreSQL 数据库,用真实的 RESTful API 接口和持久化数据替换前端模拟数据。 + +## 术语表 + +- **API_Server**:基于 Spring Boot 3.3.6 的 Java 后端 API 服务,项目路径 `apps/geo-bps-api/` +- **Database**:PostgreSQL 12.14 数据库实例,按模块使用不同 schema 隔离 +- **Frontend**:现有 Next.js 前端应用,位于 `src/app/` 目录 +- **Device_Module**:设备管理业务模块,包名 `com.geomative.bps.device`,数据库 schema `dev` +- **Common_Module**:公共模块,包名 `com.geomative.bps.common`,提供统一响应体、全局异常处理、工具类 +- **API_Admin**:后台管理入口模块,提供需登录鉴权的 API 端点 +- **DDD**:领域驱动设计分层架构(interfaces / application / domain / infrastructure) +- **DO**:数据库映射对象(Data Object) +- **VO**:视图对象(View Object),用于 API 响应 +- **Query**:查询参数对象 +- **Command**:命令对象,用于创建/更新操作 + +## 需求 + +### 需求 1:后端项目骨架搭建 + +**用户故事:** 作为开发者,我希望搭建一个符合技术规范的 Java Spring Boot 多模块 Maven 项目骨架,以便后续各业务模块可以在此基础上开发。 + +#### 验收标准 + +1. THE API_Server SHALL 采用多模块 Maven 项目结构,父 POM 统一管理 Spring Boot 3.3.6、MyBatis-Plus、Lombok 等依赖版本 +2. THE API_Server SHALL 包含以下子模块:api-admin、api-portal、business(含 device 子模块)、common +3. THE Common_Module SHALL 提供统一 JSON 响应格式,包含 code(整数)、message(字符串)、data(泛型)三个字段 +4. THE Common_Module SHALL 提供全局异常处理器,捕获业务异常和参数校验异常并返回统一格式的错误响应 +5. THE Common_Module SHALL 提供 MyBatis-Plus 的 MetaObjectHandler 实现,自动填充 created_at 和 updated_at 审计字段 +6. THE API_Admin SHALL 配置 CORS 策略,允许前端开发服务器(localhost:3000)的跨域请求 +7. THE API_Server SHALL 在 application.yml 中配置 PostgreSQL 数据源连接和 MyBatis-Plus 逻辑删除策略 + +### 需求 2:数据库 Schema 与表结构设计 + +**用户故事:** 作为开发者,我希望设计并创建 PostgreSQL 数据库表结构,以便持久化存储各业务模块的数据。 + +#### 验收标准 + +1. THE Database SHALL 在 `dev` schema 下创建设备管理相关的数据表 +2. THE Database SHALL 包含 `dev.devices` 表,存储设备信息(SN号、型号、状态、固件版本、生产日期、客户名称、批次号) +3. THE Database SHALL 包含 `dev.device_models` 表,存储设备型号信息(型号名称、型号代码、状态、描述) +4. THE Database SHALL 包含 `dev.board_types` 表,存储板卡型号信息(板卡类型、型号、固件版本、生产日期、状态) +5. THE Database SHALL 包含 `dev.firmware_versions` 表,存储固件版本信息(版本号、板卡型号、固件类型、发布日期、状态、文件大小、下载次数、硬件版本范围、升级类型、是否签名、MD5、SHA256、发布说明) +6. THE Database SHALL 包含 `dev.calibration_records` 表,存储校准记录(采集板SN号、板卡型号、校准日期、到期日期、校准人员、状态、通道数、综合偏差) +7. THE Database SHALL 包含 `dev.config_files` 表,存储配置文件信息(配置名称、适配型号、版本、状态、发射参数、采集参数、网络参数) +8. THE Database SHALL 包含 `dev.licenses` 表,存储授权信息(设备型号、授权模块列表、到期时间、状态) +9. THE Database SHALL 包含 `dev.repair_orders` 表,存储维修工单信息(工单号、设备SN、故障类型、状态、优先级、负责人、描述) +10. THE Database SHALL 包含 `dev.scrap_records` 表,存储报废记录(设备SN、型号、报废原因、申请人、状态、来源工单号、残值评估、可回收物料) +11. THE Database SHALL 包含 `dev.checklist_templates` 表和 `dev.checklist_items` 表,存储装配 Checklist 模板及其检查项 +12. WHEN 创建任何业务表时,THE Database SHALL 包含 id(VARCHAR(64) 主键)、created_at、created_by、updated_at、updated_by、deleted 审计字段 + +### 需求 3:设备管理 API + +**用户故事:** 作为前端开发者,我希望通过 API 获取和管理设备数据,以便替换设备列表页面的模拟数据。 + +#### 验收标准 + +1. WHEN 前端请求 GET `/api/admin/devices` 时,THE API_Server SHALL 返回分页的设备列表,支持按型号、状态、生产日期、SN号、批次号筛选 +2. WHEN 前端请求 GET `/api/admin/devices/{sn}` 时,THE API_Server SHALL 返回指定设备的详细信息,包含关联的授权信息、子设备列表、固件信息 +3. WHEN 前端请求 POST `/api/admin/devices` 时,THE API_Server SHALL 创建新设备记录(设备登记),包含装机信息和 BOM 清单 +4. WHEN 前端请求 GET `/api/admin/devices/batches` 时,THE API_Server SHALL 返回所有生产批次列表及每个批次的设备数量 +5. IF 请求参数中的 SN 号已存在,THEN THE API_Server SHALL 返回 409 冲突错误码和描述性错误消息 + +### 需求 4:设备型号管理 API + +**用户故事:** 作为前端开发者,我希望通过 API 管理设备型号和装配 Checklist 模板,以便替换型号管理页面的模拟数据。 + +#### 验收标准 + +1. WHEN 前端请求 GET `/api/admin/device-models` 时,THE API_Server SHALL 返回所有设备型号列表 +2. WHEN 前端请求 POST `/api/admin/device-models` 时,THE API_Server SHALL 创建新设备型号记录 +3. WHEN 前端请求 GET `/api/admin/checklist-templates?modelCode={code}` 时,THE API_Server SHALL 返回指定型号的装配 Checklist 模板及其检查项列表 +4. WHEN 前端请求 POST `/api/admin/checklist-templates` 时,THE API_Server SHALL 创建新的 Checklist 模板,包含检查项列表 +5. IF 请求的型号代码已存在,THEN THE API_Server SHALL 返回 409 冲突错误码 + +### 需求 5:板卡型号管理 API + +**用户故事:** 作为前端开发者,我希望通过 API 管理板卡型号数据,以便替换板卡管理页面的模拟数据。 + +#### 验收标准 + +1. WHEN 前端请求 GET `/api/admin/board-types` 时,THE API_Server SHALL 返回板卡型号列表,支持按板卡类型(主协板、采集板、发射板、升压板)筛选 +2. WHEN 前端请求 GET `/api/admin/board-types/{id}` 时,THE API_Server SHALL 返回板卡详情,包含升级历史、校准历史、保养历史、维修历史 +3. WHEN 前端请求 POST `/api/admin/board-types` 时,THE API_Server SHALL 创建新板卡型号记录 + +### 需求 6:固件库管理 API + +**用户故事:** 作为前端开发者,我希望通过 API 管理固件版本数据,以便替换固件库页面的模拟数据。 + +#### 验收标准 + +1. WHEN 前端请求 GET `/api/admin/firmware` 时,THE API_Server SHALL 返回固件版本列表,支持按固件类型和板卡型号筛选 +2. WHEN 前端请求 POST `/api/admin/firmware` 时,THE API_Server SHALL 创建新固件版本记录,包含版本号、硬件版本范围、升级类型、固件类型、签名状态、发布说明 +3. WHEN 前端请求 GET `/api/admin/firmware/{id}/download` 时,THE API_Server SHALL 返回固件文件的下载流,并将该固件的下载次数加 1 +4. IF 上传的固件版本号与同一板卡型号的已有版本重复,THEN THE API_Server SHALL 返回 409 冲突错误码 + +### 需求 7:校准管理 API + +**用户故事:** 作为前端开发者,我希望通过 API 管理采集板校准数据,以便替换校准管理页面的模拟数据。 + +#### 验收标准 + +1. WHEN 前端请求 GET `/api/admin/calibrations` 时,THE API_Server SHALL 返回分页的校准记录列表,支持按采集板SN号、校准状态、校准人员筛选 +2. WHEN 前端请求 GET `/api/admin/calibrations/{id}` 时,THE API_Server SHALL 返回校准详情,包含各通道的校准结果(参考值、测量值、偏差、结果) +3. WHEN 前端请求 POST `/api/admin/calibrations/import` 时,THE API_Server SHALL 支持批量导入校准记录数据 + +### 需求 8:配置文件管理 API + +**用户故事:** 作为前端开发者,我希望通过 API 管理设备配置文件,以便替换配置文件管理页面的模拟数据。 + +#### 验收标准 + +1. WHEN 前端请求 GET `/api/admin/config-files` 时,THE API_Server SHALL 返回分页的配置文件列表,支持按适配型号、版本、关键字筛选 +2. WHEN 前端请求 GET `/api/admin/config-files/{id}` 时,THE API_Server SHALL 返回配置文件详情,包含发射参数、采集参数、网络参数 +3. WHEN 前端请求 POST `/api/admin/config-files` 时,THE API_Server SHALL 创建新配置文件记录 +4. WHEN 前端请求 PUT `/api/admin/config-files/{id}` 时,THE API_Server SHALL 更新指定配置文件记录 +5. WHEN 前端请求 DELETE `/api/admin/config-files/{id}` 时,THE API_Server SHALL 逻辑删除指定配置文件(设置 deleted=1) + +### 需求 9:授权管理 API + +**用户故事:** 作为前端开发者,我希望通过 API 管理设备授权数据,以便替换授权管理页面的模拟数据。 + +#### 验收标准 + +1. WHEN 前端请求 GET `/api/admin/licenses` 时,THE API_Server SHALL 返回分页的授权列表,支持按设备型号和状态筛选 +2. WHEN 前端请求 POST `/api/admin/licenses` 时,THE API_Server SHALL 创建新授权记录,包含设备型号、授权模块列表、授权期限 +3. WHEN 前端请求 PUT `/api/admin/licenses/{id}` 时,THE API_Server SHALL 更新指定授权记录 +4. WHEN 前端请求 PUT `/api/admin/licenses/{id}/disable` 时,THE API_Server SHALL 将指定授权记录状态设置为已停用 + +### 需求 10:维修工单管理 API + +**用户故事:** 作为前端开发者,我希望通过 API 管理维修工单数据,以便替换维修工单页面的模拟数据。 + +#### 验收标准 + +1. WHEN 前端请求 GET `/api/admin/repair-orders` 时,THE API_Server SHALL 返回分页的维修工单列表,支持按状态、优先级、负责人、日期范围、设备SN筛选 +2. WHEN 前端请求 GET `/api/admin/repair-orders/{id}` 时,THE API_Server SHALL 返回工单详情,包含设备信息、故障信息、处理记录时间线、板卡更换记录 +3. WHEN 前端请求 POST `/api/admin/repair-orders` 时,THE API_Server SHALL 创建新维修工单 +4. WHEN 前端请求 PUT `/api/admin/repair-orders/{id}/process` 时,THE API_Server SHALL 更新工单处理信息(处理操作、板卡更换、授权处理、处理备注) +5. WHEN 前端请求 PUT `/api/admin/repair-orders/{id}/close` 时,THE API_Server SHALL 关闭工单并将状态设置为已处理 + +### 需求 11:报废管理 API + +**用户故事:** 作为前端开发者,我希望通过 API 管理报废审批和物料回收数据,以便替换报废管理页面的模拟数据。 + +#### 验收标准 + +1. WHEN 前端请求 GET `/api/admin/scrap-records` 时,THE API_Server SHALL 返回分页的报废记录列表,支持按设备SN、状态、日期筛选 +2. WHEN 前端请求 GET `/api/admin/scrap-records/{id}` 时,THE API_Server SHALL 返回报废详情,包含设备信息、审批信息、可回收物料列表、审批记录时间线 +3. WHEN 前端请求 PUT `/api/admin/scrap-records/{id}/approve` 时,THE API_Server SHALL 审批通过报废申请,更新状态为已审批 +4. WHEN 前端请求 PUT `/api/admin/scrap-records/{id}/reject` 时,THE API_Server SHALL 驳回报废申请,更新状态为已驳回,记录驳回意见 +5. WHEN 前端请求 PUT `/api/admin/scrap-records/{id}/recover` 时,THE API_Server SHALL 完成物料回收入库,更新状态为已回收,记录回收的物料清单 +6. THE API_Server SHALL 提供 GET `/api/admin/scrap-records/stats` 接口,返回报废统计数据(报废总数、待审批数、已审批待回收数、已回收数) + +### 需求 12:首页 Dashboard 统计 API + +**用户故事:** 作为前端开发者,我希望通过 API 获取首页仪表盘的统计数据,以便替换首页的模拟数据。 + +#### 验收标准 + +1. WHEN 前端请求 GET `/api/admin/dashboard/metrics` 时,THE API_Server SHALL 返回设备总数、装配中数量、已激活数量、维修中数量、报废数量、授权即将到期数量等统计指标 +2. WHEN 前端请求 GET `/api/admin/dashboard/device-status` 时,THE API_Server SHALL 返回设备状态分布数据(已装配、已出厂、已激活、报废各状态的数量) +3. WHEN 前端请求 GET `/api/admin/dashboard/tasks` 时,THE API_Server SHALL 返回待处理任务列表,包含校准即将到期、维修工单、固件升级通知、授权即将到期四个分组 + +### 需求 13:前端 API 集成层 + +**用户故事:** 作为前端开发者,我希望在前端建立统一的 API 调用层,以便各页面组件可以方便地调用后端接口替换模拟数据。 + +#### 验收标准 + +1. THE Frontend SHALL 创建统一的 API 客户端模块,配置后端 API 基础 URL、请求超时时间(5秒)、统一错误处理 +2. THE Frontend SHALL 为每个业务模块创建独立的 API 服务文件(如 deviceApi.ts、boardApi.ts、firmwareApi.ts 等) +3. WHEN API 请求失败时,THE Frontend SHALL 在页面上展示友好的错误提示信息 +4. WHEN API 请求正在进行时,THE Frontend SHALL 展示加载状态指示器 +5. THE Frontend SHALL 将各页面组件中的硬编码模拟数据替换为 API 调用,使用 React 的 useState 和 useEffect 管理数据获取状态 + +### 需求 14:分页与筛选标准化 + +**用户故事:** 作为前端开发者,我希望前后端采用统一的分页和筛选参数规范,以便各列表页面的数据交互保持一致。 + +#### 验收标准 + +1. THE API_Server SHALL 对所有列表接口采用统一的分页参数格式:page(页码,从1开始)、pageSize(每页条数,默认10) +2. THE API_Server SHALL 对所有列表接口返回统一的分页响应格式,包含 total(总记录数)、page(当前页码)、pageSize(每页条数)、records(数据列表) +3. THE API_Server SHALL 对所有筛选参数进行服务端校验,无效参数返回 400 错误码和描述性错误消息 +4. WHEN 筛选条件为空或为"全部"时,THE API_Server SHALL 返回不带该条件过滤的完整数据集 diff --git a/.kiro/steering/java-api.md b/.kiro/steering/java-api.md new file mode 100644 index 0000000..6c77ab8 --- /dev/null +++ b/.kiro/steering/java-api.md @@ -0,0 +1,127 @@ +# Java API 技术规范 + +## 运行环境 +- JDK 17 + +## 框架选型 +- Spring Boot 3.3.6 (spring-boot-starter-parent) +- ORM:MyBatis-Plus +- Lombok + +## 架构约束 +- API 采用多模块 Maven 项目结构,父项目统一管理依赖版本 +- 项目名: geo-bps +- 包名前缀:com.geomative.bps.* +- 子模块划分: + - `api-admin` 后台管理入口模块:需登录鉴权,引入 `website`、`device`、`library`、`permission` 等模块 + - `api-portal` 前端门户入口模块:无需登录,仅引入对外开放的业务模块 + - `device` 设备管理模块 + - `website` 网站管理后台 + - `library` 资料库模块 + - `permission` 权限管理模块 + - `common` 公共模块:工具类、基础配置、统一响应格式、全局异常处理等共享代码 + +- 项目路径:`apps/geo-bps-api/` +- groupId:`com.geomative.bsp` +- artifactId:`geo-bps-api` +- 项目整体结构: +``` +apps/geo-bps-api/ +├── pom.xml # 父 POM,统一依赖版本管理 +├── api-admin/ # 后台管理入口,Spring Security 鉴权配置 +├── api-portal/ # 前端门户入口,公开接口无需授权 +├── business/ # 业务模块聚合器(pom packaging) +│ ├── pom.xml +│ ├── permission/ # 权限管理模块 +│ ├── website/ # 网站业务模块(被两个入口共享) +│ ├── device/ # 设备管理模块 +│ └── library/ # 资料库模块 +└── common/ # 公共工具、基础配置、统一响应体 +``` + +## 编码规范 + +### 命名规范 +- 类名使用 UpperCamelCase,如 `DeviceService`、`UserDO` +- 方法名、变量名使用 lowerCamelCase,如 `getUserById`、`deviceList` +- 常量全部大写,单词间用下划线,如 `MAX_RETRY_COUNT` +- 包名全部小写,如 `com.example.device.domain` +- 抽象类命名以 `Abstract` 开头;异常类命名以 `Exception` 结尾;测试类命名以被测类名开头、`Test` 结尾 +- POJO 类中布尔类型变量不加 `is` 前缀,避免序列化问题 +- 领域对象命名后缀约定: + - 数据库映射对象:`XxxDO` + - 数据传输对象:`XxxDTO` + - 视图对象:`XxxVO` + - 查询对象:`XxxQuery` + - 命令对象:`XxxCommand` + +### 注释规范 +- 所有 public 类、方法必须有 Javadoc 注释 +- 方法注释需说明功能、参数含义、返回值、可能抛出的异常 +- 代码逻辑复杂处需有行内注释说明意图,而非描述代码本身 +- 禁止保留无意义的注释和注释掉的废弃代码 + +### 异常处理 +- 不允许捕获 `Exception` 等大类异常后不做任何处理(空 catch) +- 业务异常统一使用自定义异常类,继承 `RuntimeException` +- 不允许用异常控制正常业务流程 +- finally 块中不允许使用 return + +### 日志规范 +- 使用 SLF4J + Logback,禁止直接使用 `System.out.println` +- 日志变量声明:`private static final Logger log = LoggerFactory.getLogger(XxxClass.class);` +- 日志输出使用占位符,禁止字符串拼接:`log.info("userId: {}", userId)` +- 异常日志必须输出完整堆栈:`log.error("message", e)` + +### 集合与并发 +- 初始化集合时指定初始容量,如 `new ArrayList<>(16)` +- 禁止在 foreach 循环中对集合进行 add/remove 操作 +- 线程池不允许使用 `Executors` 创建,需通过 `ThreadPoolExecutor` 显式配置参数 + +### 其他 +- 所有方法入参需做非空校验,使用 `Objects.requireNonNull` 或断言 +- 魔法值(Magic Number)禁止直接出现在代码中,需定义为常量 +- 返回值为集合类型时,不允许返回 null,应返回空集合 + +### DDD 分层架构 +- 采用领域驱动设计(DDD)分层架构,每个子模块内部结构如下: + +``` +{module}/ +├── interfaces/ # 接口层:Controller、DTO、Assembler +├── application/ # 应用层:ApplicationService、Command、Query +├── domain/ # 领域层:Entity、ValueObject、DomainService、Repository接口、DomainEvent +└── infrastructure/ # 基础设施层:Repository实现、Mapper、持久化对象(PO)、外部服务适配 +``` + +## 数据库 +- PostgreSQL 12.14 (Debian 12.14-1.pgdg110+1) + +### 审计字段规范 +- 所有业务表必须包含以下审计字段: + - `created_at` TIMESTAMP NOT NULL — 创建时间,INSERT 时自动填充 + - `created_by` VARCHAR(64) NULL — 创建人(用户ID或用户名),字符类型 + - `updated_at` TIMESTAMP NOT NULL — 最后修改时间,INSERT 和 UPDATE 时自动填充 + - `updated_by` VARCHAR(64) NULL — 最后修改人(用户ID或用户名),字符类型 + - `deleted` TINYINT NOT NULL DEFAULT 0 — 删除状态,0=未删除,1=已删除 + +### 主键规范 +- 所有业务表主键类型为 VARCHAR(64),由应用层生成(如雪花算法、UUID 字符串等),不使用数据库自增或 UUID 类型 + +### PostgreSQL Schema 分模块 +- 不同子模块的表使用不同的 PostgreSQL schema 进行隔离: + - `perm` — permission 模块(admin_users、revoked_tokens、admin_menus、admin_roles 等) + - `web` — website 模块(nav_menus、branches、sub_branches、pages、page_contents、page_seo、fixed_page_contents、enabled_locales 等) + - `dev` — device 模块(quotations、access_logs、configurator_steps 等) + - `lib` — library 模块(knowledge_articles 等) + - `common` — 公共表(contact_submissions、system_config 等) +- MyBatis-Plus 通过 `@TableName(schema = "xxx")` 或全局配置指定 schema +- MyBatis-Plus 配置: + - 通过 `MetaObjectHandler` 自动填充 `created_at`、`updated_at` + - 通过 `@TableLogic` 注解标记 `deleted` 字段实现逻辑删除 + - 查询默认过滤 `deleted=1` 的记录 + +## 部署 +- 集成 Nginx 作为前置代理 + - `api-admin`:Nginx 直接流量穿透,转发至单实例后台管理服务 + - `api-portal`:Nginx 4层负载均衡(TCP/stream模块),支持多实例横向扩展 diff --git a/.next/dev/logs/next-development.log b/.next/dev/logs/next-development.log index a3146f8..a1364c5 100644 --- a/.next/dev/logs/next-development.log +++ b/.next/dev/logs/next-development.log @@ -19,3 +19,215 @@ {"timestamp":"117:32:42.259","source":"Browser","level":"ERROR","message":"\u001b[31mUncaught Error: The default export is not a React Component in \"/devices/page\"\u001b[39m"} {"timestamp":"117:33:29.348","source":"Server","level":"LOG","message":"✓ Compiled in 274ms"} {"timestamp":"117:33:30.697","source":"Browser","level":"INFO","message":"%cDownload the React DevTools for a better development experience: https://react.dev/link/react-devtools font-weight:bold"} +{"timestamp":"118:56:04.251","source":"Browser","level":"INFO","message":"%cDownload the React DevTools for a better development experience: https://react.dev/link/react-devtools font-weight:bold"} +{"timestamp":"118:56:06.098","source":"Browser","level":"INFO","message":"%cDownload the React DevTools for a better development experience: https://react.dev/link/react-devtools font-weight:bold"} +{"timestamp":"118:56:21.517","source":"Browser","level":"INFO","message":"%cDownload the React DevTools for a better development experience: https://react.dev/link/react-devtools font-weight:bold"} +{"timestamp":"119:13:03.183","source":"Browser","level":"INFO","message":"%cDownload the React DevTools for a better development experience: https://react.dev/link/react-devtools font-weight:bold"} +{"timestamp":"119:13:04.798","source":"Browser","level":"INFO","message":"%cDownload the React DevTools for a better development experience: https://react.dev/link/react-devtools font-weight:bold"} +{"timestamp":"119:14:07.937","source":"Browser","level":"INFO","message":"%cDownload the React DevTools for a better development experience: https://react.dev/link/react-devtools font-weight:bold"} +{"timestamp":"119:18:22.932","source":"Server","level":"LOG","message":"✓ Compiled in 65ms"} +{"timestamp":"119:25:27.462","source":"Server","level":"LOG","message":"✓ Compiled in 29ms"} +{"timestamp":"119:28:26.107","source":"Server","level":"LOG","message":"✓ Compiled in 58ms"} +{"timestamp":"119:28:32.906","source":"Server","level":"LOG","message":"✓ Compiled in 30ms"} +{"timestamp":"119:29:36.058","source":"Server","level":"LOG","message":"✓ Compiled in 49ms"} +{"timestamp":"119:30:08.040","source":"Server","level":"LOG","message":"✓ Compiled in 48ms"} +{"timestamp":"119:36:42.082","source":"Server","level":"LOG","message":"✓ Compiled in 67ms"} +{"timestamp":"119:36:42.377","source":"Browser","level":"ERROR","message":"uncaughtError: ReferenceError: modelsData is not defined"} +{"timestamp":"119:36:42.484","source":"Server","level":"ERROR","message":"[browser] \"\\u001b[31mUncaught ReferenceError: modelsData is not defined\\u001b[39m\\n\\u001b[31m at ModelsPage (src/app/models/page.tsx:107:14)\\u001b[39m\\n \\u001b[90m105 |\\u001b[0m \\n \\u001b[90m106 |\\u001b[0m
\\n\\u001b[31m\\u001b[1m>\\u001b[0m \\u001b[90m107 |\\u001b[0m {modelsData.map(model => (\\n \\u001b[90m |\\u001b[0m \\u001b[31m\\u001b[1m^\\u001b[0m\\n \\u001b[90m108 |\\u001b[0m