# 个人头像与公司 Logo:前端对接 日期:2026-10-27。本文面向前端开发与联调人员;本批只改后端和契约,不表示已部署或前端已经接入。 ## 1. 展示规则 | 场景 | 数据来源 | 无图片时 | | --- | --- | --- | | 本人的个人资料/本人聊天气泡 | GET /auth/me 的 avatarUrl | 个人昵称首字 | | 聊天对方为求职者 | 会话列表/详情的 avatarUrl | contactName 首字 | | 聊天对方为企业 | 会话列表/详情的 avatarUrl,来源为公司 logoUrl | 公司名称首字 | | 企业主页、岗位关联公司卡片 | 企业资料的 logoUrl | 公司名称首字 | 个人头像属于用户,Logo 属于企业,两个资源独立。企业账号修改个人头像不改变公司 Logo;修改 Logo 不改变 HR 本人头像。不要根据 URL 是否为空自行把个人头像替换成企业 Logo,或反过来。 本人的头像以 /auth/me 为统一来源,本批不改变 GET /profile/me 的空资料返回 {} 约定。会话摘要实时查询用户/公司引用,不从历史消息中固化头像。TALENT_INVITATION 会话继续隐藏候选人个人头像,不因新上传接口而放开隐私。 ## 2. 上传、删除与读取接口 以下路径相对于 API 基址 /api/v1。所有写请求使用当前账号 access token,身份来自服务端,不接受客户端 userId/companyId 或文件路径。 | 方法 | 路径 | 权限/作用 | | --- | --- | --- | | POST | /auth/me/avatar | 已选择身份且有效的 STUDENT/COMPANY/ADMIN;上传自己的个人头像 | | DELETE | /auth/me/avatar | 同上;清空个人头像,重复删除成功 | | POST | /companies/me/logo | COMPANY 且已有自己的企业资料;上传企业 Logo | | DELETE | /companies/me/logo | 同上;清空企业 Logo,重复删除成功 | | GET | /profile-images/{imageId} | 公司 Logo 可匿名读;个人头像须鉴权且仅本人或具备当前 DIRECT 沟通授权的成员可读 | 企业不必先通过认证才能维护自己的 Logo,但上传 Logo 不改变企业认证状态,也不放开岗位发布门禁。 ### 上传请求 multipart/form-data,字段名 file。使用 FormData,不要手动设置 Content-Type(让运行时自动带 boundary),不要把本机 file:// URI 或预设素材 key 作为远程图片 URL 提交。 允许 JPEG/PNG(扩展名、声明 MIME 与真实解码格式必须匹配),原文件最多 2 MiB;单边最多 4096、总像素最多 400 万。SVG/GIF/WebP/HEIC 等本批不支持。相册素材不满足格式时应在客户端转换并裁剪,或给出明确提示。 后端去除原图元数据及附加内容,等比例缩小到最长边 512,透明背景转白色,统一保存 JPEG,最大 512 KiB。文件名和原图不保存。 成功返回 envelope,data 示例: { "url": "/api/v1/profile-images/00000000-0000-0000-0000-000000000000", "version": "00000000-0000-0000-0000-000000000000", "contentType": "image/jpeg", "size": 12345 } 示例 UUID 仅示意;每次上传生成新 UUID 和新 URL。个人上传同时更新 users.avatar_url;Logo 上传更新 companies.logo_url。替换/删除在数据库事务内完成,失败保留旧图与旧引用;不推进在线简历 revision。 删除成功 data 为 {"deleted":true}。重新取资料时没有头像/Logo 应使用占位图,不能继续展示旧本地缓存。 ### 图片读取 url 是包含 API context path 的同源相对路径,不是完整域名。用 API 服务 origin 解析,不要再次拼 /api/v1,也不要让已登录下载器向任意外部 URL 附带 Bearer。 个人头像 GET 必须带 Authorization: Bearer access-token;普通图片组件不会必然继承业务请求层的鉴权,要给同源 source 配置认证请求头,或通过受控下载层取字节。禁止把 Token 拼进 URL。 返回 image/jpeg,Cache-Control: no-store,X-Content-Type-Options: nosniff。这是图片字节,不是 JSON,不能直接使用只解 JSON envelope 的 request() 当作图片下载器。 旧 URL 在替换/删除后返回 404。第三方登录账号即使知道私有头像 URL,也不能读取;具备 DIRECT 成员关系还必须满足当前拉黑、撤回及企业接收投递等沟通权限。公司 Logo 是公开企业展示素材,不能用它上传私密资料。 ### 错误状态 - 400:文件缺失、空文件、格式/MIME/内容不一致、大小或像素超限。 - 401:缺少/无效/过期/禁用的登录凭证;匿名读个人头像。 - 403:身份不允许、非授权聊天成员、已失去沟通权限。 - 404:企业资料不存在、图片不存在/已替换/已删除、图片所属账号停用。 - 超出全局 multipart/网关大小上限可能更早被拒绝;前端仍应先限制 2 MiB。 不要向用户暴露文件系统路径、SQL、Token 或完整异常日志。 ## 3. 缓存与状态同步 1. 上传成功立即把返回的新 URL 更新到本人资料状态;更新会话页共享状态或使会话列表/详情缓存失效。 2. 个人资料页与聊天页复用图片头像组件。先尝试图片 URL,失败/缺失才回退姓名首字;不能把 URL 渲染到 Text。 3. 页面重新聚焦时拉取当前 /auth/me、会话列表/详情,避免长期使用路由传参或首次进入时的旧快照。 4. 对方设备不会因为本机 setState 自动更新。本批没有新增头像变更 WebSocket 事件;对方通过列表/详情刷新获取新 URL。若要求停留聊天页时即时更新,需要前端刷新策略或另立头像事件协议。 5. 旧图收到 404 时只做受控的元信息刷新,不能无限重试旧 URL。新 URL 成功后覆盖显示,失败时使用占位头像。 6. 切换账号时清理身份相关状态及私有图片缓存;上一账号迟到的响应不能覆盖新账号。 本机历史 file://、本地预设头像不自动迁移到后端。需要前端获得可上传的实际文件并调用上传接口;只在个人资料页选中素材不算服务器保存成功。 ## 4. 联调验收 - 求职者改头像后:个人资料、本人气泡、对方会话列表/详情使用同一新图。 - 企业改个人头像不改公司 Logo;改 Logo 后企业主页、岗位公司卡片和对方会话摘要使用新 Logo。 - 换设备/重新登录仍能从服务器读取;成功上传前不提示“已同步”。 - 连续替换、删除、并发上传均只保留当前版本;旧 URL 不再可读。 - 匿名/第三方账号不可读私有头像;合法 DIRECT 成员可读,拉黑后旧 URL 也不可读;邀约隐私保持。 - 测试空文件、假图片、MIME 伪装、超限、旧地址404与加载失败占位。 - 全流程不改变在线简历内容和 revision,不混用公司 Logo 和个人头像。 ## 5. 存储与验收边界 新增 V63 迁移,仅创建 profile_images 表,不重写旧迁移,不搬运历史外链。每个 owner/kind 最多一张当前图片,二进制和引用在同一数据库事务内更新;数据库备份需包含该表。账号注销完成时清除其上传图片,物理删除用户/企业时外键级联清理。 现有企业资料中的历史 logoUrl 外链保持兼容;后端不会下载/代理任意外部图片。历史资料接口另写 logoUrl 后,已不再引用的新上传地址不可读;推荐统一使用本批上传/删除接口维护图片。 本轮定向验证结果见同目录 profile-images-development-verification-20261027.md。全量 clean verify、双真实 MySQL、同次 JAR 黑盒与重启,以及前端真机验收须按各自实际结果登记,不能以此文档替代通过证据。